mirror of
https://github.com/python/cpython.git
synced 2025-10-07 15:42:02 +00:00
gh-98624 Add mutex to unittest.mock.NonCallableMock (#98688)
* Added lock to NonCallableMock in unittest.mock * Add blurb * Nitpick blurb * Edit comment based on @Jason-Y-Z's review * Add link to GH issue
This commit is contained in:
parent
fbcafa6eee
commit
0346eddbe9
2 changed files with 39 additions and 27 deletions
|
@ -35,6 +35,7 @@ from asyncio import iscoroutinefunction
|
||||||
from types import CodeType, ModuleType, MethodType
|
from types import CodeType, ModuleType, MethodType
|
||||||
from unittest.util import safe_repr
|
from unittest.util import safe_repr
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
|
from threading import RLock
|
||||||
|
|
||||||
|
|
||||||
class InvalidSpecError(Exception):
|
class InvalidSpecError(Exception):
|
||||||
|
@ -402,6 +403,14 @@ class Base(object):
|
||||||
class NonCallableMock(Base):
|
class NonCallableMock(Base):
|
||||||
"""A non-callable version of `Mock`"""
|
"""A non-callable version of `Mock`"""
|
||||||
|
|
||||||
|
# Store a mutex as a class attribute in order to protect concurrent access
|
||||||
|
# to mock attributes. Using a class attribute allows all NonCallableMock
|
||||||
|
# instances to share the mutex for simplicity.
|
||||||
|
#
|
||||||
|
# See https://github.com/python/cpython/issues/98624 for why this is
|
||||||
|
# necessary.
|
||||||
|
_lock = RLock()
|
||||||
|
|
||||||
def __new__(cls, /, *args, **kw):
|
def __new__(cls, /, *args, **kw):
|
||||||
# every instance has its own class
|
# every instance has its own class
|
||||||
# so we can create magic methods on the
|
# so we can create magic methods on the
|
||||||
|
@ -644,6 +653,7 @@ class NonCallableMock(Base):
|
||||||
f"{name!r} is not a valid assertion. Use a spec "
|
f"{name!r} is not a valid assertion. Use a spec "
|
||||||
f"for the mock if {name!r} is meant to be an attribute.")
|
f"for the mock if {name!r} is meant to be an attribute.")
|
||||||
|
|
||||||
|
with NonCallableMock._lock:
|
||||||
result = self._mock_children.get(name)
|
result = self._mock_children.get(name)
|
||||||
if result is _deleted:
|
if result is _deleted:
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add a mutex to unittest.mock.NonCallableMock to protect concurrent access
|
||||||
|
to mock attributes.
|
Loading…
Add table
Add a link
Reference in a new issue