Coder Social home page Coder Social logo

xion / callee Goto Github PK

View Code? Open in Web Editor NEW
87.0 6.0 11.0 221 KB

Argument matchers for unittest.mock

Home Page: http://callee.readthedocs.org

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%
python testing mocking unit-testing matchers

callee's People

Contributors

donaldwhyte avatar fperetti avatar xion avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

callee's Issues

Add tests for __repr__

Some __repr__ method implementations in matcher are quite complex. They should have tests written for them.

Magic ARG object for predicate construction

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.

Caveats

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).

Matching/ArgThat to accept eval() strings

Essentially:

ArgThat('x % 2 == 0')

Caveats:

  • Scoping. It's probably best if the compiled closure didn't include local scope of the matcher ctor invocation, but it should still include global scope (for imported modules).
  • Name of the placeholder/argument variable could be deduced intelligently (it'd be the sole unbound variable), but it probably requires tricks with the Python code object.

Importing ABCs directly from collections deprecated in Python 3.7, stopped working in 3.8

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

Allow matcher classes to be used directly

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.

Add on= parameter to Eq

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 matchers to assert on characters

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.

Dict(keys=String()) example fails

Docs give the example:

dict with string keys (no restriction on values)

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?

Allow `Captor` to capture multiple arguments

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.

  • Allow Captor to be created with an allow_multiple_captures parameter and set the value to the last captured argument
captor = Captor(allow_multiple_captures=True)  # False by default?
mock = Mock()
mock(1)
mock(2)
mock.assert_called_with(captor)
assert 2 == captor.value
  • Allow Captor to match multiple arguments and save them in a list
captor = 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

  • Create a MultiCaptor Captor that will collect all matches for a given argument

Coalesce chained logical expressions

Chained 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.

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.

asyncio.coroutine has been deprecated since Python 3.8 over async def syntax

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):

Are maintainers missing in this project?

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!

Bootstrap documentation

We need something to put up on ReadTheDocs, even if it's just empty page, to have the link in README not 404.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.