Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8349403

Browse files
authored
bpo-32873: Treat type variables and special typing forms as immutable by copy and pickle (GH-6216)
This alsofixespython/typing#512This alsofixespython/typing#511As was discussed in both issues, some typing forms deserve to be treatedas immutable by copy and pickle modules, so that:* copy(X) is X* deepcopy(X) is X* loads(dumps(X)) is X # pickled by referenceThis PR adds such behaviour to:* Type variables* Special forms like Union, Any, ClassVar* Unsubscripted generic aliases to containers like List, Mapping, IterableThis not only resolves inconsistencies mentioned in the issues, but alsoimproves 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
1 parent0e7144b commit8349403

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

‎Lib/test/test_typing.py‎

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,20 +1057,20 @@ class C(B[int]):
10571057
self.assertEqual(x.foo,42)
10581058
self.assertEqual(x.bar,'abc')
10591059
self.assertEqual(x.__dict__, {'foo':42,'bar':'abc'})
1060-
samples= [Any,Union,Tuple,Callable,ClassVar]
1060+
samples= [Any,Union,Tuple,Callable,ClassVar,
1061+
Union[int,str],ClassVar[List],Tuple[int, ...],Callable[[str],bytes]]
10611062
forsinsamples:
10621063
forprotoinrange(pickle.HIGHEST_PROTOCOL+1):
10631064
z=pickle.dumps(s,proto)
10641065
x=pickle.loads(z)
10651066
self.assertEqual(s,x)
1066-
more_samples= [List,typing.Iterable,typing.Type]
1067+
more_samples= [List,typing.Iterable,typing.Type,List[int],
1068+
typing.Type[typing.Mapping]]
10671069
forsinmore_samples:
10681070
forprotoinrange(pickle.HIGHEST_PROTOCOL+1):
10691071
z=pickle.dumps(s,proto)
10701072
x=pickle.loads(z)
1071-
self.assertEqual(repr(s),repr(x))# TODO: fix this
1072-
# see also comment in test_copy_and_deepcopy
1073-
# the issue is typing/#512
1073+
self.assertEqual(s,x)
10741074

10751075
deftest_copy_and_deepcopy(self):
10761076
T=TypeVar('T')
@@ -1082,7 +1082,27 @@ class Node(Generic[T]): ...
10821082
Union['T',int],List['T'],typing.Mapping['T',int]]
10831083
fortinthings+ [Any]:
10841084
self.assertEqual(t,copy(t))
1085-
self.assertEqual(repr(t),repr(deepcopy(t)))# Use repr() because of TypeVars
1085+
self.assertEqual(t,deepcopy(t))
1086+
1087+
deftest_immutability_by_copy_and_pickle(self):
1088+
# Special forms like Union, Any, etc., generic aliases to containers like List,
1089+
# Mapping, etc., and type variabcles are considered immutable by copy and pickle.
1090+
globalTP,TPB,TPV# for pickle
1091+
TP=TypeVar('TP')
1092+
TPB=TypeVar('TPB',bound=int)
1093+
TPV=TypeVar('TPV',bytes,str)
1094+
forXin [TP,TPB,TPV,List,typing.Mapping,ClassVar,typing.Iterable,
1095+
Union,Any,Tuple,Callable]:
1096+
self.assertIs(copy(X),X)
1097+
self.assertIs(deepcopy(X),X)
1098+
self.assertIs(pickle.loads(pickle.dumps(X)),X)
1099+
# Check that local type variables are copyable.
1100+
TL=TypeVar('TL')
1101+
TLB=TypeVar('TLB',bound=int)
1102+
TLV=TypeVar('TLV',bytes,str)
1103+
forXin [TL,TLB,TLV]:
1104+
self.assertIs(copy(X),X)
1105+
self.assertIs(deepcopy(X),X)
10861106

10871107
deftest_copy_generic_instances(self):
10881108
T=TypeVar('T')

‎Lib/typing.py‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,17 @@ def __init_subclass__(self, *args, **kwds):
285285
if'_root'notinkwds:
286286
raiseTypeError("Cannot subclass special typing classes")
287287

288+
class_Immutable:
289+
"""Mixin to indicate that object should not be copied."""
288290

289-
class_SpecialForm(_Final,_root=True):
291+
def__copy__(self):
292+
returnself
293+
294+
def__deepcopy__(self,memo):
295+
returnself
296+
297+
298+
class_SpecialForm(_Final,_Immutable,_root=True):
290299
"""Internal indicator of special typing constructs.
291300
See _doc instance attribute for specific docs.
292301
"""
@@ -328,8 +337,8 @@ def __hash__(self):
328337
def__repr__(self):
329338
return'typing.'+self._name
330339

331-
def__copy__(self):
332-
returnself# Special forms are immutable.
340+
def__reduce__(self):
341+
returnself._name
333342

334343
def__call__(self,*args,**kwds):
335344
raiseTypeError(f"Cannot instantiate{self!r}")
@@ -496,7 +505,11 @@ def __repr__(self):
496505
returnf'ForwardRef({self.__forward_arg__!r})'
497506

498507

499-
classTypeVar(_Final,_root=True):
508+
def_find_name(mod,name):
509+
returngetattr(sys.modules[mod],name)
510+
511+
512+
classTypeVar(_Final,_Immutable,_root=True):
500513
"""Type variable.
501514
502515
Usage::
@@ -536,10 +549,12 @@ def longest(x: A, y: A) -> A:
536549
T.__covariant__ == False
537550
T.__contravariant__ = False
538551
A.__constraints__ == (str, bytes)
552+
553+
Note that only type variables defined in global scope can be pickled.
539554
"""
540555

541556
__slots__= ('__name__','__bound__','__constraints__',
542-
'__covariant__','__contravariant__')
557+
'__covariant__','__contravariant__','_def_mod')
543558

544559
def__init__(self,name,*constraints,bound=None,
545560
covariant=False,contravariant=False):
@@ -558,6 +573,7 @@ def __init__(self, name, *constraints, bound=None,
558573
self.__bound__=_type_check(bound,"Bound must be a type.")
559574
else:
560575
self.__bound__=None
576+
self._def_mod=sys._getframe(1).f_globals['__name__']# for pickling
561577

562578
def__getstate__(self):
563579
return {'name':self.__name__,
@@ -582,6 +598,9 @@ def __repr__(self):
582598
prefix='~'
583599
returnprefix+self.__name__
584600

601+
def__reduce__(self):
602+
return (_find_name, (self._def_mod,self.__name__))
603+
585604

586605
# Special typing constructs Union, Optional, Generic, Callable and Tuple
587606
# use three special attributes for internal bookkeeping of generic types:
@@ -724,6 +743,11 @@ def __subclasscheck__(self, cls):
724743
raiseTypeError("Subscripted generics cannot be used with"
725744
" class and instance checks")
726745

746+
def__reduce__(self):
747+
ifself._special:
748+
returnself._name
749+
returnsuper().__reduce__()
750+
727751

728752
class_VariadicGenericAlias(_GenericAlias,_root=True):
729753
"""Same as _GenericAlias above but for variadic aliases. Currently,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Treat type variables and special typing forms as immutable by copy and
2+
pickle. This fixes several minor issues and inconsistencies, and improves
3+
backwards compatibility with Python 3.6.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2026 Movatter.jp