Skip to content

Commit 908ac8f

Browse files
Fix misdetection of some 3.6 typing[_extensions] (#409)
Co-authored-by: Olivier Grisel <[email protected]>
1 parent fd596d2 commit 908ac8f

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

Diff for: CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ dev
88
https://www.python.org/dev/peps/pep-0563/
99
([PR #400](https://github.com/cloudpipe/cloudpickle/pull/400))
1010

11+
- Stricter parametrized type detection heuristics in
12+
_is_parametrized_type_hint to limit false positives.
13+
([PR #409](https://github.com/cloudpipe/cloudpickle/pull/409))
14+
1115
1.6.0
1216
=====
1317

Diff for: cloudpickle/cloudpickle.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -455,15 +455,31 @@ def _extract_class_dict(cls):
455455

456456
if sys.version_info[:2] < (3, 7): # pragma: no branch
457457
def _is_parametrized_type_hint(obj):
458-
# This is very cheap but might generate false positives.
458+
# This is very cheap but might generate false positives. So try to
459+
# narrow it down is good as possible.
460+
type_module = getattr(type(obj), '__module__', None)
461+
from_typing_extensions = type_module == 'typing_extensions'
462+
from_typing = type_module == 'typing'
463+
459464
# general typing Constructs
460465
is_typing = getattr(obj, '__origin__', None) is not None
461466

462467
# typing_extensions.Literal
463-
is_literal = getattr(obj, '__values__', None) is not None
468+
is_literal = (
469+
(getattr(obj, '__values__', None) is not None)
470+
and from_typing_extensions
471+
)
464472

465473
# typing_extensions.Final
466-
is_final = getattr(obj, '__type__', None) is not None
474+
is_final = (
475+
(getattr(obj, '__type__', None) is not None)
476+
and from_typing_extensions
477+
)
478+
479+
# typing.ClassVar
480+
is_classvar = (
481+
(getattr(obj, '__type__', None) is not None) and from_typing
482+
)
467483

468484
# typing.Union/Tuple for old Python 3.5
469485
is_union = getattr(obj, '__union_params__', None) is not None
@@ -472,8 +488,8 @@ def _is_parametrized_type_hint(obj):
472488
getattr(obj, '__result__', None) is not None and
473489
getattr(obj, '__args__', None) is not None
474490
)
475-
return any((is_typing, is_literal, is_final, is_union, is_tuple,
476-
is_callable))
491+
return any((is_typing, is_literal, is_final, is_classvar, is_union,
492+
is_tuple, is_callable))
477493

478494
def _create_parametrized_type_hint(origin, args):
479495
return origin[args]

Diff for: tests/cloudpickle_test.py

+20
Original file line numberDiff line numberDiff line change
@@ -2301,6 +2301,26 @@ def reduce_myclass(x):
23012301
finally:
23022302
copyreg.dispatch_table.pop(MyClass)
23032303

2304+
def test_literal_misdetection(self):
2305+
# see https://github.com/cloudpipe/cloudpickle/issues/403
2306+
class MyClass:
2307+
@property
2308+
def __values__(self):
2309+
return ()
2310+
2311+
o = MyClass()
2312+
pickle_depickle(o, protocol=self.protocol)
2313+
2314+
def test_final_or_classvar_misdetection(self):
2315+
# see https://github.com/cloudpipe/cloudpickle/issues/403
2316+
class MyClass:
2317+
@property
2318+
def __type__(self):
2319+
return int
2320+
2321+
o = MyClass()
2322+
pickle_depickle(o, protocol=self.protocol)
2323+
23042324

23052325
class Protocol2CloudPickleTest(CloudPickleTest):
23062326

0 commit comments

Comments
 (0)