xion / callee Goto Github PK
View Code? Open in Web Editor NEWArgument matchers for unittest.mock
Home Page: http://callee.readthedocs.org
License: BSD 3-Clause "New" or "Revised" License
Argument matchers for unittest.mock
Home Page: http://callee.readthedocs.org
License: BSD 3-Clause "New" or "Revised" License
Some __repr__
method implementations in matcher are quite complex. They should have tests written for them.
mock_foo.assert_called_with(ARG % 2 == 0)
mock_foo.assert_called_with(ARG.id == 42)
mock_foo.assert_called_with(ARG('foo') == 'FOO')
# etc.
as an equivalent of:
mock_foo.assert_called_with(ArgThat(lambda x: x % 2 == 0))
mock_foo.assert_called_with(ArgThat(lambda x: x.id == 42))
mock_foo.assert_called_with(ArgThat(lambda x: x('foo') == 'FOO'))
# etc.
In other words, an instance of a magic class with all feasible operators overloaded to produce lazy callables. ARG
itself would be just such lazy callable corresponding to an identity function.
Not every Python operator is overloadable, and
/or
are notable exceptions.
Of those that are, some have limitations (e.g. in
can only return boolean).
Pitfalls with function calls: foo(ARG)
doesn't work like the user may have expected.
How to distinguish ==
used in a predicate itself rather than for final matching? It would probably require a wrapper (i.e. M(ARG.id == 42)
vs. just ARG.id == 42
).
Alternatively, relational operator would produce a final matcher while __getattr__
or __getitem__
or other operators would result in an "unfinished" matcher. (This would work better if we could signal when a matcher has been created but not used).
tests/test_collections.py
176:class CustomDict(collections.MutableMapping):
181: if isinstance(iterable, collections.Mapping):
Is there a way to use the functionality for configuring a mock to return specific values (using side_effect as it seems from how mock works) when called with specific parameters?
Essentially:
ArgThat('x % 2 == 0')
Caveats:
code
object.When I run some tests with pytest and callee 0.3, this is printed at the end:
============================== warnings summary ===============================
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:74
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:74: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
CLASS = collections.Iterable
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:116
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:116: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
CLASS = collections.Sequence
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:128
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:128: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
CLASS = collections.Set
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:246
c:\users\rnd10\appdata\local\programs\python\python37-32\lib\site-packages\callee\collections.py:246: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
CLASS = collections.Mapping
-- Docs: https://docs.pytest.org/en/latest/warnings.html
======================= 78 passed, 4 warnings in 1.38s ========================
Pytest version info:
platform win32 -- Python 3.7.3, pytest-5.1.0, py-1.8.0, pluggy-0.12.0
plugins: cov-2.7.1, ordering-0.6, pycharm-0.6.0
Solution suggestions: https://stackoverflow.com/questions/53978542/how-to-use-collections-abc-from-both-python-3-8-and-python-2-7
For matchers that are rarely/never parametrized (like Integer
), the pair of parentheses required for their instantation is kind of a boilerplate. Ideally, we'd want the following two lines to be equivalent:
mock_foo.assert_called_with(Integer())
mock_foo.assert_called_with(Integer)
This is theoretically possible by copying the crucial magic methods (mostly __eq__
) from BaseMatcher
to BaseMatcherMetaclass
(likely through a shared mixin). It would have to be investigated, however, that there are no adverse effects of doing so.
Example:
mock_foo.assert_called_with(Eq(expected, on=attrgetter('id')))
which is equivalent to:
mock_foo.assert_called_with(ArgThat(lambda x: x.id == expected.id))
Optionally, if just a string is given to on=
, treat it as an implicit argument to attrgetter
, e.g. on='id
'.
Make key=
an alias for on=
for consistency with max
/min
/etc.
String
and Unicode
matchers could accept optional argument for matching characters, e.g. letters, digits, or arbitrary predicates. It could take a set of characters, a callable, or a Matcher
.
Docs give the example:
Dict(keys=String())
But this will fail because the code expects both keys and value to be defined. Also there is not test case for this example. Is this docs error or code error?
Currently the following will fail
from callee.general import Captor
from mock import Mock
mock = Mock()
mock(1)
captor = Captor()
mock.assert_called_with(captor)
assert 1 == captor.value # This is ok!
mock(2)
mock.assert_called_with(captor) # Fails with ValueError: a value has already been captured
This is somewhat inconsistent with how Mock::assert_called_with works
. For example:
mock = Mock()
mock(1)
mock(2)
mock(3)
mock.assert_called_with(3) # This is ok!
There are multiple ways to deal with this.
Captor
to be created with an allow_multiple_captures
parameter and set the value to the last captured argumentcaptor = Captor(allow_multiple_captures=True) # False by default?
mock = Mock()
mock(1)
mock(2)
mock.assert_called_with(captor)
assert 2 == captor.value
Captor
to match multiple arguments and save them in a listcaptor = Captor(matcher=lambda x: x < 2, allow_multiple_captures=True)
mock = Mock()
mock(1)
mock(2)
mock.assert_called_with(captor)
assert [1, 2] == captor.values
assert [Match(1, True), Match(2, False)] == captor.matches
MultiCaptor
Captor that will collect all matches for a given argumentChained expressions such as a | b | c
are currently represented as nested matchers (Or(Or(a, b), c)
) because of operators associativity. These structures should be flattened instead (e.g. Or(a, b, c)
).
Deprecation warning due to invalid escape sequences. Using raw strings or escaping them again helps in resolving this. Check https://github.com/asottile/pyupgrade/ for automatic fix of this.
find . -iname '*.py' | grep -Ev 'rdf4|tool' | xargs -P4 -I{} python3.8 -Wall -m py_compile {}
./callee/collections.py:98: DeprecationWarning: invalid escape sequence \
"""Matches an iterable that's a generator.
./callee/types.py:19: DeprecationWarning: invalid escape sequence \
""":param type\ _: Type to match against"""
./callee/types.py:35: DeprecationWarning: invalid escape sequence \
"""
./callee/types.py:61: DeprecationWarning: invalid escape sequence \
"""
./callee/operators.py:188: DeprecationWarning: invalid escape sequence \
"""Matches values that are shorter than,
./callee/operators.py:206: DeprecationWarning: invalid escape sequence \
"""Matches values that are longer than,
./callee/numbers.py:46: DeprecationWarning: invalid escape sequence \
"""Matches any complex number.
./callee/numbers.py:60: DeprecationWarning: invalid escape sequence \
"""Matches any real number.
./callee/numbers.py:75: DeprecationWarning: invalid escape sequence \
"""Matches a rational number.
./callee/base.py:150: DeprecationWarning: invalid escape sequence \
"""Provides a default ``repr``\ esentation for custom matchers.
Following tests emit deprecation warning regarding this as below :
tests/test_objects.py
80: @asyncio.coroutine
103: @asyncio.coroutine
tests/test_functions.py
176: @asyncio.coroutine
199: @asyncio.coroutine
tests/test_functions.py::CoroutineFunction::test_coroutine__decorator
/root/checked_repos/callee/tests/test_functions.py:177: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def coro_func(loop):
tests/test_functions.py::CoroutineFunction::test_coroutine_function__decorator
/root/checked_repos/callee/tests/test_functions.py:200: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def coro_func(loop):
tests/test_objects.py::Coroutine::test_coroutine__decorator
/root/checked_repos/callee/tests/test_objects.py:81: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def coro_func(loop):
tests/test_objects.py::Coroutine::test_coroutine_function__decorator
/root/checked_repos/callee/tests/test_objects.py:104: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def coro_func(loop):
Hi @Xion or other people who maintains this project,
What is the status of this project?
This is a great tool for testing, I would like to keep using but looks like it hasn't been maintained for a while.
If there are any alternatives we could use, that information would be appreciated, too.
Thanks!
We need something to put up on ReadTheDocs, even if it's just empty page, to have the link in README not 404.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.