deadpixi / contracts

An implementation of contracts for Python.
GNU Lesser General Public License v3.0
342 stars 18 forks source link

Handling generators #3

Closed wontonst closed 6 years ago

wontonst commented 6 years ago

I found an issue with this library.

If you pass a generator to a function that has an @require which loops through the generator to do some verification, the pointer to the empty generator is returned.

Here's a minimal repro:

(default) Roys-MacBook-Pro:web royzheng$ cat o.py
from dpcontracts import require

@require('mylist should have elements greater than 0', lambda args: all(a > 0 for a in args.mylist))
def test(mylist):
    print(list(mylist))

test([1,2,3])
test(x for x in xrange(1,4))
(default) Roys-MacBook-Pro:web royzheng$ python o.py
[1, 2, 3]
[]

Smells like somewhere in the code we need to check inspect.isgeneratorfunction and if so, original_generator = itertools.tee(the_generator) and pass that to the function instead of the original generator

wontonst commented 6 years ago

Same issue if the user iterates thru the generator again on @ensure

wontonst commented 6 years ago

@deadpixi I have a possible solution up at #5 please have a look.

deadpixi commented 6 years ago

@wontonst Please look at my comments on the PR, and check out the new rewrite and transform functionality in the master branch and let me know if that solves your problem.