Pylint magic

I am using pylint on most of my code to make sure nothing bad or too complicated sneaks in. So far it has helped me a lot in discovering stuff I would not notice, and if you are not using #pylint: disable=... too often it forces you to write better code.

I just stumbled across this:

I want to find the first element in a list of elements that is bigger than the specified one. For simplicity I am just using numbers here…

./some.py:

def function(current, *selection):
    for number in [num for num in sorted(selection) if num > current]:
        return number

But my tests show me that something bad is happening…

./test_some.py:

from some import function

NUMBERS = [5, 4, 3, 2, 1]


def test_function():
    assert function(3, *NUMBERS) == 4
    assert function(3) is None

Running the tests shows that the last assert statement goes over the for loop end exits the function, returning None.

$ pytest -vv  test_some.py
================= test session starts =================
collected 1 item

test_some.py::test_function PASSED              [100%]

================== 1 passed in 0.02s ==================

But running the tests yields no errors:

$ pylint --disable "C0114" --disable "C0116" some.py test_some.py

------------------------------------
Your code has been rated at 10.00/10

I would have expected this typical message:

Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)

Weird.


So, digging a little further, that example can be trimmed down to this:

def fun():
    for _ in []:
        return True

It seems, that the check for inconsistent-return-statements gets confused by the return inside the for loop. It does (or cannot?) not check if the input of the for loop is empty or not.

So, now I am aware of this. Anyway, I only discovered this while doing test driven development. For a moment I was confused why some assert bailed out with some None value for some edge-case that was not implemented yet..

So long!