From ca237594c6f72e6045989d9dbe363ebe9fb05941 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Wed, 17 Jul 2019 11:47:55 +0200 Subject: [PATCH 1/5] FIX revert annotations support for Python3.4->3.6 --- cloudpickle/cloudpickle.py | 4 +++- tests/cloudpickle_test.py | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index c92b2eac4..1d4c85cbe 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -747,7 +747,9 @@ def save_function_tuple(self, func): '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__ diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index ec1d089bb..37fcc2190 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1621,9 +1621,9 @@ def g(): self.assertEqual(f2.__doc__, f.__doc__) - @unittest.skipIf(sys.version_info < (3, 4), + @unittest.skipIf(sys.version_info < (3, 7), """This syntax won't work on py2 and pickling annotations - isn't supported for py34 and below.""") + isn't supported for py37 and below.""") def test_wraps_preserves_function_annotations(self): from functools import wraps @@ -1640,6 +1640,17 @@ def g(x): 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): From d6cc73b2c4ead6872eb6887a70369dcf9e23a08f Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Wed, 17 Jul 2019 11:48:18 +0200 Subject: [PATCH 2/5] DOC, MNT changelog and readme --- CHANGES.md | 6 ++++++ README.md | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 65f61d451..5eb9a3350 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,12 @@ 1.2.2 ===== +- Revert the change introduced in + ([issue #276](https://github.com/cloudpipe/cloudpickle/pull/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]( https://github.com/cloudpipe/cloudpickle/issues/193)) + - Fix a bug affecting bound classmethod saving on Python 2. ([issue #288](https://github.com/cloudpipe/cloudpickle/issues/288)) diff --git a/README.md b/README.md index 2eed9717e..f785eb701 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,23 @@ Running the tests PYTHONPATH='.:tests' py.test +Note about function Annotations +------------------------------- + +Note that because of design issues `Python`'s `typing` module, `cloudpickle` will +not pickle dynamic function annotations on `Python` 3.4, 3.5 and 3.6: + +```python +>>> import typing +>>> import cloudpickle +>>> def f(x: typing.Union[list, int]): +... return x +>>> f + +>>> cloudpickle.loads(cloudpickle.dumps(f)) # drops f's annotations + +``` + History ------- From eee91f2969f740fdf1a4c3b170bf8d37d1fc0d5d Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Wed, 17 Jul 2019 11:58:36 +0200 Subject: [PATCH 3/5] CLN spurious line --- tests/cloudpickle_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index 37fcc2190..c32b65fc8 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1650,7 +1650,6 @@ def test_type_hint(self): 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): From 27bbc23863741d0d1951dcfb218299db171b9589 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Mon, 2 Sep 2019 09:07:28 +0200 Subject: [PATCH 4/5] CI trigger From 27f73465023f0f074d847aca99fa6e1dcf96cdd4 Mon Sep 17 00:00:00 2001 From: Pierre Glaser Date: Mon, 9 Sep 2019 17:20:23 +0200 Subject: [PATCH 5/5] CLN address review comments --- README.md | 6 ++++-- tests/cloudpickle_test.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f785eb701..7c9e0dd48 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,10 @@ Running the tests Note about function Annotations ------------------------------- -Note that because of design issues `Python`'s `typing` module, `cloudpickle` will -not pickle dynamic function annotations on `Python` 3.4, 3.5 and 3.6: +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 diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index c32b65fc8..144635930 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -1622,8 +1622,8 @@ def g(): self.assertEqual(f2.__doc__, f.__doc__) @unittest.skipIf(sys.version_info < (3, 7), - """This syntax won't work on py2 and pickling annotations - isn't supported for py37 and below.""") + "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