Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
9a7d9519
Commit
9a7d9519
authored
Sep 28, 2019
by
Lisa Roach
Committed by
GitHub
Sep 28, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-38108: Makes mock objects inherit from Base (GH-16060)
parent
f185a732
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
58 additions
and
57 deletions
+58
-57
Lib/unittest/mock.py
Lib/unittest/mock.py
+19
-36
Lib/unittest/test/testmock/testasync.py
Lib/unittest/test/testmock/testasync.py
+37
-18
Lib/unittest/test/testmock/testmagicmethods.py
Lib/unittest/test/testmock/testmagicmethods.py
+0
-3
Misc/NEWS.d/next/Library/2019-09-25-21-37-02.bpo-38108.Jr9HU6.rst
...S.d/next/Library/2019-09-25-21-37-02.bpo-38108.Jr9HU6.rst
+2
-0
No files found.
Lib/unittest/mock.py
View file @
9a7d9519
...
...
@@ -409,7 +409,7 @@ class NonCallableMock(Base):
if
spec_arg
and
_is_async_obj
(
spec_arg
):
bases
=
(
AsyncMockMixin
,
cls
)
new
=
type
(
cls
.
__name__
,
bases
,
{
'__doc__'
:
cls
.
__doc__
})
instance
=
object
.
__new__
(
new
)
instance
=
_safe_super
(
NonCallableMock
,
cls
)
.
__new__
(
new
)
return
instance
...
...
@@ -990,17 +990,18 @@ class NonCallableMock(Base):
_type
=
type
(
self
)
if
issubclass
(
_type
,
MagicMock
)
and
_new_name
in
_async_method_magics
:
# Any asynchronous magic becomes an AsyncMock
klass
=
AsyncMock
elif
_new_name
in
_sync_async_magics
:
# Special case these ones b/c users will assume they are async,
# but they are actually sync (ie. __aiter__)
klass
=
MagicMock
elif
issubclass
(
_type
,
AsyncMockMixin
):
klass
=
AsyncMock
if
_new_name
in
_all_sync_magics
:
# Any synchronous magic becomes a MagicMock
klass
=
MagicMock
else
:
klass
=
AsyncMock
elif
not
issubclass
(
_type
,
CallableMixin
):
if
issubclass
(
_type
,
NonCallableMagicMock
):
klass
=
MagicMock
elif
issubclass
(
_type
,
NonCallableMock
)
:
elif
issubclass
(
_type
,
NonCallableMock
):
klass
=
Mock
else
:
klass
=
_type
.
__mro__
[
1
]
...
...
@@ -1886,6 +1887,7 @@ magic_methods = (
"round trunc floor ceil "
"bool next "
"fspath "
"aiter "
)
numerics
=
(
...
...
@@ -2024,7 +2026,7 @@ def _set_return_value(mock, method, name):
class
MagicMixin
(
object
):
class
MagicMixin
(
Base
):
def
__init__
(
self
,
/
,
*
args
,
**
kw
):
self
.
_mock_set_magics
()
# make magic work for kwargs in init
_safe_super
(
MagicMixin
,
self
).
__init__
(
*
args
,
**
kw
)
...
...
@@ -2032,13 +2034,14 @@ class MagicMixin(object):
def
_mock_set_magics
(
self
):
these_magics
=
_magics
orig_magics
=
_magics
|
_async_method_magics
these_magics
=
orig_magics
if
getattr
(
self
,
"_mock_methods"
,
None
)
is
not
None
:
these_magics
=
_magics
.
intersection
(
self
.
_mock_methods
)
these_magics
=
orig
_magics
.
intersection
(
self
.
_mock_methods
)
remove_magics
=
set
()
remove_magics
=
_magics
-
these_magics
remove_magics
=
orig
_magics
-
these_magics
for
entry
in
remove_magics
:
if
entry
in
type
(
self
).
__dict__
:
...
...
@@ -2066,33 +2069,13 @@ class NonCallableMagicMock(MagicMixin, NonCallableMock):
self
.
_mock_set_magics
()
class
AsyncMagicMixin
:
class
AsyncMagicMixin
(
MagicMixin
)
:
def
__init__
(
self
,
/
,
*
args
,
**
kw
):
self
.
_mock_set_
async_
magics
()
# make magic work for kwargs in init
self
.
_mock_set_magics
()
# make magic work for kwargs in init
_safe_super
(
AsyncMagicMixin
,
self
).
__init__
(
*
args
,
**
kw
)
self
.
_mock_set_async_magics
()
# fix magic broken by upper level init
def
_mock_set_async_magics
(
self
):
these_magics
=
_async_magics
if
getattr
(
self
,
"_mock_methods"
,
None
)
is
not
None
:
these_magics
=
_async_magics
.
intersection
(
self
.
_mock_methods
)
remove_magics
=
_async_magics
-
these_magics
for
entry
in
remove_magics
:
if
entry
in
type
(
self
).
__dict__
:
# remove unneeded magic methods
delattr
(
self
,
entry
)
# don't overwrite existing attributes if called a second time
these_magics
=
these_magics
-
set
(
type
(
self
).
__dict__
)
_type
=
type
(
self
)
for
entry
in
these_magics
:
setattr
(
_type
,
entry
,
MagicProxy
(
entry
,
self
))
self
.
_mock_set_magics
()
# fix magic broken by upper level init
class
MagicMock
(
MagicMixin
,
AsyncMagicMixin
,
Mock
):
class
MagicMock
(
MagicMixin
,
Mock
):
"""
MagicMock is a subclass of Mock with default implementations
of most of the magic methods. You can use MagicMock without having to
...
...
@@ -2114,7 +2097,7 @@ class MagicMock(MagicMixin, AsyncMagicMixin, Mock):
class
MagicProxy
(
object
):
class
MagicProxy
(
Base
):
def
__init__
(
self
,
name
,
parent
):
self
.
name
=
name
self
.
parent
=
parent
...
...
Lib/unittest/test/testmock/testasync.py
View file @
9a7d9519
...
...
@@ -379,6 +379,43 @@ class AsyncArguments(unittest.TestCase):
RuntimeError
(
'coroutine raised StopIteration'
)
)
class
AsyncMagicMethods
(
unittest
.
TestCase
):
def
test_async_magic_methods_return_async_mocks
(
self
):
m_mock
=
MagicMock
()
self
.
assertIsInstance
(
m_mock
.
__aenter__
,
AsyncMock
)
self
.
assertIsInstance
(
m_mock
.
__aexit__
,
AsyncMock
)
self
.
assertIsInstance
(
m_mock
.
__anext__
,
AsyncMock
)
# __aiter__ is actually a synchronous object
# so should return a MagicMock
self
.
assertIsInstance
(
m_mock
.
__aiter__
,
MagicMock
)
def
test_sync_magic_methods_return_magic_mocks
(
self
):
a_mock
=
AsyncMock
()
self
.
assertIsInstance
(
a_mock
.
__enter__
,
MagicMock
)
self
.
assertIsInstance
(
a_mock
.
__exit__
,
MagicMock
)
self
.
assertIsInstance
(
a_mock
.
__next__
,
MagicMock
)
self
.
assertIsInstance
(
a_mock
.
__len__
,
MagicMock
)
def
test_magicmock_has_async_magic_methods
(
self
):
m_mock
=
MagicMock
()
self
.
assertTrue
(
hasattr
(
m_mock
,
"__aenter__"
))
self
.
assertTrue
(
hasattr
(
m_mock
,
"__aexit__"
))
self
.
assertTrue
(
hasattr
(
m_mock
,
"__anext__"
))
def
test_asyncmock_has_sync_magic_methods
(
self
):
a_mock
=
AsyncMock
()
self
.
assertTrue
(
hasattr
(
a_mock
,
"__enter__"
))
self
.
assertTrue
(
hasattr
(
a_mock
,
"__exit__"
))
self
.
assertTrue
(
hasattr
(
a_mock
,
"__next__"
))
self
.
assertTrue
(
hasattr
(
a_mock
,
"__len__"
))
def
test_magic_methods_are_async_functions
(
self
):
m_mock
=
MagicMock
()
self
.
assertIsInstance
(
m_mock
.
__aenter__
,
AsyncMock
)
self
.
assertIsInstance
(
m_mock
.
__aexit__
,
AsyncMock
)
# AsyncMocks are also coroutine functions
self
.
assertTrue
(
asyncio
.
iscoroutinefunction
(
m_mock
.
__aenter__
))
self
.
assertTrue
(
asyncio
.
iscoroutinefunction
(
m_mock
.
__aexit__
))
class
AsyncContextManagerTest
(
unittest
.
TestCase
):
...
...
@@ -406,24 +443,6 @@ class AsyncContextManagerTest(unittest.TestCase):
val
=
await
response
.
json
()
return
val
def
test_async_magic_methods_are_async_mocks_with_magicmock
(
self
):
cm_mock
=
MagicMock
(
self
.
WithAsyncContextManager
())
self
.
assertIsInstance
(
cm_mock
.
__aenter__
,
AsyncMock
)
self
.
assertIsInstance
(
cm_mock
.
__aexit__
,
AsyncMock
)
def
test_magicmock_has_async_magic_methods
(
self
):
cm
=
MagicMock
(
name
=
'magic_cm'
)
self
.
assertTrue
(
hasattr
(
cm
,
"__aenter__"
))
self
.
assertTrue
(
hasattr
(
cm
,
"__aexit__"
))
def
test_magic_methods_are_async_functions
(
self
):
cm
=
MagicMock
(
name
=
'magic_cm'
)
self
.
assertIsInstance
(
cm
.
__aenter__
,
AsyncMock
)
self
.
assertIsInstance
(
cm
.
__aexit__
,
AsyncMock
)
# AsyncMocks are also coroutine functions
self
.
assertTrue
(
asyncio
.
iscoroutinefunction
(
cm
.
__aenter__
))
self
.
assertTrue
(
asyncio
.
iscoroutinefunction
(
cm
.
__aexit__
))
def
test_set_return_value_of_aenter
(
self
):
def
inner_test
(
mock_type
):
pc
=
self
.
ProductionCode
()
...
...
Lib/unittest/test/testmock/testmagicmethods.py
View file @
9a7d9519
...
...
@@ -271,9 +271,6 @@ class TestMockingMagicMethods(unittest.TestCase):
self
.
assertEqual
(
mock
==
mock
,
True
)
self
.
assertEqual
(
mock
!=
mock
,
False
)
# This should be fixed with issue38163
@
unittest
.
expectedFailure
def
test_asyncmock_defaults
(
self
):
mock
=
AsyncMock
()
self
.
assertEqual
(
int
(
mock
),
1
)
...
...
Misc/NEWS.d/next/Library/2019-09-25-21-37-02.bpo-38108.Jr9HU6.rst
0 → 100644
View file @
9a7d9519
Any synchronous magic methods on an AsyncMock now return a MagicMock. Any
asynchronous magic methods on a MagicMock now return an AsyncMock.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment