Skip to content

Commit

Permalink
Fixed an issue where using partial on a generator function in pytho…
Browse files Browse the repository at this point in the history
…n 3.5 was raising a `SyntaxError`. Fixed #79
  • Loading branch information
Sylvain MARIE committed Jan 7, 2022
1 parent e4f4b5b commit 2101bca
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,3 @@ def partial_f(*args, **kwargs):
kwargs.update(preset_kwargs) # for python 3.4: explicit dict update
yield from f(*chain(preset_pos_args, args), **kwargs)
return partial_f


def make_partial_using_async_for_in_yield(new_sig, f, *preset_pos_args, **preset_kwargs):
"""
Makes a 'partial' when f is a async generator and python is new enough to support `async for v in f(): yield v`
:param new_sig:
:param f:
:param presets:
:return:
"""

@wraps(f, new_sig=new_sig)
async def partial_f(*args, **kwargs):
kwargs.update(preset_kwargs)
async for v in f(*chain(preset_pos_args, args), **kwargs):
yield v

return partial_f
26 changes: 26 additions & 0 deletions src/makefun/_main_py36_and_higher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Authors: Sylvain MARIE <[email protected]>
# + All contributors to <https://github.com/smarie/python-makefun>
#
# License: 3-clause BSD, <https://github.com/smarie/python-makefun/blob/master/LICENSE>
from itertools import chain

from makefun.main import wraps


def make_partial_using_async_for_in_yield(new_sig, f, *preset_pos_args, **preset_kwargs):
"""
Makes a 'partial' when f is a async generator and python is new enough to support `async for v in f(): yield v`
:param new_sig:
:param f:
:param presets:
:return:
"""

@wraps(f, new_sig=new_sig)
async def partial_f(*args, **kwargs):
kwargs.update(preset_kwargs)
async for v in f(*chain(preset_pos_args, args), **kwargs):
yield v

return partial_f
4 changes: 2 additions & 2 deletions src/makefun/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1127,13 +1127,13 @@ def partial(f, # type: Callable

if _is_generator_func(f):
if sys.version_info >= (3, 3):
from makefun._main_latest_py import make_partial_using_yield_from
from makefun._main_py35_and_higher import make_partial_using_yield_from
partial_f = make_partial_using_yield_from(new_sig, f, *preset_pos_args, **preset_kwargs)
else:
from makefun._main_legacy_py import make_partial_using_yield
partial_f = make_partial_using_yield(new_sig, f, *preset_pos_args, **preset_kwargs)
elif isasyncgenfunction(f) and sys.version_info >= (3, 6):
from makefun._main_latest_py import make_partial_using_async_for_in_yield
from makefun._main_py36_and_higher import make_partial_using_async_for_in_yield
partial_f = make_partial_using_async_for_in_yield(new_sig, f, *preset_pos_args, **preset_kwargs)
else:
@wraps(f, new_sig=new_sig)
Expand Down
22 changes: 17 additions & 5 deletions tests/test_partial_and_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,19 @@ def f(a, b, c, **d):
# assert str(signature(fp_ref)) == str(signature(fp))


def test_simple_partial_copy():
"""Test that when not providing any argument to partial, it is equivalent to wraps with new sig = None"""
def f1(a):
return a + 1
@pytest.mark.parametrize("is_generator", [False, True])
def test_simple_partial_copy(is_generator):
"""Test that when not providing any argument to partial, it is equivalent to wraps with new sig = None
This test was extended to cover issue 79.
"""

if is_generator:
def f1(a):
yield a + 1
else:
def f1(a):
return a + 1

f2 = makefun.partial(f1)

Expand All @@ -188,7 +197,10 @@ def f1(a):
f3 = makefun.wraps(f1)(f1)
assert f3.__wrapped__ == f1

assert f2(1) == f3(1) == 2
if is_generator:
assert next(f2(1)) == next(f3(1)) == 2
else:
assert f2(1) == f3(1) == 2

# the func attribute is there too
f4 = functools.partial(f1)
Expand Down

0 comments on commit 2101bca

Please sign in to comment.