Skip to content

Commit 246577d

Browse files
committed
Fix test_dataclassess
1 parent bbf01bb commit 246577d

File tree

7 files changed

+38
-140
lines changed

7 files changed

+38
-140
lines changed

Lib/dataclasses.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,10 @@ def _create_fn(name, args, body, *, globals=None, locals=None,
398398

399399
ns = {}
400400
exec(txt, globals, ns)
401-
return ns['__create_fn__'](**locals)
402-
401+
func = ns['__create_fn__'](**locals)
402+
for arg, annotation in func.__annotations__.copy().items():
403+
func.__annotations__[arg] = locals[annotation]
404+
return func
403405

404406
def _field_assign(frozen, name, value, self_name):
405407
# If we're a frozen class, then assign to our fields in __init__

Lib/test/dataclass_module_1.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
#from __future__ import annotations
2-
USING_STRINGS = False
3-
4-
# dataclass_module_1.py and dataclass_module_1_str.py are identical
5-
# except only the latter uses string annotations.
6-
71
import dataclasses
82
import typing
93

Lib/test/dataclass_module_1_str.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

Lib/test/dataclass_module_2.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
#from __future__ import annotations
2-
USING_STRINGS = False
3-
4-
# dataclass_module_2.py and dataclass_module_2_str.py are identical
5-
# except only the latter uses string annotations.
6-
71
from dataclasses import dataclass, InitVar
82
from typing import ClassVar
93

Lib/test/dataclass_module_2_str.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

Lib/test/dataclass_textanno.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from __future__ import annotations
2-
31
import dataclasses
42

53

Lib/test/test_dataclasses.py

Lines changed: 34 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import inspect
99
import builtins
1010
import unittest
11+
from textwrap import dedent
1112
from unittest.mock import Mock
1213
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
1314
from typing import get_type_hints
@@ -561,17 +562,17 @@ class C:
561562
self.assertEqual(len(the_fields), 3)
562563

563564
self.assertEqual(the_fields[0].name, 'x')
564-
self.assertEqual(the_fields[0].type, int)
565+
self.assertEqual(the_fields[0].type, 'int')
565566
self.assertFalse(hasattr(C, 'x'))
566567
self.assertTrue (the_fields[0].init)
567568
self.assertTrue (the_fields[0].repr)
568569
self.assertEqual(the_fields[1].name, 'y')
569-
self.assertEqual(the_fields[1].type, str)
570+
self.assertEqual(the_fields[1].type, 'str')
570571
self.assertIsNone(getattr(C, 'y'))
571572
self.assertFalse(the_fields[1].init)
572573
self.assertTrue (the_fields[1].repr)
573574
self.assertEqual(the_fields[2].name, 'z')
574-
self.assertEqual(the_fields[2].type, str)
575+
self.assertEqual(the_fields[2].type, 'str')
575576
self.assertFalse(hasattr(C, 'z'))
576577
self.assertTrue (the_fields[2].init)
577578
self.assertFalse(the_fields[2].repr)
@@ -757,11 +758,11 @@ class F:
757758
def validate_class(cls):
758759
# First, check __annotations__, even though they're not
759760
# function annotations.
760-
self.assertEqual(cls.__annotations__['i'], int)
761-
self.assertEqual(cls.__annotations__['j'], str)
762-
self.assertEqual(cls.__annotations__['k'], F)
763-
self.assertEqual(cls.__annotations__['l'], float)
764-
self.assertEqual(cls.__annotations__['z'], complex)
761+
self.assertEqual(cls.__annotations__['i'], 'int')
762+
self.assertEqual(cls.__annotations__['j'], 'str')
763+
self.assertEqual(cls.__annotations__['k'], 'F')
764+
self.assertEqual(cls.__annotations__['l'], 'float')
765+
self.assertEqual(cls.__annotations__['z'], 'complex')
765766

766767
# Verify __init__.
767768

@@ -776,22 +777,22 @@ def validate_class(cls):
776777
self.assertEqual(param.name, 'self')
777778
param = next(params)
778779
self.assertEqual(param.name, 'i')
779-
self.assertIs (param.annotation, int)
780+
self.assertIs (param.annotation, 'int')
780781
self.assertEqual(param.default, inspect.Parameter.empty)
781782
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
782783
param = next(params)
783784
self.assertEqual(param.name, 'j')
784-
self.assertIs (param.annotation, str)
785+
self.assertIs (param.annotation, 'str')
785786
self.assertEqual(param.default, inspect.Parameter.empty)
786787
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
787788
param = next(params)
788789
self.assertEqual(param.name, 'k')
789-
self.assertIs (param.annotation, F)
790+
self.assertIs (param.annotation, 'F')
790791
# Don't test for the default, since it's set to MISSING.
791792
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
792793
param = next(params)
793794
self.assertEqual(param.name, 'l')
794-
self.assertIs (param.annotation, float)
795+
self.assertIs (param.annotation, 'float')
795796
# Don't test for the default, since it's set to MISSING.
796797
self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_OR_KEYWORD)
797798
self.assertRaises(StopIteration, next, params)
@@ -1997,15 +1998,15 @@ def test_docstring_one_field(self):
19971998
class C:
19981999
x: int
19992000

