Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-makefun for openSUSE:Factory 
checked in at 2022-09-30 17:57:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-makefun (Old)
 and      /work/SRC/openSUSE:Factory/.python-makefun.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-makefun"

Fri Sep 30 17:57:49 2022 rev:3 rq:1007066 version:1.14.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-makefun/python-makefun.changes    
2021-12-16 21:20:55.398558020 +0100
+++ /work/SRC/openSUSE:Factory/.python-makefun.new.2275/python-makefun.changes  
2022-09-30 17:58:06.945289822 +0200
@@ -1,0 +2,21 @@
+Thu Sep 29 15:46:07 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com>
+
+- Update to Version 1.15.0
+  More PEP-compliant `wraps` Latest
+  wraps now always sets the __wrapped__ attribute, and also sets the 
__signature__ attribute when the signature changes,
+  as specified by PEP 362. PR by #86 by lucaswiman.
+
+- Update to Version 1.14.0
+  Support for lambda functions
+  create_wrapper, create_function, wraps and with_signature now support lambda 
functions. They also accept a new parameter
+  co_name to define the name to be used in the compiled code. PR #80 by 
andrewcleveland.
+
+- Update to Version 1.13.1
+  - Fixed regression with generators in python 3.5
+  - Fixed an issue where using partial on a generator function in python 3.5 
was raising a SyntaxError. Fixed #79
+
+- Update to Version 1.13.0 
+  - Support for async generator functions
+    async generator functions are now supported (See PEP525). Fixed #77. PR#78 
by broglep-work.
+
+-------------------------------------------------------------------

Old:
----
  makefun-1.12.1.tar.gz

New:
----
  makefun-1.14.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-makefun.spec ++++++
--- /var/tmp/diff_new_pack.XQ6H6C/_old  2022-09-30 17:58:07.365290720 +0200
+++ /var/tmp/diff_new_pack.XQ6H6C/_new  2022-09-30 17:58:07.373290737 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-makefun
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-makefun
-Version:        1.12.1
+Version:        1.14.0
 Release:        0
 License:        BSD-3-Clause
 Summary:        Small library to dynamically create python functions

++++++ makefun-1.12.1.tar.gz -> makefun-1.14.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/LICENSE new/makefun-1.14.0/LICENSE
--- old/makefun-1.12.1/LICENSE  2021-10-08 12:12:08.000000000 +0200
+++ new/makefun-1.14.0/LICENSE  2022-06-21 23:26:54.000000000 +0200
@@ -1,6 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2019-2020, Sylvain Mari??, Schneider Electric Industries
+Copyright (c) 2019-2022, Sylvain Mari??, Schneider Electric Industries
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/PKG-INFO new/makefun-1.14.0/PKG-INFO
--- old/makefun-1.12.1/PKG-INFO 2021-10-08 12:13:06.000000000 +0200
+++ new/makefun-1.14.0/PKG-INFO 2022-06-21 23:27:52.000000000 +0200
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: makefun
-Version: 1.12.1
+Version: 1.14.0
 Summary: Small library to dynamically create python functions.
 Home-page: https://github.com/smarie/python-makefun
+Download-URL: https://github.com/smarie/python-makefun/tarball/1.14.0
 Author: Sylvain MARIE <sylvain.ma...@se.com>
 Maintainer: Sylvain MARIE <sylvain.ma...@se.com>
 License: BSD 3-Clause
-Download-URL: https://github.com/smarie/python-makefun/tarball/1.12.1
 Keywords: decorate decorator compile make dynamic function generate generation 
define definition signature args wrapper wraps
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/ci_tools/flake8-requirements.txt 
new/makefun-1.14.0/ci_tools/flake8-requirements.txt
--- old/makefun-1.12.1/ci_tools/flake8-requirements.txt 2021-10-08 
12:12:08.000000000 +0200
+++ new/makefun-1.14.0/ci_tools/flake8-requirements.txt 2022-06-21 
23:26:54.000000000 +0200
@@ -2,6 +2,7 @@
 flake8>=3.6,<4
 flake8-html>=0.4,<1
 flake8-bandit>=2.1.1,<3
+bandit<1.7.3  # temporary until this is fixed 
https://github.com/tylerwince/flake8-bandit/issues/21
 flake8-bugbear>=20.1.0,<21.0.0
 flake8-docstrings>=1.5,<2
 flake8-print>=3.1.1,<4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/docs/api_reference.md 
new/makefun-1.14.0/docs/api_reference.md
--- old/makefun-1.12.1/docs/api_reference.md    2021-10-08 12:12:08.000000000 
+0200
+++ new/makefun-1.14.0/docs/api_reference.md    2022-06-21 23:26:54.000000000 
+0200
@@ -15,6 +15,7 @@
                     add_impl: bool = True,
                     doc: str = None,
                     qualname: str = None,
