Skip to content

Commit 89b688a

Browse files
committed
gh-135368: Fix mocks on dataclass specs with instance=True
1 parent d447129 commit 89b688a

3 files changed

Lines changed: 28 additions & 1 deletion

File tree

Lib/test/test_unittest/testmock/testhelpers.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ def __post_init__(self):
10501050
create_autospec(WithPostInit()),
10511051
]:
10521052
with self.subTest(mock=mock):
1053+
self.assertIsInstance(mock, WithPostInit)
10531054
self.assertIsInstance(mock.a, int)
10541055
self.assertIsInstance(mock.b, int)
10551056

@@ -1072,6 +1073,7 @@ class WithDefault:
10721073
create_autospec(WithDefault(1)),
10731074
]:
10741075
with self.subTest(mock=mock):
1076+
self.assertIsInstance(mock, WithDefault)
10751077
self.assertIsInstance(mock.a, int)
10761078
self.assertIsInstance(mock.b, int)
10771079

@@ -1087,6 +1089,7 @@ def b(self) -> int:
10871089
create_autospec(WithMethod(1)),
10881090
]:
10891091
with self.subTest(mock=mock):
1092+
self.assertIsInstance(mock, WithMethod)
10901093
self.assertIsInstance(mock.a, int)
10911094
mock.b.assert_not_called()
10921095

@@ -1102,11 +1105,27 @@ class WithNonFields:
11021105
create_autospec(WithNonFields(1)),
11031106
]:
11041107
with self.subTest(mock=mock):
1108+
self.assertIsInstance(mock, WithNonFields)
11051109
with self.assertRaisesRegex(AttributeError, msg):
11061110
mock.a
11071111
with self.assertRaisesRegex(AttributeError, msg):
11081112
mock.b
11091113

1114+
def test_dataclass_special_attrs(self):
1115+
@dataclass
1116+
class Description:
1117+
name: str
1118+
1119+
for mock in [
1120+
create_autospec(Description, instance=True),
1121+
create_autospec(Description(1)),
1122+
]:
1123+
with self.subTest(mock=mock):
1124+
self.assertIsInstance(mock, Description)
1125+
self.assertIs(mock.__class__, Description)
1126+
self.assertIsInstance(mock.__dataclass_fields__, MagicMock)
1127+
self.assertIsInstance(mock.__dataclass_params__, MagicMock)
1128+
11101129
class TestCallList(unittest.TestCase):
11111130

11121131
def test_args_list_contains_call_list(self):

Lib/unittest/mock.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2771,9 +2771,13 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
27712771
if is_type and instance and is_dataclass(spec):
27722772
dataclass_fields = fields(spec)
27732773
entries.extend((f.name, f.type) for f in dataclass_fields)
2774-
_kwargs = {'spec': [f.name for f in dataclass_fields]}
2774+
spec_list = [f.name for f in dataclass_fields]
2775+
spec_list.extend(['__dataclass_fields__', '__dataclass_params__'])
2776+
_kwargs = {'spec': spec_list} # we set `__class__` further
2777+
is_dataclass_spec = True
27752778
else:
27762779
_kwargs = {'spec': spec}
2780+
is_dataclass_spec = False
27772781

27782782
if spec_set:
27792783
_kwargs = {'spec_set': spec}
@@ -2810,6 +2814,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28102814

28112815
mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
28122816
name=_name, **_kwargs)
2817+
if is_dataclass_spec:
2818+
mock.__class__ = spec # we need this for `isinstance` to work
28132819

28142820
if isinstance(spec, FunctionTypes):
28152821
# should only happen at the top level because we don't
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :class:`unittest.mock.Mock` generation on :func:`dataclasses.dataclass`
2+
objects. Now all special attributes are set as it was before :gh:`124429`.

0 commit comments

Comments
 (0)