2000-
self.assertDocStrEqual(C.__doc__, "C(x:int)")
2001+
self.assertDocStrEqual(C.__doc__, "C(x:'int')")
20012002

20022003
def test_docstring_two_fields(self):
20032004
@dataclass
20042005
class C:
20052006
x: int
20062007
y: int
20072008

2008-
self.assertDocStrEqual(C.__doc__, "C(x:int, y:int)")
2009+
self.assertDocStrEqual(C.__doc__, "C(x:'int', y:'int')")
20092010

20102011
def test_docstring_three_fields(self):
20112012
@dataclass
@@ -2014,49 +2015,49 @@ class C:
20142015
y: int
20152016
z: str
20162017

2017-
self.assertDocStrEqual(C.__doc__, "C(x:int, y:int, z:str)")
2018+
self.assertDocStrEqual(C.__doc__, "C(x:'int', y:'int', z:'str')")
20182019

20192020
def test_docstring_one_field_with_default(self):
20202021
@dataclass
20212022
class C:
20222023
x: int = 3
20232024

2024-
self.assertDocStrEqual(C.__doc__, "C(x:int=3)")
2025+
self.assertDocStrEqual(C.__doc__, "C(x:'int'=3)")
20252026

20262027
def test_docstring_one_field_with_default_none(self):
20272028
@dataclass
20282029
class C:
20292030
x: Union[int, type(None)] = None
20302031

2031-
self.assertDocStrEqual(C.__doc__, "C(x:Optional[int]=None)")
2032+
self.assertDocStrEqual(C.__doc__, "C(x:'Union[int, type(None)]'=None)")
20322033

20332034
def test_docstring_list_field(self):
20342035
@dataclass
20352036
class C:
20362037
x: List[int]
20372038

2038-
self.assertDocStrEqual(C.__doc__, "C(x:List[int])")
2039+
self.assertDocStrEqual(C.__doc__, "C(x:'List[int]')")
20392040

20402041
def test_docstring_list_field_with_default_factory(self):
20412042
@dataclass
20422043
class C:
20432044
x: List[int] = field(default_factory=list)
20442045

2045-
self.assertDocStrEqual(C.__doc__, "C(x:List[int]=<factory>)")
2046+
self.assertDocStrEqual(C.__doc__, "C(x:'List[int]'=<factory>)")
20462047

20472048
def test_docstring_deque_field(self):
20482049
@dataclass
20492050
class C:
20502051
x: deque
20512052

2052-
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque)")
2053+
self.assertDocStrEqual(C.__doc__, "C(x:'deque')")
20532054

20542055
def test_docstring_deque_field_with_default_factory(self):
20552056
@dataclass
20562057
class C:
20572058
x: deque = field(default_factory=deque)
20582059

2059-
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=<factory>)")
2060+
self.assertDocStrEqual(C.__doc__, "C(x:'deque'=<factory>)")
20602061

20612062

20622063
class TestInit(unittest.TestCase):
@@ -2805,13 +2806,10 @@ class C:
28052806

