Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3a0e7f5

Browse files
authored
gh-124176: Add special support for dataclasses tocreate_autospec (#124429)
1 parent08e1bbe commit3a0e7f5

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

‎Lib/test/test_unittest/testmock/testhelpers.py‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
Mock,ANY,_CallList,patch,PropertyMock,_callable
99
)
1010

11+
fromdataclassesimportdataclass,field,InitVar
1112
fromdatetimeimportdatetime
1213
fromfunctoolsimportpartial
14+
fromtypingimportClassVar
1315

1416
classSomeClass(object):
1517
defone(self,a,b):pass
@@ -1034,6 +1036,76 @@ def f(a): pass
10341036
self.assertEqual(mock.mock_calls, [])
10351037
self.assertEqual(rv.mock_calls, [])
10361038

1039+
deftest_dataclass_post_init(self):
1040+
@dataclass
1041+
classWithPostInit:
1042+
a:int=field(init=False)
1043+
b:int=field(init=False)
1044+
def__post_init__(self):
1045+
self.a=1
1046+
self.b=2
1047+
1048+
formockin [
1049+
create_autospec(WithPostInit,instance=True),
1050+
create_autospec(WithPostInit()),
1051+
]:
1052+
withself.subTest(mock=mock):
1053+
self.assertIsInstance(mock.a,int)
1054+
self.assertIsInstance(mock.b,int)
1055+
1056+
# Classes do not have these fields:
1057+
mock=create_autospec(WithPostInit)
1058+
msg="Mock object has no attribute"
1059+
withself.assertRaisesRegex(AttributeError,msg):
1060+
mock.a
1061+
withself.assertRaisesRegex(AttributeError,msg):
1062+
mock.b
1063+
1064+
deftest_dataclass_default(self):
1065+
@dataclass
1066+
classWithDefault:
1067+
a:int
1068+
b:int=0
1069+
1070+
formockin [
1071+
create_autospec(WithDefault,instance=True),
1072+
create_autospec(WithDefault(1)),
1073+
]:
1074+
withself.subTest(mock=mock):
1075+
self.assertIsInstance(mock.a,int)
1076+
self.assertIsInstance(mock.b,int)
1077+
1078+
deftest_dataclass_with_method(self):
1079+
@dataclass
1080+
classWithMethod:
1081+
a:int
1082+
defb(self)->int:
1083+
return1
1084+
1085+
formockin [
1086+
create_autospec(WithMethod,instance=True),
1087+
create_autospec(WithMethod(1)),
1088+
]:
1089+
withself.subTest(mock=mock):
1090+
self.assertIsInstance(mock.a,int)
1091+
mock.b.assert_not_called()
1092+
1093+
deftest_dataclass_with_non_fields(self):
1094+
@dataclass
1095+
classWithNonFields:
1096+
a:ClassVar[int]
1097+
b:InitVar[int]
1098+
1099+
msg="Mock object has no attribute"
1100+
formockin [
1101+
create_autospec(WithNonFields,instance=True),
1102+
create_autospec(WithNonFields(1)),
1103+
]:
1104+
withself.subTest(mock=mock):
1105+
withself.assertRaisesRegex(AttributeError,msg):
1106+
mock.a
1107+
withself.assertRaisesRegex(AttributeError,msg):
1108+
mock.b
10371109

10381110
classTestCallList(unittest.TestCase):
10391111

‎Lib/unittest/mock.py‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
importpkgutil
3535
frominspectimportiscoroutinefunction
3636
importthreading
37+
fromdataclassesimportfields,is_dataclass
3738
fromtypesimportCodeType,ModuleType,MethodType
3839
fromunittest.utilimportsafe_repr
3940
fromfunctoolsimportwraps,partial
@@ -2756,7 +2757,15 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
27562757
raiseInvalidSpecError(f'Cannot autospec a Mock object. '
27572758
f'[object={spec!r}]')
27582759
is_async_func=_is_async_func(spec)
2759-
_kwargs= {'spec':spec}
2760+
2761+
entries= [(entry,_missing)forentryindir(spec)]
2762+
ifis_typeandinstanceandis_dataclass(spec):
2763+
dataclass_fields=fields(spec)
2764+
entries.extend((f.name,f.type)forfindataclass_fields)
2765+
_kwargs= {'spec': [f.nameforfindataclass_fields]}
2766+
else:
2767+
_kwargs= {'spec':spec}
2768+
27602769
ifspec_set:
27612770
_kwargs= {'spec_set':spec}
27622771
elifspecisNone:
@@ -2813,7 +2822,7 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28132822
_name='()',_parent=mock,
28142823
wraps=wrapped)
28152824

2816-
forentryindir(spec):
2825+
forentry,originalinentries:
28172826
if_is_magic(entry):
28182827
# MagicMock already does the useful magic methods for us
28192828
continue
@@ -2827,10 +2836,11 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
28272836
# AttributeError on being fetched?
28282837
# we could be resilient against it, or catch and propagate the
28292838
# exception when the attribute is fetched from the mock
2830-
try:
2831-
original=getattr(spec,entry)
2832-
exceptAttributeError:
2833-
continue
2839+
iforiginalis_missing:
2840+
try:
2841+
original=getattr(spec,entry)
2842+
exceptAttributeError:
2843+
continue
28342844

28352845
child_kwargs= {'spec':original}
28362846
# Wrap child attributes also.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add support for:func:`dataclasses.dataclass` in
2+
:func:`unittest.mock.create_autospec`. Now ``create_autospec`` will check
3+
for potential dataclasses and use:func:`dataclasses.fields` function to
4+
retrieve the spec information.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp