Hello community,

here is the log from the commit of package python-cloudpickle for 
openSUSE:Factory checked in at 2019-09-30 15:56:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cloudpickle (Old)
 and      /work/SRC/openSUSE:Factory/.python-cloudpickle.new.2352 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cloudpickle"

Mon Sep 30 15:56:31 2019 rev:8 rq:733396 version:1.2.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cloudpickle/python-cloudpickle.changes    
2019-07-31 14:15:18.638794685 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-cloudpickle.new.2352/python-cloudpickle.changes
  2019-09-30 15:56:32.597672606 +0200
@@ -1,0 +2,8 @@
+Thu Sep 26 10:40:19 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 1.2.2:
+  * Revert the change introduced in (issue #276) attempting to pickle 
functions annotations for Python 3.4 to 3.6. It is not possible to pickle 
complex typing constructs for those versions (see issue #193)
+  * Fix a bug affecting bound classmethod saving on Python 2. (issue #288)
+  * Add support for pickling "getset" descriptors (issue #290)
+
+-------------------------------------------------------------------

Old:
----
  cloudpickle-1.2.1.tar.gz

New:
----
  cloudpickle-1.2.2.tar.gz

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

Other differences:
------------------
++++++ python-cloudpickle.spec ++++++
--- /var/tmp/diff_new_pack.OuVfmM/_old  2019-09-30 15:56:33.149671137 +0200
+++ /var/tmp/diff_new_pack.OuVfmM/_new  2019-09-30 15:56:33.149671137 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-cloudpickle
-Version:        1.2.1
+Version:        1.2.2
 Release:        0
 Summary:        Extended pickling support for Python objects
 License:        BSD-3-Clause

++++++ cloudpickle-1.2.1.tar.gz -> cloudpickle-1.2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/PKG-INFO 
new/cloudpickle-1.2.2/PKG-INFO
--- old/cloudpickle-1.2.1/PKG-INFO      2019-06-10 21:56:01.000000000 +0200
+++ new/cloudpickle-1.2.2/PKG-INFO      2019-09-10 14:27:06.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cloudpickle
-Version: 1.2.1
+Version: 1.2.2
 Summary: Extended pickling support for Python objects
 Home-page: https://github.com/cloudpipe/cloudpickle
 Author: Cloudpipe
@@ -23,11 +23,15 @@
         along with **functions and classes defined interactively** in the
         `__main__` module (for instance in a script, a shell or a Jupyter 
notebook).
         
-        **`cloudpickle` uses `pickle.HIGHEST_PROTOCOL` by default**: it is 
meant to
-        send objects between processes running the **same version of Python**.
+        Cloudpickle can only be used to send objects between the **exact same 
version
+        of Python**.
         
         Using `cloudpickle` for **long-term object storage is not supported and
-        discouraged.**
+        strongly discouraged.**
+        
+        **Security notice**: one should **only load pickle data from trusted 
sources** as
+        otherwise `pickle.load` can lead to arbitrary code execution resulting 
in a critical
+        security vulnerability.
         
         
         Installation
@@ -89,6 +93,25 @@
               PYTHONPATH='.:tests' py.test
         
         
+        Note about function Annotations
+        -------------------------------
+        
+        Note that because of design issues `Python`'s `typing` module, 
`cloudpickle`
+        supports pickling type annotations of dynamic functions for `Python` 
3.7 and
+        later.  On `Python` 3.4, 3.5 and 3.6, those type annotations will be 
dropped
+        silently during pickling (example below):
+        
+        ```python
+        >>> import typing
+        >>> import cloudpickle
+        >>> def f(x: typing.Union[list, int]):
+        ...     return x
+        >>> f
+        <function __main__.f(x:Union[list, int])>
+        >>> cloudpickle.loads(cloudpickle.dumps(f))  # drops f's annotations
+        <function __main__.f(x)>
+        ```
+        
         History
         -------
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/README.md 
new/cloudpickle-1.2.2/README.md
--- old/cloudpickle-1.2.1/README.md     2019-04-17 11:27:32.000000000 +0200
+++ new/cloudpickle-1.2.2/README.md     2019-09-10 14:19:13.000000000 +0200
@@ -15,11 +15,15 @@
 along with **functions and classes defined interactively** in the
 `__main__` module (for instance in a script, a shell or a Jupyter notebook).
 
-**`cloudpickle` uses `pickle.HIGHEST_PROTOCOL` by default**: it is meant to
-send objects between processes running the **same version of Python**.
+Cloudpickle can only be used to send objects between the **exact same version
+of Python**.
 
 Using `cloudpickle` for **long-term object storage is not supported and
-discouraged.**
+strongly discouraged.**
+
+**Security notice**: one should **only load pickle data from trusted sources** 
as
+otherwise `pickle.load` can lead to arbitrary code execution resulting in a 
critical
+security vulnerability.
 
 
 Installation
@@ -81,6 +85,25 @@
       PYTHONPATH='.:tests' py.test
 
 
+Note about function Annotations
+-------------------------------
+
+Note that because of design issues `Python`'s `typing` module, `cloudpickle`
+supports pickling type annotations of dynamic functions for `Python` 3.7 and
+later.  On `Python` 3.4, 3.5 and 3.6, those type annotations will be dropped
+silently during pickling (example below):
+
+```python
+>>> import typing
+>>> import cloudpickle
+>>> def f(x: typing.Union[list, int]):
+...     return x
+>>> f
+<function __main__.f(x:Union[list, int])>
+>>> cloudpickle.loads(cloudpickle.dumps(f))  # drops f's annotations
+<function __main__.f(x)>
+```
+
 History
 -------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/cloudpickle/__init__.py 
new/cloudpickle-1.2.2/cloudpickle/__init__.py
--- old/cloudpickle-1.2.1/cloudpickle/__init__.py       2019-06-10 
21:55:30.000000000 +0200
+++ new/cloudpickle-1.2.2/cloudpickle/__init__.py       2019-09-10 
14:19:34.000000000 +0200
@@ -8,4 +8,4 @@
 if sys.version_info[:2] >= (3, 8):
     from cloudpickle.cloudpickle_fast import CloudPickler, dumps, dump
 
-__version__ = '1.2.1'
+__version__ = '1.2.2'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/cloudpickle/cloudpickle.py 
new/cloudpickle-1.2.2/cloudpickle/cloudpickle.py
--- old/cloudpickle-1.2.1/cloudpickle/cloudpickle.py    2019-06-10 
21:54:13.000000000 +0200
+++ new/cloudpickle-1.2.2/cloudpickle/cloudpickle.py    2019-09-10 
14:19:13.000000000 +0200
@@ -274,41 +274,80 @@
     return subimports
 
 
-def _make_cell_set_template_code():
-    """Get the Python compiler to emit LOAD_FAST(arg); STORE_DEREF
-
-    Notes
-    -----
-    In Python 3, we could use an easier function:
-
-    .. code-block:: python
-
-       def f():
-           cell = None
+def cell_set(cell, value):
+    """Set the value of a closure cell.
 
-           def _stub(value):
-               nonlocal cell
-               cell = value
+    The point of this function is to set the cell_contents attribute of a cell
+    after its creation. This operation is necessary in case the cell contains a
+    reference to the function the cell belongs to, as when calling the
+    function's constructor
+    ``f = types.FunctionType(code, globals, name, argdefs, closure)``,
+    closure will not be able to contain the yet-to-be-created f.
+
+    In Python3.7, cell_contents is writeable, so setting the contents of a cell
+    can be done simply using
+    >>> cell.cell_contents = value
+
+    In earlier Python3 versions, the cell_contents attribute of a cell is read
+    only, but this limitation can be worked around by leveraging the Python 3
+    ``nonlocal`` keyword.
+
+    In Python2 however, this attribute is read only, and there is no
+    ``nonlocal`` keyword. For this reason, we need to come up with more
+    complicated hacks to set this attribute.
+
+    The chosen approach is to create a function with a STORE_DEREF opcode,
+    which sets the content of a closure variable. Typically:
+
+    >>> def inner(value):
+    ...     lambda: cell  # the lambda makes cell a closure
+    ...     cell = value  # cell is a closure, so this triggers a STORE_DEREF
+
+    (Note that in Python2, A STORE_DEREF can never be triggered from an inner
+    function. The function g for example here
+    >>> def f(var):
+    ...     def g():
+    ...         var += 1
+    ...     return g
+
+    will not modify the closure variable ``var```inplace, but instead try to
+    load a local variable var and increment it. As g does not assign the local
+    variable ``var`` any initial value, calling f(1)() will fail at runtime.)
+
+    Our objective is to set the value of a given cell ``cell``. So we need to
+    somewhat reference our ``cell`` object into the ``inner`` function so that
+    this object (and not the smoke cell of the lambda function) gets affected
+    by the STORE_DEREF operation.
+
+    In inner, ``cell`` is referenced as a cell variable (an enclosing variable
+    that is referenced by the inner function). If we create a new function
+    cell_set with the exact same code as ``inner``, but with ``cell`` marked as
+    a free variable instead, the STORE_DEREF will be applied on its closure -
+    ``cell``, which we can specify explicitly during construction! The new
+    cell_set variable thus actually sets the contents of a specified cell!
+
+    Note: we do not make use of the ``nonlocal`` keyword to set the contents of
+    a cell in early python3 versions to limit possible syntax errors in case
+    test and checker libraries decide to parse the whole file.
+    """
 
-           return _stub
+    if sys.version_info[:2] >= (3, 7):  # pragma: no branch
+        cell.cell_contents = value
+    else:
+        _cell_set = types.FunctionType(
+            _cell_set_template_code, {}, '_cell_set', (), (cell,),)
+        _cell_set(value)
 
-        _cell_set_template_code = f().__code__
 
-    This function is _only_ a LOAD_FAST(arg); STORE_DEREF, but that is
-    invalid syntax on Python 2. If we use this function we also don't need
-    to do the weird freevars/cellvars swap below
-    """
-    def inner(value):
-        lambda: cell  # make ``cell`` a closure so that we get a STORE_DEREF
+def _make_cell_set_template_code():
+    def _cell_set_factory(value):
+        lambda: cell
         cell = value
 
-    co = inner.__code__
+    co = _cell_set_factory.__code__
 
-    # NOTE: we are marking the cell variable as a free variable intentionally
-    # so that we simulate an inner function instead of the outer function. This
-    # is what gives us the ``nonlocal`` behavior in a Python 2 compatible way.
     if PY2:  # pragma: no branch
-        return types.CodeType(
+        _cell_set_template_code = types.CodeType(
             co.co_argcount,
             co.co_nlocals,
             co.co_stacksize,
@@ -321,62 +360,32 @@
             co.co_name,
             co.co_firstlineno,
             co.co_lnotab,
-            co.co_cellvars,  # this is the trickery
-            (),
+            co.co_cellvars,  # co_freevars is initialized with co_cellvars
+            (),  # co_cellvars is made empty
         )
     else:
-        if hasattr(types.CodeType, "co_posonlyargcount"):  # pragma: no branch
-            return types.CodeType(
-                co.co_argcount,
-                co.co_posonlyargcount,  # Python3.8 with PEP570
-                co.co_kwonlyargcount,
-                co.co_nlocals,
-                co.co_stacksize,
-                co.co_flags,
-                co.co_code,
-                co.co_consts,
-                co.co_names,
-                co.co_varnames,
-                co.co_filename,
-                co.co_name,
-                co.co_firstlineno,
-                co.co_lnotab,
-                co.co_cellvars,  # this is the trickery
-                (),
-            )
-        else:
-            return types.CodeType(
-                co.co_argcount,
-                co.co_kwonlyargcount,
-                co.co_nlocals,
-                co.co_stacksize,
-                co.co_flags,
-                co.co_code,
-                co.co_consts,
-                co.co_names,
-                co.co_varnames,
-                co.co_filename,
-                co.co_name,
-                co.co_firstlineno,
-                co.co_lnotab,
-                co.co_cellvars,  # this is the trickery
-                (),
-            )
-
-_cell_set_template_code = _make_cell_set_template_code()
-
+        _cell_set_template_code = types.CodeType(
+            co.co_argcount,
+            co.co_kwonlyargcount,   # Python 3 only argument
+            co.co_nlocals,
+            co.co_stacksize,
+            co.co_flags,
+            co.co_code,
+            co.co_consts,
+            co.co_names,
+            co.co_varnames,
+            co.co_filename,
+            co.co_name,
+            co.co_firstlineno,
+            co.co_lnotab,
+            co.co_cellvars,  # co_freevars is initialized with co_cellvars
+            (),  # co_cellvars is made empty
+        )
+    return _cell_set_template_code
 
-def cell_set(cell, value):
-    """Set the value of a closure cell.
-    """
-    return types.FunctionType(
-        _cell_set_template_code,
-        {},
-        '_cell_set_inner',
-        (),
-        (cell,),
-    )(value)
 
+if sys.version_info[:2] < (3, 7):
+    _cell_set_template_code = _make_cell_set_template_code()
 
 # relevant opcodes
 STORE_GLOBAL = opcode.opmap['STORE_GLOBAL']
@@ -738,7 +747,9 @@
             'doc': func.__doc__,
             '_cloudpickle_submodules': submodules
         }
-        if hasattr(func, '__annotations__') and sys.version_info >= (3, 4):
+        if hasattr(func, '__annotations__') and sys.version_info >= (3, 7):
+            # Although annotations were added in Python3.4, It is not possible
+            # to properly pickle them until Python3.7. (See #193)
             state['annotations'] = func.__annotations__
         if hasattr(func, '__qualname__'):
             state['qualname'] = func.__qualname__
@@ -839,6 +850,11 @@
         method_descriptor = type(str.upper)
         dispatch[method_descriptor] = save_builtin_function_or_method
 
+    def save_getset_descriptor(self, obj):
+        return self.save_reduce(getattr, (obj.__objclass__, obj.__name__))
+
+    dispatch[types.GetSetDescriptorType] = save_getset_descriptor
+
     def save_global(self, obj, name=None, pack=struct.pack):
         """
         Save a "global".
@@ -873,8 +889,9 @@
             if PY3:  # pragma: no branch
                 self.save_reduce(types.MethodType, (obj.__func__, 
obj.__self__), obj=obj)
             else:
-                self.save_reduce(types.MethodType, (obj.__func__, 
obj.__self__, obj.__self__.__class__),
-                                 obj=obj)
+                self.save_reduce(
+                    types.MethodType,
+                    (obj.__func__, obj.__self__, type(obj.__self__)), obj=obj)
 
     dispatch[types.MethodType] = save_instancemethod
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/cloudpickle/cloudpickle_fast.py 
new/cloudpickle-1.2.2/cloudpickle/cloudpickle_fast.py
--- old/cloudpickle-1.2.1/cloudpickle/cloudpickle_fast.py       2019-06-07 
19:01:53.000000000 +0200
+++ new/cloudpickle-1.2.2/cloudpickle/cloudpickle_fast.py       2019-08-02 
21:50:49.000000000 +0200
@@ -260,6 +260,10 @@
     return _file_reconstructor, (retval,)
 
 
+def _getset_descriptor_reduce(obj):
+    return getattr, (obj.__objclass__, obj.__name__)
+
+
 def _mappingproxy_reduce(obj):
     return types.MappingProxyType, (dict(obj),)
 
@@ -405,6 +409,7 @@
     dispatch[staticmethod] = _classmethod_reduce
     dispatch[types.CellType] = _cell_reduce
     dispatch[types.CodeType] = _code_reduce
+    dispatch[types.GetSetDescriptorType] = _getset_descriptor_reduce
     dispatch[types.ModuleType] = _module_reduce
     dispatch[types.MethodType] = _method_reduce
     dispatch[types.MappingProxyType] = _mappingproxy_reduce
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/cloudpickle.egg-info/PKG-INFO 
new/cloudpickle-1.2.2/cloudpickle.egg-info/PKG-INFO
--- old/cloudpickle-1.2.1/cloudpickle.egg-info/PKG-INFO 2019-06-10 
21:56:01.000000000 +0200
+++ new/cloudpickle-1.2.2/cloudpickle.egg-info/PKG-INFO 2019-09-10 
14:27:06.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cloudpickle
-Version: 1.2.1
+Version: 1.2.2
 Summary: Extended pickling support for Python objects
 Home-page: https://github.com/cloudpipe/cloudpickle
 Author: Cloudpipe
@@ -23,11 +23,15 @@
         along with **functions and classes defined interactively** in the
         `__main__` module (for instance in a script, a shell or a Jupyter 
notebook).
         
-        **`cloudpickle` uses `pickle.HIGHEST_PROTOCOL` by default**: it is 
meant to
-        send objects between processes running the **same version of Python**.
+        Cloudpickle can only be used to send objects between the **exact same 
version
+        of Python**.
         
         Using `cloudpickle` for **long-term object storage is not supported and
-        discouraged.**
+        strongly discouraged.**
+        
+        **Security notice**: one should **only load pickle data from trusted 
sources** as
+        otherwise `pickle.load` can lead to arbitrary code execution resulting 
in a critical
+        security vulnerability.
         
         
         Installation
@@ -89,6 +93,25 @@
               PYTHONPATH='.:tests' py.test
         
         
+        Note about function Annotations
+        -------------------------------
+        
+        Note that because of design issues `Python`'s `typing` module, 
`cloudpickle`
+        supports pickling type annotations of dynamic functions for `Python` 
3.7 and
+        later.  On `Python` 3.4, 3.5 and 3.6, those type annotations will be 
dropped
+        silently during pickling (example below):
+        
+        ```python
+        >>> import typing
+        >>> import cloudpickle
+        >>> def f(x: typing.Union[list, int]):
+        ...     return x
+        >>> f
+        <function __main__.f(x:Union[list, int])>
+        >>> cloudpickle.loads(cloudpickle.dumps(f))  # drops f's annotations
+        <function __main__.f(x)>
+        ```
+        
         History
         -------
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cloudpickle-1.2.1/tests/cloudpickle_test.py 
new/cloudpickle-1.2.2/tests/cloudpickle_test.py
--- old/cloudpickle-1.2.1/tests/cloudpickle_test.py     2019-06-10 
21:54:13.000000000 +0200
+++ new/cloudpickle-1.2.2/tests/cloudpickle_test.py     2019-09-10 
14:19:13.000000000 +0200
@@ -431,6 +431,15 @@
         self.assertEqual(A.test_sm(), "sm")
         self.assertEqual(A.test_cm(), "cm")
 
+    def test_bound_classmethod(self):
+        class A:
+            @classmethod
+            def test_cm(cls):
+                return "cm"
+
+        A.test_cm = pickle_depickle(A.test_cm, protocol=self.protocol)
+        self.assertEqual(A.test_cm(), "cm")
+
     def test_method_descriptors(self):
         f = pickle_depickle(str.upper)
         self.assertEqual(f('abc'), 'ABC')
@@ -661,10 +670,9 @@
         # builtin function from the __builtin__ module
         assert pickle_depickle(zip, protocol=self.protocol) is zip
 
-        from sys import getcheckinterval
+        from os import mkdir
         # builtin function from a "regular" module
-        assert pickle_depickle(
-            getcheckinterval, protocol=self.protocol) is getcheckinterval
+        assert pickle_depickle(mkdir, protocol=self.protocol) is mkdir
 
     @pytest.mark.skipif(platform.python_implementation() == 'PyPy' and
                         sys.version_info[:2] == (3, 5),
@@ -975,6 +983,11 @@
         # logging.Logger object
         self.check_logger('cloudpickle.dummy_test_logger')
 
+    def test_getset_descriptor(self):
+        assert isinstance(float.real, types.GetSetDescriptorType)
+        depickled_descriptor = pickle_depickle(float.real)
+        self.assertIs(depickled_descriptor, float.real)
+
     def test_abc(self):
 
         @abc.abstractmethod
@@ -1607,9 +1620,9 @@
 
         self.assertEqual(f2.__doc__, f.__doc__)
 
-    @unittest.skipIf(sys.version_info < (3, 4),
-                     """This syntax won't work on py2 and pickling annotations
-                     isn't supported for py34 and below.""")
+    @unittest.skipIf(sys.version_info < (3, 7),
+                     "This syntax won't work on py2 and pickling annotations "
+                     "isn't supported for py37 and below.")
     def test_wraps_preserves_function_annotations(self):
         from functools import wraps
 
@@ -1626,6 +1639,16 @@
 
         self.assertEqual(f2.__annotations__, f.__annotations__)
 
+    @unittest.skipIf(sys.version_info < (3, 7),
+                     """This syntax won't work on py2 and pickling annotations
+                     isn't supported for py37 and below.""")
+    def test_type_hint(self):
+        # Try to pickle compound typing constructs. This would typically fail
+        # on Python < 3.7 (See #193)
+        import typing
+        t = typing.Union[list, int]
+        assert pickle_depickle(t) == t
+
     def test_instance_with_slots(self):
         for slots in [["registered_attribute"], "registered_attribute"]:
             class ClassWithSlots(object):


Reply via email to