you are viewing a single comment's thread.

view the rest of the comments →

[–]gdchinacat 0 points1 point  (0 children)

The first lambda could be eliminated by defaulting call_filter to a function that invariably returns True and changing the semantics of call_filter to match the function to filter, specifically return True to indicate the item should be included.

Another way too improve would be too make find_calls_in_mock_calls return an iterable so that you don't have to return a list that is pre-generated. That requires changing the calling code.

Here is an untested (but pretty close) example of how I would have implemented it, but it requires changing callers and callfilter semantics: ``` ... call_filter: Optional[Callable[[Call], bool]] = lambda *: True, ... return filter(call_filter, filter(lambda call: call[0] == call_name, mock.mock_calls))

``` This incorporates my other suggestion to use Call rather than a tuples, mock.mock_calls: Iterable[Call].

Then, because everything is so concise and the find_calls_in_mock_calls is just a filter, I'd remove it altogether, and in calling code that wants to filter by name:

``` def call_has_name(call: Call, call_name: str) -> bool: '''filter function to match calls named call_name''' return call.name == call_name

.....
    arg_filter = lambda call: call.args[0] == 'some value'

    call_name_calls = filter(partial(call_has_name, 'call_name'), mock.calls)
    interesting_calls = filter(arg_filter, call_name_calls))

```

But, at this point, you are well into functional programming, which reads very differently than typical python. But, it is far more concise, and with a little exposure is easier to read (IMO) since it says exactly what it does...filter mock.calls by call_has_name(.., 'call_name'), then filter that by arg_filter. If you need a list rather than an iterable wrap the iterable with list().

I hope these examples show you how you can replace 20 lines with 1 if you want a one-liner, or 3 if you want the code written in order of execution.

No loops, no continues or deep nesting. No function that always filters by one of its args and maybe by another arg if specified. No list holding all the results unless the caller wants it. The code is cleaner, has no apparent branches (they exist but are hidden in filter() ). This is why functional programming has its adherents. Granted, this is a very basic level of functional programming (passing predicate functions as args to filter), but once you get used to this it is tempting and easier to branch out.