Skip to content

Commit 7569c0f

Browse files
authored
bpo-44468: Never skip base classes in typing.get_type_hints(), even with invalid .__module__. (GH-26862)
1 parent 521ba88 commit 7569c0f

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

Lib/test/test_typing.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,13 +2277,6 @@ def test_no_isinstance(self):
22772277
with self.assertRaises(TypeError):
22782278
issubclass(int, ClassVar)
22792279

2280-
def test_bad_module(self):
2281-
# bpo-41515
2282-
class BadModule:
2283-
pass
2284-
BadModule.__module__ = 'bad' # Something not in sys.modules
2285-
self.assertEqual(get_type_hints(BadModule), {})
2286-
22872280
class FinalTests(BaseTestCase):
22882281

22892282
def test_basics(self):
@@ -3033,6 +3026,24 @@ class Foo:
30333026
# This previously raised an error under PEP 563.
30343027
self.assertEqual(get_type_hints(Foo), {'x': str})
30353028

3029+
def test_get_type_hints_bad_module(self):
3030+
# bpo-41515
3031+
class BadModule:
3032+
pass
3033+
BadModule.__module__ = 'bad' # Something not in sys.modules
3034+
self.assertNotIn('bad', sys.modules)
3035+
self.assertEqual(get_type_hints(BadModule), {})
3036+
3037+
def test_get_type_hints_annotated_bad_module(self):
3038+
# See https://bugs.python.org/issue44468
3039+
class BadBase:
3040+
foo: tuple
3041+
class BadType(BadBase):
3042+
bar: list
3043+
BadType.__module__ = BadBase.__module__ = 'bad'
3044+
self.assertNotIn('bad', sys.modules)
3045+
self.assertEqual(get_type_hints(BadType), {'foo': tuple, 'bar': list})
3046+
30363047

30373048
class GetUtilitiesTestCase(TestCase):
30383049
def test_get_origin(self):

Lib/typing.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,10 +1701,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
17011701
hints = {}
17021702
for base in reversed(obj.__mro__):
17031703
if globalns is None:
1704-
try:
1705-
base_globals = sys.modules[base.__module__].__dict__
1706-
except KeyError:
1707-
continue
1704+
base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
17081705
else:
17091706
base_globals = globalns
17101707
ann = base.__dict__.get('__annotations__', {})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`typing.get_type_hints` now finds annotations in classes and base classes
2+
with unexpected ``__module__``. Previously, it skipped those MRO elements.

0 commit comments

Comments
 (0)