28062807
class TestStringAnnotations(unittest.TestCase):
28072808
def test_classvar(self):
2808-
# Some expressions recognized as ClassVar really aren't. But
2809-
# if you're using string annotations, it's not an exact
2810-
# science.
28112809
# These tests assume that both "import typing" and "from
28122810
# typing import *" have been run in this file.
28132811
for typestr in ('ClassVar[int]',
2814-
'ClassVar [int]'
2812+
'ClassVar [int]',
28152813
' ClassVar [int]',
28162814
'ClassVar',
28172815
' ClassVar ',
@@ -2822,17 +2820,9 @@ def test_classvar(self):
28222820
'typing. ClassVar[str]',
28232821
'typing.ClassVar [str]',
28242822
'typing.ClassVar [ str]',
2825-
2826-
# Not syntactically valid, but these will
2827-
# be treated as ClassVars.
2828-
'typing.ClassVar.[int]',
2829-
'typing.ClassVar+',
28302823
):
28312824
with self.subTest(typestr=typestr):
2832-
@dataclass
2833-
class C:
2834-
x: typestr
2835-
2825+
C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
28362826
# x is a ClassVar, so C() takes no args.
28372827
C()
28382828

@@ -2853,9 +2843,7 @@ def test_isnt_classvar(self):
28532843
'typingxClassVar[str]',
28542844
):
28552845
with self.subTest(typestr=typestr):
2856-
@dataclass
2857-
class C:
2858-
x: typestr
2846+
C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
28592847

28602848
# x is not a ClassVar, so C() takes one arg.
28612849
self.assertEqual(C(10).x, 10)
@@ -2882,9 +2870,8 @@ def test_initvar(self):
28822870
'dataclasses.InitVar+',
28832871
):
28842872
with self.subTest(typestr=typestr):
2885-
@dataclass
2886-
class C:
2887-
x: typestr
2873+
C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
2874+
28882875

28892876
# x is an InitVar, so doesn't create a member.
28902877
with self.assertRaisesRegex(AttributeError,
@@ -2898,30 +2885,22 @@ def test_isnt_initvar(self):
28982885
'typing.xInitVar[int]',
28992886
):
29002887
with self.subTest(typestr=typestr):
2901-
@dataclass
2902-
class C:
2903-
x: typestr
2888+
C = dataclass(type("C", (), {"__annotations__": {"x": typestr}}))
29042889

29052890
# x is not an InitVar, so there will be a member x.
29062891
self.assertEqual(C(10).x, 10)
29072892

29082893
def test_classvar_module_level_import(self):
29092894
from test import dataclass_module_1
2910-
from test import dataclass_module_1_str
29112895
from test import dataclass_module_2
2912-
from test import dataclass_module_2_str
29132896

2914-
for m in (dataclass_module_1, dataclass_module_1_str,
2915-
dataclass_module_2, dataclass_module_2_str,
2916-
):
2897+
for m in (dataclass_module_1,
2898+
dataclass_module_2):
29172899
with self.subTest(m=m):
29182900
# There's a difference in how the ClassVars are
29192901
# interpreted when using string annotations or
29202902
# not. See the imported modules for details.
2921-
if m.USING_STRINGS:
2922-
c = m.CV(10)
2923-
else:
2924-
c = m.CV()
2903+
c = m.CV(10)
29252904
self.assertEqual(c.cv0, 20)
29262905

29272906

@@ -2937,14 +2916,9 @@ def test_classvar_module_level_import(self):
29372916
# not an instance field.
29382917
getattr(c, field_name)
29392918

2940-
if m.USING_STRINGS:
2941-
# iv4 is interpreted as a normal field.
2942-
self.assertIn('not_iv4', c.__dict__)
2943-
self.assertEqual(c.not_iv4, 4)
2944-
else:
2945-
# iv4 is interpreted as an InitVar, so it
2946-
# won't exist on the instance.
2947-
self.assertNotIn('not_iv4', c.__dict__)
2919+
# iv4 is interpreted as a normal field.
2920+
self.assertIn('not_iv4', c.__dict__)
2921+
self.assertEqual(c.not_iv4, 4)
29482922

29492923
def test_text_annotations(self):
29502924
from test import dataclass_textanno

0 commit comments

Comments
 (0)