aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/unittest/mock.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
committershadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Lib/unittest/mock.py
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
downloadydb-d4be68e361f4258cf0848fc70018dfe37a2acc24.tar.gz
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Lib/unittest/mock.py')
-rw-r--r--contrib/tools/python3/src/Lib/unittest/mock.py84
1 files changed, 71 insertions, 13 deletions
diff --git a/contrib/tools/python3/src/Lib/unittest/mock.py b/contrib/tools/python3/src/Lib/unittest/mock.py
index 3f5442ed80..7152f86ed9 100644
--- a/contrib/tools/python3/src/Lib/unittest/mock.py
+++ b/contrib/tools/python3/src/Lib/unittest/mock.py
@@ -36,6 +36,10 @@ from unittest.util import safe_repr
from functools import wraps, partial
+class InvalidSpecError(Exception):
+ """Indicates that an invalid value was used as a mock spec."""
+
+
_builtins = {name for name in dir(builtins) if not name.startswith('_')}
FILTER_DIR = True
@@ -631,9 +635,10 @@ class NonCallableMock(Base):
elif _is_magic(name):
raise AttributeError(name)
if not self._mock_unsafe:
- if name.startswith(('assert', 'assret')):
- raise AttributeError("Attributes cannot start with 'assert' "
- "or 'assret'")
+ if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')):
+ raise AttributeError(
+ f"{name!r} is not a valid assertion. Use a spec "
+ f"for the mock if {name!r} is meant to be an attribute.")
result = self._mock_children.get(name)
if result is _deleted:
@@ -652,10 +657,17 @@ class NonCallableMock(Base):
self._mock_children[name] = result
elif isinstance(result, _SpecState):
- result = create_autospec(
- result.spec, result.spec_set, result.instance,
- result.parent, result.name
- )
+ try:
+ result = create_autospec(
+ result.spec, result.spec_set, result.instance,
+ result.parent, result.name
+ )
+ except InvalidSpecError:
+ target_name = self.__dict__['_mock_name'] or self
+ raise InvalidSpecError(
+ f'Cannot autospec attr {name!r} from target '
+ f'{target_name!r} as it has already been mocked out. '
+ f'[target={self!r}, attr={result.spec!r}]')
self._mock_children[name] = result
return result
@@ -1240,6 +1252,17 @@ def _importer(target):
return thing
+# _check_spec_arg_typos takes kwargs from commands like patch and checks that
+# they don't contain common misspellings of arguments related to autospeccing.
+def _check_spec_arg_typos(kwargs_to_check):
+ typos = ("autospect", "auto_spec", "set_spec")
+ for typo in typos:
+ if typo in kwargs_to_check:
+ raise RuntimeError(
+ f"{typo!r} might be a typo; use unsafe=True if this is intended"
+ )
+
+
class _patch(object):
attribute_name = None
@@ -1247,7 +1270,7 @@ class _patch(object):
def __init__(
self, getter, attribute, new, spec, create,
- spec_set, autospec, new_callable, kwargs
+ spec_set, autospec, new_callable, kwargs, *, unsafe=False
):
if new_callable is not None:
if new is not DEFAULT:
@@ -1258,6 +1281,16 @@ class _patch(object):
raise ValueError(
"Cannot use 'autospec' and 'new_callable' together"
)
+ if not unsafe:
+ _check_spec_arg_typos(kwargs)
+ if _is_instance_mock(spec):
+ raise InvalidSpecError(
+ f'Cannot spec attr {attribute!r} as the spec '
+ f'has already been mocked out. [spec={spec!r}]')
+ if _is_instance_mock(spec_set):
+ raise InvalidSpecError(
+ f'Cannot spec attr {attribute!r} as the spec_set '
+ f'target has already been mocked out. [spec_set={spec_set!r}]')
self.getter = getter
self.attribute = attribute
@@ -1485,6 +1518,18 @@ class _patch(object):
if autospec is True:
autospec = original
+ if _is_instance_mock(self.target):
+ raise InvalidSpecError(
+ f'Cannot autospec attr {self.attribute!r} as the patch '
+ f'target has already been mocked out. '
+ f'[target={self.target!r}, attr={autospec!r}]')
+ if _is_instance_mock(autospec):
+ target_name = getattr(self.target, '__name__', self.target)
+ raise InvalidSpecError(
+ f'Cannot autospec attr {self.attribute!r} from target '
+ f'{target_name!r} as it has already been mocked out. '
+ f'[target={self.target!r}, attr={autospec!r}]')
+
new = create_autospec(autospec, spec_set=spec_set,
_name=self.attribute, **kwargs)
elif kwargs:
@@ -1567,7 +1612,7 @@ def _get_target(target):
def _patch_object(
target, attribute, new=DEFAULT, spec=None,
create=False, spec_set=None, autospec=None,
- new_callable=None, **kwargs
+ new_callable=None, *, unsafe=False, **kwargs
):
"""
patch the named member (`attribute`) on an object (`target`) with a mock
@@ -1589,7 +1634,7 @@ def _patch_object(
getter = lambda: target
return _patch(
getter, attribute, new, spec, create,
- spec_set, autospec, new_callable, kwargs
+ spec_set, autospec, new_callable, kwargs, unsafe=unsafe
)
@@ -1644,7 +1689,7 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None,
def patch(
target, new=DEFAULT, spec=None, create=False,
- spec_set=None, autospec=None, new_callable=None, **kwargs
+ spec_set=None, autospec=None, new_callable=None, *, unsafe=False, **kwargs
):
"""
`patch` acts as a function decorator, class decorator or a context
@@ -1706,6 +1751,10 @@ def patch(
use "as" then the patched object will be bound to the name after the
"as"; very useful if `patch` is creating a mock object for you.
+ Patch will raise a `RuntimeError` if passed some common misspellings of
+ the arguments autospec and spec_set. Pass the argument `unsafe` with the
+ value True to disable that check.
+
`patch` takes arbitrary keyword arguments. These will be passed to
`AsyncMock` if the patched object is asynchronous, to `MagicMock`
otherwise or to `new_callable` if specified.
@@ -1716,7 +1765,7 @@ def patch(
getter, attribute = _get_target(target)
return _patch(
getter, attribute, new, spec, create,
- spec_set, autospec, new_callable, kwargs
+ spec_set, autospec, new_callable, kwargs, unsafe=unsafe
)
@@ -2566,7 +2615,7 @@ call = _Call(from_kall=False)
def create_autospec(spec, spec_set=False, instance=False, _parent=None,
- _name=None, **kwargs):
+ _name=None, *, unsafe=False, **kwargs):
"""Create a mock object using another object as a spec. Attributes on the
mock will use the corresponding attribute on the `spec` object as their
spec.
@@ -2582,6 +2631,10 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
spec for an instance object by passing `instance=True`. The returned mock
will only be callable if instances of the mock are callable.
+ `create_autospec` will raise a `RuntimeError` if passed some common
+ misspellings of the arguments autospec and spec_set. Pass the argument
+ `unsafe` with the value True to disable that check.
+
`create_autospec` also takes arbitrary keyword arguments that are passed to
the constructor of the created mock."""
if _is_list(spec):
@@ -2590,6 +2643,9 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
spec = type(spec)
is_type = isinstance(spec, type)
+ if _is_instance_mock(spec):
+ raise InvalidSpecError(f'Cannot autospec a Mock object. '
+ f'[object={spec!r}]')
is_async_func = _is_async_func(spec)
_kwargs = {'spec': spec}
if spec_set:
@@ -2599,6 +2655,8 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
_kwargs = {}
if _kwargs and instance:
_kwargs['_spec_as_instance'] = True
+ if not unsafe:
+ _check_spec_arg_typos(kwargs)
_kwargs.update(kwargs)