diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 4cba606dd8dd4d..a8c1af6f6ec4f0 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1530,7 +1530,11 @@ class C(Base): for item in fields: if isinstance(item, str): name = item - tp = 'typing.Any' + typing = sys.modules.get('typing') + if typing: + tp = typing.Any + else: + tp = "__import__('typing').Any" elif len(item) == 2: name, tp, = item elif len(item) == 3: diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index b93c99d8c90bf3..9c06058260eebd 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -13,6 +13,7 @@ import weakref import traceback import unittest +import sys from unittest.mock import Mock from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict from typing import get_type_hints @@ -23,6 +24,7 @@ import dataclasses # Needed for the string "dataclasses.InitVar[int]" to work as an annotation. from test import support +from test.support import import_helper # Just any custom exception we can catch. class CustomError(Exception): pass @@ -4108,16 +4110,30 @@ def test_no_types(self): C = make_dataclass('Point', ['x', 'y', 'z']) c = C(1, 2, 3) self.assertEqual(vars(c), {'x': 1, 'y': 2, 'z': 3}) - self.assertEqual(C.__annotations__, {'x': 'typing.Any', - 'y': 'typing.Any', - 'z': 'typing.Any'}) + self.assertEqual(C.__annotations__, {'x': typing.Any, + 'y': typing.Any, + 'z': typing.Any}) C = make_dataclass('Point', ['x', ('y', int), 'z']) c = C(1, 2, 3) self.assertEqual(vars(c), {'x': 1, 'y': 2, 'z': 3}) - self.assertEqual(C.__annotations__, {'x': 'typing.Any', + self.assertEqual(C.__annotations__, {'x': typing.Any, 'y': int, - 'z': 'typing.Any'}) + 'z': typing.Any}) + + def test_no_types_no_NameError(self): + C = make_dataclass('Point', ['x']) + self.assertEqual(C.__annotations__, {'x': typing.Any}) + self.assertEqual(get_type_hints(C), {'x': typing.Any}) + + def test_no_types_no_NameError_no_typing_fallback(self): + with import_helper.isolated_modules(): + del sys.modules['typing'] + C = make_dataclass('Point', ['x']) + self.assertEqual(C.__annotations__, + {'x': "__import__('typing').Any"}) + from typing import Any # since we hack our modules + self.assertEqual(get_type_hints(C), {'x': Any}) def test_module_attr(self): self.assertEqual(ByMakeDataClass.__module__, __name__) diff --git a/Misc/NEWS.d/next/Library/2024-07-24-15-47-11.gh-issue-82129.7z5g8K.rst b/Misc/NEWS.d/next/Library/2024-07-24-15-47-11.gh-issue-82129.7z5g8K.rst new file mode 100644 index 00000000000000..4ba6c79994911c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-24-15-47-11.gh-issue-82129.7z5g8K.rst @@ -0,0 +1,3 @@ +Fix name error in :func:`typing.get_type_hints` when calling it in a +dataclass created without an annotation via +:func:`dataclasses.make_dataclass` function.