diff options
author | Ivan Levkivskyi <levkivskyi@gmail.com> | 2018-03-26 22:01:12 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-26 22:01:12 (GMT) |
commit | 834940375ae88bc95794226dd8eff1f25fba1cf9 (patch) | |
tree | 5a14eb4adb449c670e322463c9c690b4ac3f727b /Lib/test/test_typing.py | |
parent | 0e7144b064a19493a146af94175a087b3888c37b (diff) | |
download | cpython-834940375ae88bc95794226dd8eff1f25fba1cf9.zip cpython-834940375ae88bc95794226dd8eff1f25fba1cf9.tar.gz cpython-834940375ae88bc95794226dd8eff1f25fba1cf9.tar.bz2 |
bpo-32873: Treat type variables and special typing forms as immutable by copy and pickle (GH-6216)
This also fixes python/typing#512
This also fixes python/typing#511
As was discussed in both issues, some typing forms deserve to be treated
as immutable by copy and pickle modules, so that:
* copy(X) is X
* deepcopy(X) is X
* loads(dumps(X)) is X # pickled by reference
This PR adds such behaviour to:
* Type variables
* Special forms like Union, Any, ClassVar
* Unsubscripted generic aliases to containers like List, Mapping, Iterable
This not only resolves inconsistencies mentioned in the issues, but also
improves backwards compatibility with previous versions of Python
(including 3.6).
Note that this requires some dances with __module__ for type variables
(similar to NamedTuple) because the class TypeVar itself is define in typing,
while type variables should get module where they were defined.
https://bugs.python.org/issue32873
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r-- | Lib/test/test_typing.py | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f56caa1..09e39fe 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1057,20 +1057,20 @@ class GenericTests(BaseTestCase): self.assertEqual(x.foo, 42) self.assertEqual(x.bar, 'abc') self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) - samples = [Any, Union, Tuple, Callable, ClassVar] + samples = [Any, Union, Tuple, Callable, ClassVar, + Union[int, str], ClassVar[List], Tuple[int, ...], Callable[[str], bytes]] for s in samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) x = pickle.loads(z) self.assertEqual(s, x) - more_samples = [List, typing.Iterable, typing.Type] + more_samples = [List, typing.Iterable, typing.Type, List[int], + typing.Type[typing.Mapping]] for s in more_samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): z = pickle.dumps(s, proto) x = pickle.loads(z) - self.assertEqual(repr(s), repr(x)) # TODO: fix this - # see also comment in test_copy_and_deepcopy - # the issue is typing/#512 + self.assertEqual(s, x) def test_copy_and_deepcopy(self): T = TypeVar('T') @@ -1082,7 +1082,27 @@ class GenericTests(BaseTestCase): Union['T', int], List['T'], typing.Mapping['T', int]] for t in things + [Any]: self.assertEqual(t, copy(t)) - self.assertEqual(repr(t), repr(deepcopy(t))) # Use repr() because of TypeVars + self.assertEqual(t, deepcopy(t)) + + def test_immutability_by_copy_and_pickle(self): + # Special forms like Union, Any, etc., generic aliases to containers like List, + # Mapping, etc., and type variabcles are considered immutable by copy and pickle. + global TP, TPB, TPV # for pickle + TP = TypeVar('TP') + TPB = TypeVar('TPB', bound=int) + TPV = TypeVar('TPV', bytes, str) + for X in [TP, TPB, TPV, List, typing.Mapping, ClassVar, typing.Iterable, + Union, Any, Tuple, Callable]: + self.assertIs(copy(X), X) + self.assertIs(deepcopy(X), X) + self.assertIs(pickle.loads(pickle.dumps(X)), X) + # Check that local type variables are copyable. + TL = TypeVar('TL') + TLB = TypeVar('TLB', bound=int) + TLV = TypeVar('TLV', bytes, str) + for X in [TL, TLB, TLV]: + self.assertIs(copy(X), X) + self.assertIs(deepcopy(X), X) def test_copy_generic_instances(self): T = TypeVar('T') |