+                    co_name: str = None,
                     module_name: str = None,
                     **attrs):
 ```
@@ -34,12 +35,18 @@
  - `__annotations__` attribute is created to match the annotations in the 
signature.
  - `__doc__` attribute is copied from `func_impl.__doc__` except if overridden 
using `doc`
  - `__module__` attribute is copied from `func_impl.__module__` except if 
overridden using `module_name`
+ - `__code__.co_name` (see above) defaults to the same value as the above 
`__name__` attribute, except when that value is not a valid Python identifier, 
in which case it will be `<lambda>`. It can be  overridden by providing a 
`co_name` that is either a valid Python identifier or `<lambda>`.
 
 Finally two new attributes are optionally created
 
  - `__source__` attribute: set if `add_source` is `True` (default), this 
attribute contains the source code of the generated function
  - `__func_impl__` attribute: set if `add_impl` is `True` (default), this 
attribute contains a pointer to `func_impl`
 
+A lambda function will be created in the following cases:
+
+- when `func_signature` is a `Signature` object and `func_impl` is itself a 
lambda function,
+- when the function name, either derived from a `func_signature` string, or 
given explicitly with `func_name`, is not a valid Python identifier, or
+- when the provided `co_name` is `<lambda>`.
 
 **Parameters:**
 
@@ -58,7 +65,9 @@
  * `doc`: a string representing the docstring that will be used to set the 
__doc__ attribute on the generated function. If None (default), the doc of 
func_impl will be used.
    
  * `qualname`: a string representing the qualified name to be used. If None 
(default), the `__qualname__` will default to the one of `func_impl` if 
`func_signature` is a `Signature`, or to the name defined in `func_signature` 
if `func_signature` is a `str` and contains a non-empty name.
-   
+ 
+ * `co_name`: a string representing the name to be used in the compiled code 
of the function. If None (default), the `__code__.co_name` will default to the 
one of `func_impl` if `func_signature` is a `Signature`, or to the name defined 
in `func_signature` if `func_signature` is a `str` and contains a non-empty 
name.
+
  * `module_name`: the name of the module to be set on the function (under 
__module__ ). If None (default), `func_impl.__module__` will be used.
    
  * `attrs`: other keyword attributes that should be set on the function. Note 
that `func_impl.__dict__` is not automatically copied.
@@ -73,6 +82,7 @@
                    add_impl: bool = True,
                    doc: str = None,
                    qualname: str = None,
+                   co_name: str = None,
                    module_name: str = None,
                    **attrs
                    ):
@@ -104,7 +114,9 @@
  * `doc`: a string representing the docstring that will be used to set the 
__doc__ attribute on the generated function. If None (default), the doc of the 
decorated function will be used.
    
  * `qualname`: a string representing the qualified name to be used. If None 
(default), the `__qualname__` will default to the one of `func_impl` if 
`func_signature` is a `Signature`, or to the name defined in `func_signature` 
if `func_signature` is a `str` and contains a non-empty name.
-   
+
+ * `co_name`: a string representing the name to be used in the compiled code 
of the function. If None (default), the `__code__.co_name` will default to the 
one of `func_impl` if `func_signature` is a `Signature`, or to the name defined 
in `func_signature` if `func_signature` is a `str` and contains a non-empty 
name.
+
  * `module_name`: the name of the module to be set on the function (under 
__module__ ). If None (default), the `__module__` attribute of the decorated 
function will be used.
    
  * `attrs`: other keyword attributes that should be set on the function. Note 
that the full `__dict__` of the decorated function is not automatically copied.
@@ -124,6 +136,7 @@
           add_impl: bool = True,
           doc: str = None,
           qualname: str = None,
+          co_name: str = None,
           module_name: str = None,
           **attrs
           ):
@@ -180,7 +193,9 @@
  - `doc`: a string representing the docstring that will be used to set the 
__doc__ attribute on the generated function. If None (default), the doc of 
`wrapped_fun` will be used. If `wrapped_fun` is an instance of 
`functools.partial`, a special enhanced doc will be generated.
    
  - `qualname`: a string representing the qualified name to be used. If None 
(default), the `__qualname__` will default to the one of `wrapped_fun`, or the 
one in `new_sig` if `new_sig` is provided as a string with a non-empty function 
name.
-   
+ 
+ - `co_name`: a string representing the name to be used in the compiled code 
of the function. If None (default), the `__code__.co_name` will default to the 
one of `func_impl` if `func_signature` is a `Signature`, or to the name defined 
in `func_signature` if `func_signature` is a `str` and contains a non-empty 
name.
+
  - `module_name`: the name of the module to be set on the function (under 
__module__ ). If None (default), the `__module__` attribute of `wrapped_fun` 
will be used.
    
  - `attrs`: other keyword attributes that should be set on the function. Note 
that the full `__dict__` of `wrapped_fun` is automatically copied.
@@ -201,6 +216,7 @@
                    add_impl: bool = True,
                    doc: str = None,
                    qualname: str = None,
+                   co_name: str = None,
                    module_name: str = None,
                    **attrs
                    ):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/docs/changelog.md 
new/makefun-1.14.0/docs/changelog.md
--- old/makefun-1.12.1/docs/changelog.md        2021-10-08 12:12:08.000000000 
+0200
+++ new/makefun-1.14.0/docs/changelog.md        2022-06-21 23:26:54.000000000 
+0200
@@ -1,5 +1,17 @@
 # Changelog
 
+### 1.14.0 - Support for lambda functions
+
+ - `create_wrapper`, `create_function`, `wraps` and `with_signature` now 
support lambda functions. They also accept a new parameter `co_name` to define 
the name to be used in the compiled code. PR 
[#80](https://github.com/smarie/python-makefun/pull/80) by 
[andrewcleveland](https://github.com/andrewcleveland).
+
+### 1.13.1 - Fixed regression with generators in python 3.5
+
+ - Fixed an issue where using `partial` on a generator function in python 3.5 
was raising a `SyntaxError`. Fixed 
[#79](https://github.com/smarie/python-makefun/issues/79)
+
+### 1.13.0 - Support for async generator functions
+
+ - async generator functions are now supported (See 
[PEP525](https://www.python.org/dev/peps/pep-0525/)). Fixed 
[#77](https://github.com/smarie/python-makefun/issues/77). 
[PR#78](https://github.com/smarie/python-makefun/pull/78) by 
[broglep-work](https://github.com/broglep-work).
+
 ### 1.12.1 - Bugfix
 
  - Fixed `TypeError` when a `func` attribute is present on the function 
provided to `create_function`. Fixed 
[#76](https://github.com/smarie/python-makefun/issues/76)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/noxfile.py 
new/makefun-1.14.0/noxfile.py
--- old/makefun-1.12.1/noxfile.py       2021-10-08 12:12:08.000000000 +0200
+++ new/makefun-1.14.0/noxfile.py       2022-06-21 23:26:54.000000000 +0200
@@ -103,19 +103,22 @@
     # Fail if the assumed python version is not the actual one
     session.run2("python ci_tools/check_python_version.py %s" % session.python)
 
-    # install self so that it is recognized by pytest
-    session.run2("pip install -e . --no-deps")
-    # session.install("-e", ".", "--no-deps")
-
     # check that it can be imported even from a different folder
     # Important: do not surround the command into double quotes as in the 
shell !
-    session.run('python', '-c', 'import os; os.chdir(\'./docs/\'); import %s' 
% pkg_name)
+    # session.run('python', '-c', 'import os; os.chdir(\'./docs/\'); import 
%s' % pkg_name)
 
     # finally run all tests
     if not coverage:
+        # install self so that it is recognized by pytest
+        session.run2("pip install . --no-deps")
+        # session.install(".", "--no-deps")
+
         # simple: pytest only
         session.run2("python -m pytest --cache-clear -v tests/")
     else:
+        # install self in "develop" mode so that coverage can be measured
+        session.run2("pip install -e . --no-deps")
+
         # coverage + junit html reports + badge generation
         session.install_reqs(phase="coverage",
                              phase_reqs=["coverage", "pytest-html", 
"genbadge[tests,coverage]"],
@@ -144,7 +147,7 @@
 
     session.install("-r", str(Folders.ci_tools / "flake8-requirements.txt"))
     session.install("genbadge[flake8]")
-    session.run2("pip install -e .[flake8]")
+    session.run2("pip install .")
 
     rm_folder(Folders.flake8_reports)
     Folders.flake8_reports.mkdir(parents=True, exist_ok=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun/_main_latest_py.py 
new/makefun-1.14.0/src/makefun/_main_latest_py.py
--- old/makefun-1.12.1/src/makefun/_main_latest_py.py   2021-10-08 
12:12:08.000000000 +0200
+++ new/makefun-1.14.0/src/makefun/_main_latest_py.py   1970-01-01 
01:00:00.000000000 +0100
@@ -1,24 +0,0 @@
-# Authors: Sylvain MARIE <sylvain.ma...@se.com>
-#          + 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_yield_from(new_sig, f, *preset_pos_args, 
**preset_kwargs):
-    """
-    Makes a 'partial' when f is a generator and python is new enough to 
support `yield from`
-
-    :param new_sig:
-    :param f:
-    :param presets:
-    :return:
-    """
-    @wraps(f, new_sig)
-    def partial_f(*args, **kwargs):
-        # since the signature does the checking for us, no need to check for 
redundancy.
-        kwargs.update(preset_kwargs)  # for python 3.4: explicit dict update
-        yield from f(*chain(preset_pos_args, args), **kwargs)
-    return partial_f
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun/_main_py35_and_higher.py 
new/makefun-1.14.0/src/makefun/_main_py35_and_higher.py
--- old/makefun-1.12.1/src/makefun/_main_py35_and_higher.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/makefun-1.14.0/src/makefun/_main_py35_and_higher.py     2022-06-21 
23:26:54.000000000 +0200
@@ -0,0 +1,24 @@
+# Authors: Sylvain MARIE <sylvain.ma...@se.com>
+#          + 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_yield_from(new_sig, f, *preset_pos_args, 
**preset_kwargs):
+    """
+    Makes a 'partial' when f is a generator and python is new enough to 
support `yield from`
+
+    :param new_sig:
+    :param f:
+    :param presets:
+    :return:
+    """
+    @wraps(f, new_sig)
+    def partial_f(*args, **kwargs):
+        # since the signature does the checking for us, no need to check for 
redundancy.
+        kwargs.update(preset_kwargs)  # for python 3.4: explicit dict update
+        yield from f(*chain(preset_pos_args, args), **kwargs)
+    return partial_f
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun/_main_py36_and_higher.py 
new/makefun-1.14.0/src/makefun/_main_py36_and_higher.py
--- old/makefun-1.12.1/src/makefun/_main_py36_and_higher.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/makefun-1.14.0/src/makefun/_main_py36_and_higher.py     2022-06-21 
23:26:54.000000000 +0200
@@ -0,0 +1,26 @@
+# Authors: Sylvain MARIE <sylvain.ma...@se.com>
+#          + 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun/_version.py 
new/makefun-1.14.0/src/makefun/_version.py
--- old/makefun-1.12.1/src/makefun/_version.py  2021-10-08 12:13:06.000000000 
+0200
+++ new/makefun-1.14.0/src/makefun/_version.py  2022-06-21 23:27:51.000000000 
+0200
@@ -1,5 +1,5 @@
 # coding: utf-8
 # file generated by setuptools_scm
 # don't change, don't track in version control
-version = '1.12.1'
-version_tuple = (1, 12, 1)
+__version__ = version = '1.14.0'
+__version_tuple__ = version_tuple = (1, 14, 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun/main.py 
new/makefun-1.14.0/src/makefun/main.py
--- old/makefun-1.12.1/src/makefun/main.py      2021-10-08 12:12:08.000000000 
+0200
+++ new/makefun-1.14.0/src/makefun/main.py      2022-06-21 23:26:54.000000000 
+0200
@@ -11,9 +11,24 @@
 from collections import OrderedDict
 from copy import copy
 from inspect import getsource
+from keyword import iskeyword
 from textwrap import dedent
 from types import FunctionType
 
+
+if sys.version_info >= (3, 0):
+    is_identifier = str.isidentifier
+else:
+    def is_identifier(string):
+        """
+        Replacement for `str.isidentifier` when it is not available (e.g. on 
Python 2).
+        :param string:
+        :return:
+        """
+        if len(string) == 0 or string[0].isdigit():
+            return False
+        return all([s.isalnum() for s in string.split("_")])
+
 try:  # python 3.3+
     from inspect import signature, Signature, Parameter
 except ImportError:
@@ -33,6 +48,13 @@
     def isgeneratorfunction(f):
         return False
 
+try:
+    from inspect import isasyncgenfunction
+except ImportError:
+    # assume no generator function in old Python versions
+    def isasyncgenfunction(f):
+        return False
+
 try:  # python 3.5+
     from typing import Callable, Any, Union, Iterable, Dict, Tuple, Mapping
 except ImportError:
@@ -66,6 +88,7 @@
                    add_impl=True,              # type: bool
                    doc=None,                   # type: str
                    qualname=None,              # type: str
+                   co_name=None,               # type: str
                    module_name=None,           # type: str
                    **attrs
                    ):
@@ -77,7 +100,8 @@
     """
     return wraps(wrapped, new_sig=new_sig, prepend_args=prepend_args, 
append_args=append_args, remove_args=remove_args,
                  func_name=func_name, inject_as_first_arg=inject_as_first_arg, 
add_source=add_source,
-                 add_impl=add_impl, doc=doc, qualname=qualname, 
module_name=module_name, **attrs)(wrapper)
+                 add_impl=add_impl, doc=doc, qualname=qualname, 
module_name=module_name, co_name=co_name,
+                 **attrs)(wrapper)
 
 
 def getattr_partial_aware(obj, att_name, *att_default):
@@ -99,6 +123,7 @@
                     add_impl=True,              # type: bool
                     doc=None,                   # type: str
                     qualname=None,              # type: str
+                    co_name=None,               # type: str
                     module_name=None,           # type: str
                     **attrs):
     """
@@ -123,6 +148,9 @@
      - `__annotations__` attribute is created to match the annotations in the 
signature.
      - `__doc__` attribute is copied from `func_impl.__doc__` except if 
overridden using `doc`
      - `__module__` attribute is copied from `func_impl.__module__` except if 
overridden using `module_name`
+     - `__code__.co_name` (see above) defaults to the same value as the above 
`__name__` attribute, except when that
+       value is not a valid Python identifier, in which case it will be 
`<lambda>`. It can be  overridden by providing
+       a `co_name` that is either a valid Python identifier or `<lambda>`.
 
     Finally two new attributes are optionally created
 
@@ -131,6 +159,13 @@
      - `__func_impl__` attribute: set if `add_impl` is `True` (default), this 
attribute contains a pointer to
      `func_impl`
 
+    A lambda function will be created in the following cases:
+
+     - when `func_signature` is a `Signature` object and `func_impl` is itself 
a lambda function,
+     - when the function name, either derived from a `func_signature` string, 
or given explicitly with `func_name`,
+       is not a valid Python identifier, or
+     - when the provided `co_name` is `<lambda>`.
+
     :param func_signature: either a string without 'def' such as "foo(a, b: 
int, *args, **kwargs)" or "(a, b: int)",
         or a `Signature` object, for example from the output of 
`inspect.signature` or from the `funcsigs.signature`
         backport. Note that these objects can be created manually too. If the 
signature is provided as a string and
@@ -152,6 +187,9 @@
     :param qualname: a string representing the qualified name to be used. If 
None (default), the `__qualname__` will
         default to the one of `func_impl` if `func_signature` is a 
`Signature`, or to the name defined in
         `func_signature` if `func_signature` is a `str` and contains a 
non-empty name.
+    :param co_name: a string representing the name to be used in the compiled 
code of the function. If None (default),
+        the `__code__.co_name` will default to the one of `func_impl` if 
`func_signature` is a `Signature`, or to the
+        name defined in `func_signature` if `func_signature` is a `str` and 
contains a non-empty name.
     :param module_name: the name of the module to be set on the function 
(under __module__ ). If None (default),
         `func_impl.__module__` will be used.
     :param attrs: other keyword attributes that should be set on the function. 
Note that `func_impl.__dict__` is not
@@ -170,10 +208,24 @@
     # name defaults
     user_provided_name = True
     if func_name is None:
-        # allow None for now, we'll raise a ValueError later if needed
+        # allow None, this will result in a lambda function being created
         func_name = getattr_partial_aware(func_impl, '__name__', None)
         user_provided_name = False
 
+    # co_name default
+    user_provided_co_name = co_name is not None
+    if not user_provided_co_name:
+        if func_name is None:
+            co_name = '<lambda>'
+        else:
+            co_name = func_name
+    else:
+        if not (_is_valid_func_def_name(co_name)
+                or _is_lambda_func_name(co_name)):
+            raise ValueError("Invalid co_name %r for created function. "
+                             "It is not possible to declare a function "
+                             "with the provided co_name." % co_name)
+
     # qname default
     user_provided_qname = True
     if qualname is None:
@@ -201,25 +253,28 @@
                 func_name = func_name_from_str
             if not user_provided_qname:
                 qualname = func_name
+            if not user_provided_co_name:
+                co_name = func_name
+
+        create_lambda = not _is_valid_func_def_name(co_name)
 
+        # if lambda, strip the name, parentheses and colon from the signature
+        if create_lambda:
+            name_len = len(func_name_from_str) if func_name_from_str else 0
+            func_signature_str = func_signature_str[name_len + 1: -2]
         # fix the signature if needed
-        if func_name_from_str is None:
-            if func_name is None:
-                raise ValueError("Invalid signature for created function: 
`None` function name. This "
-                                 "probably happened because the decorated 
function %s has no __name__. You may "
-                                 "wish to pass an explicit `func_name` or to 
complete the signature string"
-                                 "with the name before the parenthesis." % 
func_impl)
-            func_signature_str = func_name + func_signature_str
+        elif func_name_from_str is None:
+            func_signature_str = co_name + func_signature_str
 
     elif isinstance(func_signature, Signature):
         # create the signature string
-        if func_name is None:
-            raise ValueError("Invalid signature for created function: `None` 
function name. This "
-                             "probably happened because the decorated function 
%s has no __name__. You may "
-                             "wish to pass an explicit `func_name` or to 
provide the new signature as a "
-                             "string containing the name" % func_impl)
-        func_signature_str = get_signature_string(func_name, func_signature, 
evaldict)
+        create_lambda = not _is_valid_func_def_name(co_name)
 
+        if create_lambda:
+            # create signature string (or argument string in the case of a 
lambda function
+            func_signature_str = get_lambda_argument_string(func_signature, 
evaldict)
+        else:
+            func_signature_str = get_signature_string(co_name, func_signature, 
evaldict)
     else:
         raise TypeError("Invalid type for `func_signature`: %s" % 
type(func_signature))
 
@@ -246,6 +301,13 @@
         else:
             from makefun._main_legacy_py import 
get_legacy_py_generator_body_template
             body = get_legacy_py_generator_body_template() % 
(func_signature_str, params_str)
+    elif isasyncgenfunction(func_impl):
+        body = "async def %s\n    async for y in _func_impl_(%s):\n        
yield y\n" % (func_signature_str, params_str)
+    elif create_lambda:
+        if func_signature_str:
+            body = "lambda_ = lambda %s: _func_impl_(%s)\n" % 
(func_signature_str, params_str)
+        else:
+            body = "lambda_ = lambda: _func_impl_(%s)\n" % (params_str)
     else:
         body = "def %s\n    return _func_impl_(%s)\n" % (func_signature_str, 
params_str)
 
@@ -255,7 +317,10 @@
     # create the function by compiling code, mapping the `_func_impl_` symbol 
to `func_impl`
     protect_eval_dict(evaldict, func_name, params_names)
     evaldict['_func_impl_'] = func_impl
-    f = _make(func_name, params_names, body, evaldict)
+    if create_lambda:
+        f = _make("lambda_", params_names, body, evaldict)
+    else:
+        f = _make(co_name, params_names, body, evaldict)
 
     # add the source annotation if needed
     if add_source:
@@ -288,6 +353,24 @@
         return isgeneratorfunction(func_impl)
 
 
+def _is_lambda_func_name(func_name):
+    """
+    Return True if func_name is the name of a lambda
+    :param func_name:
+    :return:
+    """
+    return func_name == (lambda: None).__code__.co_name
+
+
+def _is_valid_func_def_name(func_name):
+    """
+    Return True if func_name is valid in a function definition.
+    :param func_name:
+    :return:
+    """
+    return is_identifier(func_name) and not iskeyword(func_name)
+
+
 class _SymbolRef:
     """
     A class used to protect signature default values and type hints when the 
local context would not be able
@@ -357,6 +440,17 @@
     return "%s%s:" % (func_name, s)
 
 
+def get_lambda_argument_string(func_signature, evaldict):
+    """
+    Returns the string to be used as arguments in a lambda function definition.
+    If there is a non-native symbol in the defaults, it is created as a 
variable in the evaldict
+    :param func_name:
+    :param func_signature:
+    :return:
+    """
+    return get_signature_string('', func_signature, evaldict)[1:-2]
+
+
 TYPES_WITH_SAFE_REPR = (int, str, bytes, bool)
 # IMPORTANT note: float is not in the above list because not all floats have a 
repr that is valid for the
 # compiler: float('nan'), float('-inf') and float('inf') or float('+inf') have 
an invalid repr.
@@ -685,6 +779,7 @@
           append_args=None,           # type: Union[str, Parameter, 
Iterable[Union[str, Parameter]]]
           remove_args=None,           # type: Union[str, Iterable[str]]
           func_name=None,             # type: str
+          co_name=None,               # type: str
           inject_as_first_arg=False,  # type: bool
           add_source=True,            # type: bool
           add_impl=True,              # type: bool
@@ -765,17 +860,22 @@
     :param qualname: a string representing the qualified name to be used. If 
None (default), the `__qualname__` will
         default to the one of `wrapped_fun`, or the one in `new_sig` if 
`new_sig` is provided as a string with a
         non-empty function name.
+    :param co_name: a string representing the name to be used in the compiled 
code of the function. If None (default),
+        the `__code__.co_name` will default to the one of `func_impl` if 
`func_signature` is a `Signature`, or to the
+        name defined in `func_signature` if `func_signature` is a `str` and 
contains a non-empty name.
     :param module_name: the name of the module to be set on the function 
(under __module__ ). If None (default), the
         `__module__` attribute of `wrapped_fun` will be used.
     :param attrs: other keyword attributes that should be set on the function. 
Note that the full `__dict__` of
         `wrapped_fun` is automatically copied.
     :return: a decorator
     """
-    func_name, func_sig, doc, qualname, module_name, all_attrs = 
_get_args_for_wrapping(wrapped_fun, new_sig,
-                                                                               
         remove_args,
-                                                                               
         prepend_args, append_args,
-                                                                               
         func_name, doc,
-                                                                               
         qualname, module_name, attrs)
+    func_name, func_sig, doc, qualname, co_name, module_name, all_attrs = 
_get_args_for_wrapping(wrapped_fun, new_sig,
+                                                                               
                  remove_args,
+                                                                               
                  prepend_args,
+                                                                               
                  append_args,
+                                                                               
                  func_name, doc,
+                                                                               
                  qualname, co_name,
+                                                                               
                  module_name, attrs)
 
     return with_signature(func_sig,
                           func_name=func_name,
@@ -783,12 +883,13 @@
                           add_source=add_source, add_impl=add_impl,
                           doc=doc,
                           qualname=qualname,
+                          co_name=co_name,
                           module_name=module_name,
                           **all_attrs)
 
 
 def _get_args_for_wrapping(wrapped, new_sig, remove_args, prepend_args, 
append_args,
-                           func_name, doc, qualname, module_name, attrs):
+                           func_name, doc, qualname, co_name, module_name, 
attrs):
     """
     Internal method used by @wraps and create_wrapper
 
@@ -800,6 +901,7 @@
     :param func_name:
     :param doc:
     :param qualname:
+    :param co_name:
     :param module_name:
     :param attrs:
     :return:
@@ -851,6 +953,10 @@
         qualname = getattr_partial_aware(wrapped, '__qualname__', None)
     if module_name is None:
         module_name = getattr_partial_aware(wrapped, '__module__', None)
+    if co_name is None:
+        code = getattr_partial_aware(wrapped, '__code__', None)
+        if code is not None:
+            co_name = code.co_name
 
     # attributes: start from the wrapped dict, add '__wrapped__' if needed, 
and override with all attrs.
     all_attrs = copy(getattr_partial_aware(wrapped, '__dict__'))
@@ -865,7 +971,7 @@
         all_attrs['__wrapped__'] = wrapped
     all_attrs.update(attrs)
 
-    return func_name, func_sig, doc, qualname, module_name, all_attrs
+    return func_name, func_sig, doc, qualname, co_name, module_name, all_attrs
 
 
 def with_signature(func_signature,             # type: Union[str, Signature]
@@ -875,6 +981,7 @@
                    add_impl=True,            # type: bool
                    doc=None,                   # type: str
                    qualname=None,              # type: str
+                   co_name=None,                # type: str
                    module_name=None,            # type: str
                    **attrs
                    ):
@@ -916,12 +1023,15 @@
     :param qualname: a string representing the qualified name to be used. If 
None (default), the `__qualname__` will
         default to the one of `func_impl` if `func_signature` is a 
`Signature`, or to the name defined in
         `func_signature` if `func_signature` is a `str` and contains a 
non-empty name.
+    :param co_name: a string representing the name to be used in the compiled 
code of the function. If None (default),
+        the `__code__.co_name` will default to the one of `func_impl` if 
`func_signature` is a `Signature`, or to the
+        name defined in `func_signature` if `func_signature` is a `str` and 
contains a non-empty name.
     :param module_name: the name of the module to be set on the function 
(under __module__ ). If None (default), the
         `__module__` attribute of the decorated function will be used.
     :param attrs: other keyword attributes that should be set on the function. 
Note that the full `__dict__` of the
         decorated function is not automatically copied.
     """
-    if func_signature is None:
+    if func_signature is None and co_name is None:
         # make sure that user does not provide non-default other args
         if inject_as_first_arg or not add_source or not add_impl:
             raise ValueError("If `func_signature=None` no new signature will 
be generated so only `func_name`, "
@@ -950,6 +1060,7 @@
                                    add_impl=add_impl,
                                    doc=doc,
                                    qualname=qualname,
+                                   co_name=co_name,
                                    module_name=module_name,
                                    _with_sig_=True,  # special trick to tell 
create_function that we're @with_signature
                                    **attrs
@@ -1118,11 +1229,14 @@
 
     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_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)
         def partial_f(*args, **kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun.egg-info/PKG-INFO 
new/makefun-1.14.0/src/makefun.egg-info/PKG-INFO
--- old/makefun-1.12.1/src/makefun.egg-info/PKG-INFO    2021-10-08 
12:13:06.000000000 +0200
+++ new/makefun-1.14.0/src/makefun.egg-info/PKG-INFO    2022-06-21 
23:27:52.000000000 +0200
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: makefun
-Version: 1.12.1
+Version: 1.14.0
 Summary: Small library to dynamically create python functions.
 Home-page: https://github.com/smarie/python-makefun
+Download-URL: https://github.com/smarie/python-makefun/tarball/1.14.0
 Author: Sylvain MARIE <sylvain.ma...@se.com>
 Maintainer: Sylvain MARIE <sylvain.ma...@se.com>
 License: BSD 3-Clause
-Download-URL: https://github.com/smarie/python-makefun/tarball/1.12.1
 Keywords: decorate decorator compile make dynamic function generate generation 
define definition signature args wrapper wraps
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/src/makefun.egg-info/SOURCES.txt 
new/makefun-1.14.0/src/makefun.egg-info/SOURCES.txt
--- old/makefun-1.12.1/src/makefun.egg-info/SOURCES.txt 2021-10-08 
12:13:06.000000000 +0200
+++ new/makefun-1.14.0/src/makefun.egg-info/SOURCES.txt 2022-06-21 
23:27:52.000000000 +0200
@@ -18,8 +18,9 @@
 docs/index.md
 docs/long_description.md
 src/makefun/__init__.py
-src/makefun/_main_latest_py.py
 src/makefun/_main_legacy_py.py
+src/makefun/_main_py35_and_higher.py
+src/makefun/_main_py36_and_higher.py
 src/makefun/_version.py
 src/makefun/main.py
 src/makefun/py.typed
@@ -31,6 +32,7 @@
 src/makefun.egg-info/top_level.txt
 tests/__init__.py
 tests/_test_py35.py
+tests/_test_py36.py
 tests/_test_py38.py
 tests/test_advanced.py
 tests/test_compile_deco.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/tests/_test_py36.py 
new/makefun-1.14.0/tests/_test_py36.py
--- old/makefun-1.12.1/tests/_test_py36.py      1970-01-01 01:00:00.000000000 
+0100
+++ new/makefun-1.14.0/tests/_test_py36.py      2022-06-21 23:26:54.000000000 
+0200
@@ -0,0 +1,17 @@
+def make_async_generator():
+    """Returns a new async generator function to use in tests."""
+
+    async def f(v):
+        yield v
+
+    return f
+
+
+def make_async_generator_wrapper(async_gen_f):
+    """Returns a new async generator function wrapping `f`, to use in tests."""
+
+    async def wrapper(*args, **kwargs):
+        async for v in async_gen_f(*args, **kwargs):
+            yield v
+
+    return wrapper
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/tests/test_advanced.py 
new/makefun-1.14.0/tests/test_advanced.py
--- old/makefun-1.12.1/tests/test_advanced.py   2021-10-08 12:12:08.000000000 
+0200
+++ new/makefun-1.14.0/tests/test_advanced.py   2022-06-21 23:26:54.000000000 
+0200
@@ -5,7 +5,7 @@
 
 from makefun.main import get_signature_from_string, with_signature
 
-from makefun import wraps
+from makefun import create_wrapper, wraps
 
 try:  # python 3.3+
     from inspect import signature, Signature, Parameter
@@ -108,6 +108,96 @@
     assert goo('hello') == 'hello'
 
 
+def tests_wraps_lambda():
+    """ Tests that `@wraps` can duplicate the signature of a lambda """
+    foo = lambda a: a
+
+    @wraps(foo)
+    def goo(*args, **kwargs):
+        return foo(*args, **kwargs)
+
+    assert goo.__name__ == (lambda: None).__name__
+    assert str(signature(goo)) == '(a)'
+    assert goo('hello') == 'hello'
+
+
+def tests_wraps_renamed_lambda():
+     """ Tests that `@wraps` can duplicate the signature of a lambda that has 
been renamed """
+     foo = lambda a: a
+     foo.__name__ = 'bar'
+
+     @wraps(foo)
+     def goo(*args, **kwargs):
+         return foo(*args, **kwargs)
+
+     assert goo.__name__ == 'bar'
+     assert str(signature(goo)) == '(a)'
+     assert goo('hello') == 'hello'
+
+
+def test_lambda_signature_str():
+    """ Tests that `@with_signature` can create a lambda from a signature 
string """
+    new_sig = '(a, b=5)'
+
+    @with_signature(new_sig, func_name='<lambda>')
+    def foo(a, b):
+        return a + b
+
+    assert foo.__name__ == '<lambda>'
+    assert foo.__code__.co_name == '<lambda>'
+    assert str(signature(foo)) == new_sig
+    assert foo(a=4) == 9
+
+
+def test_co_name():
+    """ Tests that `@with_signature` can be used to change the 
__code__.co_name """
+    @with_signature('()', co_name='bar')
+    def foo():
+        return 'hello'
+
+    assert foo.__name__ == 'foo'
+    assert foo.__code__.co_name == 'bar'
+    assert foo() == 'hello'
+
+
+def test_with_signature_lambda():
+    """ Tests that `@with_signature` can be used to change the 
__code__.co_name to `'<lambda>'` """
+    @with_signature('()', co_name='<lambda>')
+    def foo():
+        return 'hello'
+
+    assert foo.__code__.co_name == '<lambda>'
+    assert foo() == 'hello'
+
+
+def test_create_wrapper_lambda():
+    """ Tests that `create_wrapper` returns a lambda function when given a 
lambda function to wrap"""
+    def foo():
+        return 'hello'
+    bar = create_wrapper(lambda: None, foo)
+
+    assert bar.__name__ == '<lambda>'
+    assert bar() == 'hello'
+
+
+def test_invalid_co_name():
+    """ Tests that `@with_signature` raises a `ValueError` when given an 
`co_name` that cannot be duplicated. """
+    with pytest.raises(ValueError):
+        @with_signature('()', co_name='<invalid>')
+        def foo():
+            return 'hello'
+
+
+def test_invalid_func_name():
+    """ Tests that `@with_signature` can duplicate a func_name that is invalid 
in a function definition. """
+    @with_signature('()', func_name='<invalid>')
+    def foo():
+        return 'hello'
+
+    assert foo.__name__ == '<invalid>'
+    assert foo() == 'hello'
+
+
 @pytest.mark.skipif(sys.version_info < (3, 0), reason="requires python3 or 
higher")
 def test_qualname_when_nested():
     """ Tests that qualname is correctly set when `@with_signature` is applied 
on nested functions """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/tests/test_issues.py 
new/makefun-1.14.0/tests/test_issues.py
--- old/makefun-1.12.1/tests/test_issues.py     2021-10-08 12:12:08.000000000 
+0200
+++ new/makefun-1.14.0/tests/test_issues.py     2022-06-21 23:26:54.000000000 
+0200
@@ -1,3 +1,4 @@
+import inspect
 import sys
 
 import pytest
@@ -224,3 +225,31 @@
 
     f2 = create_function("zoo(a)", f, func=f)
     assert f2(3) == 4
+
+
+@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python 3.6 or 
higher (async generator)")
+def test_issue_77_async_generator_wraps():
+    import asyncio
+    from ._test_py36 import make_async_generator, make_async_generator_wrapper
+
+    f = make_async_generator()
+    wrapper = wraps(f)(make_async_generator_wrapper(f))
+
+    assert inspect.isasyncgenfunction(f)
+    assert inspect.isasyncgenfunction(wrapper)
+
+    assert 
asyncio.get_event_loop().run_until_complete(asyncio.ensure_future(wrapper(1).__anext__()))
 == 1
+
+
+@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python 3.6 or 
higher (async generator)")
+def test_issue_77_async_generator_partial():
+    import asyncio
+    from ._test_py36 import make_async_generator
+
+    f = make_async_generator()
+    f_partial = partial(f, v=1)
+
+    assert inspect.isasyncgenfunction(f)
+    assert inspect.isasyncgenfunction(f_partial)
+
+    assert 
asyncio.get_event_loop().run_until_complete(asyncio.ensure_future(f_partial().__anext__()))
 == 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/makefun-1.12.1/tests/test_partial_and_macros.py 
new/makefun-1.14.0/tests/test_partial_and_macros.py
--- old/makefun-1.12.1/tests/test_partial_and_macros.py 2021-10-08 
12:12:08.000000000 +0200
+++ new/makefun-1.14.0/tests/test_partial_and_macros.py 2022-06-21 
23:26:54.000000000 +0200
@@ -174,10 +174,19 @@
         # 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)
 
@@ -188,7 +197,10 @@
     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)

Reply via email to