third_party.pylibs.pylint.src/pylint
Andrew Haigh 087d77adcd
Fix loop in too-many-ancestors when an inheritance cycle is inferred (#5062)
* Add regression test for #4972 hang

* Fix loop in too-many-ancestors when an inheritance cycle is inferred

Ref #4972. If a class could be inferred as an ancestor of itself then
the implementation of _get_parents could get caught in an infinite loop,
forever adding itself to to_explore. This could be possible by
monkeypatching an ancestor after class definition like in the following
simplified example:

    class Fake(module.Cls):
        pass

    module.Cls = Fake

Reproducing this is fairly tricky, but this integration test shows the
behaviour as of 1e675abcc2aa931421d7ce300908e734a93fd790:

    #!/bin/sh

    HERE=$(readlink -f .)
    VENV=$HERE/venv-repro
    PIP=$VENV/bin/pip

    python -m venv "$VENV"

    PYLINT=$VENV/bin/pylint

    # assume running in pylint dir
    $PIP install -e .
    $PIP install flask

    mkdir -p repro/flask/
    touch repro/__init__.py
    cat > repro/flask/__init__.py <<'EOF'
    import flask
    import repro.flask  # self-import necessary

    class Fake(flask.Flask):
        pass

    flask.Flask = Fake
    EOF

    echo +++ this is fine
    $PYLINT --rcfile=/dev/null -- repro/flask/
    echo +++ finished

    echo +++ this loops forever
    cd repro/; $PYLINT --rcfile=/dev/null -- flask/
    echo +++ should not reach here
2021-09-24 18:02:12 +02:00
..
checkers Fix loop in too-many-ancestors when an inheritance cycle is inferred (#5062) 2021-09-24 18:02:12 +02:00
config Update toml dependency to >=0.9.2 (#5067) 2021-09-23 19:47:04 +02:00
extensions
lint
message Fix `useless-suppression for wrong-import-order` (#5063) 2021-09-23 10:18:29 +02:00
pyreverse
reporters
testutils Refactor and typing of OutputLine (#5060) 2021-09-24 00:27:33 +02:00
utils Refactor of `FileState.handle_ignored_message()` (#5064) 2021-09-23 08:21:15 +02:00
__init__.py
__main__.py
__pkginfo__.py
constants.py
epylint.py
exceptions.py
graph.py
interfaces.py
typing.py