How to test python code on command line - python

While writing and testing a python method, I am currently using the following approach:
import foo as f
bar = f.bar()
bar.runMyMethodAndSeeIfItWorks()
If I change something in my method, and I need to retest it, I have to execute the following:
f = reload(foo)
bar = f.bar()
bar.runMyMethodAndSeeIfItWorks()
I was wondering if there is a simpler approach to this

Write a real unit test, and run it from the command line. I find this is one of the most compelling reasons for adopting unit testing: you're going to need to try out your methods as you write them anyway, you might as well do it in a form that will be runnable for evermore after that.

You must be referring to testing from a Python shell [x] where reload is used. In that case, reload is just fine - I wouldn't worry about it. You can also have:
import foomodule
And later:
reload(foomodule)
[x] Don't just use the vanilla shell (running python on the command line) - rather try something like IPython or Spyder.

You should look into Doctests. It is a dead simple way to learn testing.
Essentially, you write your tests in the interactive interpreter, then you can copy/paste them in the docstrings of your functions.
Example (from the Python documentation)
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
If the result is small enough to fit in an int, return an int.
Else return a long.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> [factorial(long(n)) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000L
>>> factorial(30L)
265252859812191058636308480000000L
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000L
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
<do stuff>
if __name__ == "__main__":
import doctest
doctest.testmod()
tldr;
You precede the line of code that you want to test with '>>>' and the expected result on the line below it. There is more to it than that but this should be enough to get you started.

Related

Can python throw a "stack overflow" error?

Can python have a stack overflow error?
Recently I was just letting my mind wander when I came across the question: "can python get the stack overflow error? Does anyone have any answers?
I searched for the answer but only found java answers. I have used java but its just not my question:
What is a StackOverflowError?
https://rollbar.com/blog/how-to-fix-java-lang-stackoverflowerror-in-java/
My Reasoning
I initially thought no because python just... works most of the time (like passing an int for a string). It also doesn't have stacks (to my knowledge). But I wasn't sure. Here I am.
Sure it can
the following code will cause a seg fault:
import sys
sys.setrecursionlimit(10_000_000)
def foo():
foo()
On Mac OS, this throws:
Segmentation fault: 11
Which is caused by a stack overflow.
You can, if your recursion limit is too high:
def foo():
return foo()
>>> foo()
Result:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
.......
File "<stdin>", line 2, in foo
RuntimeError: maximum recursion depth exceeded
>>>
The default recursion limit is 10**3 (verifiable via sys.getrecursionlimit), but you can change it using sys.setrecursionlimit:
import sys
sys.setrecursionlimit(10**8)
def foo():
foo()
but doing so could be dangerous -- the standard limit is a little conservative, but Python stackframes can be quite big.
By default, Python's recursion limit is 10**3, theoretically if you were to pass this then you would be given a RecursionError.
You can even reduce the recursion limit using setrecursionlimit() to make this happen more quickly.

python casted memoryview assignment error... why?

Due to this, I need to use python memoryview.cast('I') to access a FPGA avoiding double read/write strobe. No panic, you wont need an FPGA to answer the question below...
So here comes a python sample which fails ('testfile' can be any file here -just longer than 20 bytes-, but for me, eventually it will be a IO mapped FPGA HW):
#!/usr/bin/python
import struct
import mmap
with open('testfile', "r+b") as f:
mm=memoryview(mmap.mmap(f.fileno(), 20)).cast('I')
# now try to assign the 2 first U32 of the file new values 1 and 2
# mm[0]=1; mm[1]=2 would work, but the following fails:
mm[0:1]=memoryview(struct.pack('II',1,2)).cast('I') #assignement error
The error is:
./test.py
Traceback (most recent call last):
File "./test.py", line 8, in <module>
mm[0:1]=memoryview(struct.pack('II',1,2)).cast('I')
ValueError: memoryview assignment: lvalue and rvalue have different structures
I don't undestand the error... what "different structures" are we talking about??
How can I rewrite the right hand-side of the assignment expression so it works??
Changing the left-hand-side will fail for the FPGA... as it seems anything else generates wrong signal towards the hardware...
More generally, how should I rework my array of 32 bit integers to fit the left-hand-side of the assignment...?
Yes #Monica is right: The error was simpler than I though. The slice on the left hand side is wrong indeed.

Race condition in line of Python

I have an interesting problem. I am -- for shits and giggles -- trying to write a program really shortly. I have it down to 2 lines, but it has a race condition, and I can't figure out why. Here's the gist of it:
imports...
...[setattr(__main__, 'f', [1, 2, ..]), reduce(...random.choice(f)...)][1]...
Every once in a while, the following exception will be generated. But NOT always. That's my problem. I suspect that the order of execution is not guaranteed especially since I'm using the list trick -- I would assume that maybe the interpreter can predict that setattr() returns None and knows that I'm only selecting the 2nd thing in the list, so it defers the actual setattr() to later. But it only happens sometimes. Any ideas? Does CPython automatically thread some things like map, filter, reduce calls?
Traceback (most recent call last):
File "/usr/lib64/python3.4/random.py", line 253, in choice
i = self._randbelow(len(seq))
File "/usr/lib64/python3.4/random.py", line 230, in _randbelow
r = getrandbits(k) # 0 <= r < 2**k
ValueError: number of bits must be greater than zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test4.py", line 2, in <module>
print(" ".join([setattr(n,'f',open(sys.argv[1],"r").read().replace("\n"," ").split(" ")),setattr(n,'m',c.defaultdict(list)),g.reduce(lambda p,e:p+[r.choice(m[p[-1]])],range(int(sys.argv[2])),[r.choice(list(filter(lambda x:[m[x[0]].append(x[1]),x[0].isupper()][1],zip(f[:-1],f[1:]))))[0]])][2]))
File "test4.py", line 2, in <lambda>
print(" ".join([setattr(n,'f',open(sys.argv[1],"r").read().replace("\n"," ").split(" ")),setattr(n,'m',c.defaultdict(list)),g.reduce(lambda p,e:p+[r.choice(m[p[-1]])],range(int(sys.argv[2])),[r.choice(list(filter(lambda x:[m[x[0]].append(x[1]),x[0].isupper()][1],zip(f[:-1],f[1:]))))[0]])][2]))
File "/usr/lib64/python3.4/random.py", line 255, in choice
raise IndexError('Cannot choose from an empty sequence')
IndexError: Cannot choose from an empty sequence
I've tried modifying globals() and vars() insetad of using setattr(), but that does not seem to help (same exception sequence).
Here's the actual code:
import sys,collections as c,random as r,functools as g,__main__ as n
print(" ".join([setattr(n,'f',open(sys.argv[1],"r").read().replace("\n"," ").split(" ")),setattr(n,'m',c.defaultdict(list)),g.reduce(lambda p,e:p+[r.choice(m[p[-1]])],range(int(sys.argv[2])),[r.choice(list(filter(lambda x:[m[x[0]].append(x[1]),x[0].isupper()][1],zip(f[:-1],f[1:]))))[0]])][2]))
If you're curious: This is to read in a text file, generate a Markov model, and spit out a sentence.
random.choice()
Well, of course that is nondeterministic. If you are very careful, you could set the seed of the pseudo-random number generator to something constant, and hope that's fabricates the same sequence every time. There's a good chance it will work.
random.seed(42); ...
Alright, here's what actually happened: In my sentence generation, I sometimes hit the last word in the file (which in some cases, depending on the file, does not have a possible successor state). Hence, I'm trying to choose from an empty list in that case.

github3.py etag for conditional requests

I'm using github3.py passing the etag parameter each time I call an iterator, for example:
user.iter_starred(etag='97ba89b5c009e5530f108a06606f3e2c')
in order to avoid to consume my rate limit and performing a conditional request. But no matter what, when I start the iteration github3 always perform a proper request (and so the real data are fetched) decreasing the rate limit by 1.
Am I doing something wrong or is it a bug?
From my own experimentation this seems to work as expected:
>>> import github3
>>> u = github3.user('sigmavirus24')
>>> u
<User [sigmavirus24:Ian Cordasco]>
>>> i = u.iter_starred()
>>> i
<GitHubIterator [-1, /users/sigmavirus24/starred]>
>>> next(i)
<Repository [functional-koans/clojure-koans]>
>>> i.etag
'"1aeaaa7a249610c52ba0363009afcab9"'
>>> next(u.iter_starred(etag=i.etag))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "github3/structs.py", line 103, in next
return self.__next__()
File "github3/structs.py", line 90, in __next__
return next(self.__i__)
StopIteration
The difference between our examples is that your etag value is '97ba89b5c009e5530f108a06606f3e2c', where as the equivalent to mine is '"97ba89b5c009e5530f108a06606f3e2c"'. Since this value is placed in the headers I think it is important that the header be:
If-None-Match: "97ba89b5c009e5530f108a06606f3e2c"
Instead of:
If-None-Match: 97ba89b5c009e5530f108a06606f3e2c
Which is what yours will send.
And I just checked and that is what's wrong. The library works as expected. The way you're passing your etag value is wrong. It needs to have double quotes around the value (e.g., '"97ba89b5c009e5530f108a06606f3e2c"') to work properly.

python AssertionError in django

I am reading the http://www.djangobook.com/en/2.0/chapter04.html. I'm new to python and django but have experience with php.
I've come across the following:
>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
... def first_name(self):
... raise AssertionError, "foo"
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
this gives the following error;
Traceback (most recent call last):
...
AssertionError: foo
would someone mind explaining why this error occurs? I'm not sure I follow what the problem is. I understand lines 1,2 and 5 but not the others.
Thank you,
Bill
Your code has done exactly what the example was trying to show. You “raised” an exception which caused your program to halt execution because there was no handler to deal with it.
This guide might be a good place to start.

Categories

Resources