diff --git a/.copyrite_aliases b/.copyrite_aliases deleted file mode 100644 index 3dea23b4f7..0000000000 --- a/.copyrite_aliases +++ /dev/null @@ -1,112 +0,0 @@ -[ - { - "mails": ["cpopa@cloudbasesolutions.com", "pcmanticore@gmail.com"], - "authoritative_mail": "pcmanticore@gmail.com", - "name": "Claudiu Popa" - }, - { - "mails": [ - "pierre.sassoulas@gmail.com", - "pierre.sassoulas@cea.fr", - "pierre.sassoulas@wisebim.fr" - ], - "authoritative_mail": "pierre.sassoulas@gmail.com", - "name": "Pierre Sassoulas" - }, - { - "mails": [ - "alexandre.fayolle@logilab.fr", - "emile.anclin@logilab.fr", - "david.douard@logilab.fr", - "laura.medioni@logilab.fr", - "anthony.truchet@logilab.fr", - "alain.leufroy@logilab.fr", - "julien.cristau@logilab.fr", - "Adrien.DiMascio@logilab.fr", - "emile@crater.logilab.fr", - "sylvain.thenault@logilab.fr", - "pierre-yves.david@logilab.fr", - "nicolas.chauvat@logilab.fr", - "afayolle.ml@free.fr", - "aurelien.campeas@logilab.fr", - "charles.hebert@logilab.fr", - "julien.jehannet@logilab.fr", - "lmedioni@logilab.fr" - ], - "authoritative_mail": "contact@logilab.fr", - "name": "LOGILAB S.A. (Paris, FRANCE)" - }, - { - "mails": ["moylop260@vauxoo.com"], - "name": "Moises Lopez", - "authoritative_mail": "moylop260@vauxoo.com" - }, - { - "mails": [ - "nathaniel@google.com", - "mbp@google.com", - "tmarek@google.com", - "shlomme@gmail.com", - "balparda@google.com", - "dlindquist@google.com" - ], - "name": "Google, Inc." - }, - { - "mails": [ - "ashley@awhetter.co.uk", - "awhetter.2011@my.bristol.ac.uk", - "asw@dneg.com", - "AWhetter@users.noreply.github.com" - ], - "name": "Ashley Whetter", - "authoritative_mail": "ashley@awhetter.co.uk" - }, - { - "mails": ["ville.skytta@iki.fi", "ville.skytta@upcloud.com"], - "authoritative_mail": "ville.skytta@iki.fi", - "name": "Ville Skyttä" - }, - { - "mails": [ - "ubuntu@ip-172-31-89-59.ec2.internal", - "eli88fine@gmail.com", - "ejfine@gmail.com" - ], - "authoritative_mail": "ejfine@gmail.com", - "name": "Eli Fine" - }, - { - "mails": ["andi.finkler@gmail.com", "3929834+DudeNr33@users.noreply.github.com"], - "authoritative_mail": "andi.finkler@gmail.com", - "name": "Andreas Finkler" - }, - { - "mails": ["matusvalo@users.noreply.github.com", "matusvalo@gmail.com"], - "authoritative_mail": "matusvalo@users.noreply.github.com", - "name": "Matus Valo" - }, - { - "mails": ["nickpesce22@gmail.com", "npesce@terpmail.umd.edu"], - "authoritative_mail": "nickpesce22@gmail.com", - "name": "Nick Pesce" - }, - { - "mails": ["31762852+mbyrnepr2@users.noreply.github.com", "mbyrnepr2@gmail.com"], - "authoritative_mail": "31762852+mbyrnepr2@users.noreply.github.com", - "name": "Mark Byrne" - }, - { - "mails": ["36848472+yushao2@users.noreply.github.com", "p.yushao2@gmail.com"], - "authoritative_mail": "36848472+yushao2@users.noreply.github.com", - "name": "Yu Shao, Pang" - }, - { - "mails": [ - "66853113+pre-commit-ci[bot]@users.noreply.github.com", - "49699333+dependabot[bot]@users.noreply.github.com" - ], - "authoritative_mail": "bot@noreply.github.com", - "name": "bot" - } -] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5cb6329f62..c1c6615b09 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,11 +3,12 @@ Thank you for submitting a PR to pylint! To ease the process of reviewing your PR, do make sure to complete the following boxes. -- [ ] Add yourself to CONTRIBUTORS if you are a new contributor. - [ ] Add a ChangeLog entry describing what your PR does. - [ ] If it's a new feature, or an important bug fix, add a What's New entry in `doc/whatsnew/`. - [ ] Write a good description on what the PR does. +- [ ] If you used multiple emails or multiple names when contributing, add your mails + and preferred name in ``script/.contributors_aliases.json`` --> ## Type of Changes diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ff306bbf18..8432c93fbe 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,7 +8,8 @@ on: pull_request: ~ env: - CACHE_VERSION: 3 + # Also change CACHE_VERSION in the primer workflow + CACHE_VERSION: 5 DEFAULT_PYTHON: 3.8 PRE_COMMIT_CACHE: ~/.cache/pre-commit @@ -16,17 +17,18 @@ jobs: prepare-base: name: Prepare base dependencies runs-on: ubuntu-latest + timeout-minutes: 10 outputs: python-key: ${{ steps.generate-python-key.outputs.key }} pre-commit-key: ${{ steps.generate-pre-commit-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 with: fetch-depth: 0 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Generate partial Python venv restore key @@ -37,7 +39,7 @@ jobs: }}" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: >- @@ -59,7 +61,7 @@ jobs: hashFiles('.pre-commit-config.yaml') }}" - name: Restore pre-commit environment id: cache-precommit - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: ${{ env.PRE_COMMIT_CACHE }} key: >- @@ -73,20 +75,21 @@ jobs: pre-commit install --install-hooks formatting: - name: Run pre-commit checks + name: checks / pre-commit runs-on: ubuntu-latest + timeout-minutes: 10 needs: prepare-base steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -99,7 +102,7 @@ jobs: exit 1 - name: Restore pre-commit environment id: cache-precommit - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} @@ -115,20 +118,21 @@ jobs: pre-commit run pylint --all-files spelling: - name: Run spelling checks + name: checks / spelling runs-on: ubuntu-latest + timeout-minutes: 5 needs: prepare-base steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -144,9 +148,41 @@ jobs: . venv/bin/activate pytest tests/ -k unittest_spelling + documentation: + name: checks / documentation + runs-on: ubuntu-latest + timeout-minutes: 5 + needs: prepare-base + steps: + - name: Check out code from GitHub + uses: actions/checkout@v3.0.0 + - name: Set up Python ${{ env.DEFAULT_PYTHON }} + id: python + uses: actions/setup-python@v3.0.0 + with: + python-version: ${{ env.DEFAULT_PYTHON }} + - name: Restore Python virtual environment + id: cache-venv + uses: actions/cache@v3.0.0 + with: + path: venv + key: + ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ + needs.prepare-base.outputs.python-key }} + - name: Fail job if Python cache restore failed + if: steps.cache-venv.outputs.cache-hit != 'true' + run: | + echo "Failed to restore Python venv from cache" + exit 1 + - name: Run checks on documentation code examples + run: | + . venv/bin/activate + pytest doc/test_messages_documentation.py + prepare-tests-linux: - name: Prepare tests for Python ${{ matrix.python-version }} (Linux) + name: tests / prepare / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] @@ -154,12 +190,12 @@ jobs: python-key: ${{ steps.generate-python-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Generate partial Python venv restore key @@ -170,7 +206,7 @@ jobs: }}" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: >- @@ -187,8 +223,9 @@ jobs: pip install -U -r requirements_test.txt pytest-linux: - name: Run tests Python ${{ matrix.python-version }} (Linux) + name: tests / run / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 15 needs: prepare-tests-linux strategy: fail-fast: false @@ -196,15 +233,15 @@ jobs: python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -218,16 +255,17 @@ jobs: - name: Run pytest run: | . venv/bin/activate - pytest --benchmark-disable --cov --cov-report= tests/ + pytest -vv --durations=20 --benchmark-disable --cov --cov-report= tests/ - name: Upload coverage artifact - uses: actions/upload-artifact@v2.2.4 + uses: actions/upload-artifact@v3.0.0 with: name: coverage-${{ matrix.python-version }} path: .coverage coverage: - name: Process test coverage + name: tests / process / coverage runs-on: ubuntu-latest + timeout-minutes: 5 needs: ["prepare-tests-linux", "pytest-linux"] strategy: matrix: @@ -236,15 +274,15 @@ jobs: COVERAGERC_FILE: .coveragerc steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -256,7 +294,7 @@ jobs: echo "Failed to restore Python venv from cache" exit 1 - name: Download all coverage artifacts - uses: actions/download-artifact@v2.0.10 + uses: actions/download-artifact@v3.0.0 - name: Combine coverage results run: | . venv/bin/activate @@ -270,24 +308,25 @@ jobs: coveralls --rcfile=${{ env.COVERAGERC_FILE }} --service=github benchmark-linux: - name: Run benchmark tests Python ${{ matrix.python-version }} (Linux) + name: tests / run benchmark / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest - needs: prepare-tests-linux + timeout-minutes: 10 + needs: ["prepare-tests-linux", "pytest-linux"] strategy: fail-fast: false matrix: python-version: [3.8, 3.9] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -313,7 +352,7 @@ jobs: run: >- echo "::set-output name=datetime::"$(date "+%Y%m%d_%H%M") - name: Upload benchmark artifact - uses: actions/upload-artifact@v2.2.4 + uses: actions/upload-artifact@v3.0.0 with: name: benchmark-${{ runner.os }}-${{ matrix.python-version }}_${{ @@ -321,8 +360,10 @@ jobs: path: .benchmarks/ prepare-tests-windows: - name: Prepare tests for Python ${{ matrix.python-version }} (Windows) + name: tests / prepare / ${{ matrix.python-version }} / Windows runs-on: windows-latest + timeout-minutes: 10 + needs: pytest-linux strategy: matrix: python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] @@ -330,12 +371,12 @@ jobs: python-key: ${{ steps.generate-python-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Generate partial Python venv restore key @@ -346,7 +387,7 @@ jobs: }}" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: >- @@ -363,8 +404,9 @@ jobs: pip install -U -r requirements_test_min.txt pytest-windows: - name: Run tests Python ${{ matrix.python-version }} (Windows) + name: tests / run / ${{ matrix.python-version }} / Windows runs-on: windows-latest + timeout-minutes: 15 needs: prepare-tests-windows strategy: fail-fast: false @@ -376,15 +418,15 @@ jobs: # Workaround to set correct temp directory on Windows # https://github.com/actions/virtual-environments/issues/712 - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -398,24 +440,25 @@ jobs: - name: Run pytest run: | . venv\\Scripts\\activate - pytest --benchmark-disable tests/ + pytest -vv --durations=20 --benchmark-disable tests/ prepare-tests-pypy: - name: Prepare tests for Python ${{ matrix.python-version }} + name: tests / prepare / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: - python-version: ["pypy3"] + python-version: ["pypy-3.6", "pypy-3.7"] outputs: python-key: ${{ steps.generate-python-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Generate partial Python venv restore key @@ -426,14 +469,14 @@ jobs: }}" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: >- - ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ + ${{ runner.os }}-${{ matrix.python-version }}-${{ steps.generate-python-key.outputs.key }} restore-keys: | - ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ env.CACHE_VERSION }}- + ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ env.CACHE_VERSION }}- - name: Create Python virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | @@ -443,28 +486,29 @@ jobs: pip install -U -r requirements_test_min.txt pytest-pypy: - name: Run tests Python ${{ matrix.python-version }} + name: tests / run / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 15 needs: prepare-tests-pypy strategy: fail-fast: false matrix: - python-version: ["pypy3"] + python-version: ["pypy-3.6", "pypy-3.7"] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: - ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ + ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests-pypy.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' @@ -474,4 +518,4 @@ jobs: - name: Run pytest run: | . venv/bin/activate - pytest --benchmark-disable tests/ + pytest -vv --durations=20 --benchmark-disable tests/ diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 26c0eea1c1..29493d2071 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/primer-test.yaml b/.github/workflows/primer-test.yaml index d4f7b15048..e1c321b38e 100644 --- a/.github/workflows/primer-test.yaml +++ b/.github/workflows/primer-test.yaml @@ -1,4 +1,4 @@ -name: Primer tests +name: Primer on: push: @@ -9,9 +9,12 @@ on: paths: - "pylint/**" - "tests/primer/**" + - "requirements*" + - ".github/workflows/primer-test.yaml" env: - CACHE_VERSION: 3 + # Also change CACHE_VERSION in the CI workflow + CACHE_VERSION: 5 concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -19,8 +22,9 @@ concurrency: jobs: prepare-tests-linux: - name: Prepare tests for Python ${{ matrix.python-version }} (Linux) + name: prepare / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 5 strategy: matrix: python-version: [3.8, 3.9, "3.10"] @@ -28,12 +32,12 @@ jobs: python-key: ${{ steps.generate-python-key.outputs.key }} steps: - name: Check out code from GitHub - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Generate partial Python venv restore key @@ -44,7 +48,7 @@ jobs: }}" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: >- @@ -61,23 +65,24 @@ jobs: pip install -U -r requirements_test.txt pytest-primer-stdlib: - name: Run primer tests on stdlib Python ${{ matrix.python-version }} (Linux) + name: run on stdlib / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 10 needs: prepare-tests-linux strategy: matrix: python-version: [3.8, 3.9, "3.10"] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.3.5 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -95,25 +100,24 @@ jobs: pytest -m primer_stdlib --primer-stdlib -n auto pytest-primer-external-batch-one: - name: - Run primer tests batch one on external libs Python ${{ matrix.python-version }} - (Linux) + name: run on batch one / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 60 needs: prepare-tests-linux strategy: matrix: python-version: [3.8, 3.9, "3.10"] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.3.5 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: @@ -131,25 +135,24 @@ jobs: pytest -m primer_external_batch_one --primer-external -n auto pytest-primer-external-batch-two: - name: - Run primer tests batch two on external libs Python ${{ matrix.python-version }} - (Linux) + name: run on batch two / ${{ matrix.python-version }} / Linux runs-on: ubuntu-latest + timeout-minutes: 60 needs: prepare-tests-linux strategy: matrix: python-version: [3.8, 3.9, "3.10"] steps: - name: Check out code from GitHub - uses: actions/checkout@v2.3.5 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ matrix.python-version }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ matrix.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@v2.1.7 + uses: actions/cache@v3.0.0 with: path: venv key: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5217fae7bb..1bf53bf711 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code from Github - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.0 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3.0.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Install requirements diff --git a/.gitignore b/.gitignore index 7e7c9cc978..07ec6627cf 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /pylint.egg-info/ .tox *.sw[a-z] +doc/messages/ doc/technical_reference/extensions.rst doc/technical_reference/features.rst pyve diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e692843b9..6bd4832deb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,25 +3,32 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: trailing-whitespace - exclude: "tests/functional/t/trailing_whitespaces.py" + exclude: "tests/functional/t/trailing_whitespaces.py|tests/pyreverse/data/.*.html" - id: end-of-file-fixer exclude: "tests/functional/m/missing/missing_final_newline.py|tests/functional/t/trailing_newlines.py" - repo: https://github.com/myint/autoflake rev: v1.4 hooks: - id: autoflake - exclude: &fixtures tests/functional/|tests/input|tests/regrtest_data/|tests/data/ + exclude: &fixtures tests/functional/|tests/input|tests/regrtest_data/|tests/data/|doc/data/messages|tests/testutils/data/ args: - --in-place - --remove-all-unused-imports - --expand-star-imports - --remove-duplicate-keys - --remove-unused-variables + - repo: https://github.com/Pierre-Sassoulas/copyright_notice_precommit + rev: f683ab7d10d5f7e779c75aea17197007583d14e4 + hooks: + - id: copyright-notice + args: ["--notice=script/copyright.txt", "--enforce-all"] + exclude: tests/functional/|tests/input|tests/regrtest_data/|tests/data/|doc/data/messages|tests/testutils/data/|examples/|setup.py + types: [python] - repo: https://github.com/asottile/pyupgrade - rev: v2.29.1 + rev: v2.31.1 hooks: - id: pyupgrade args: [--py36-plus] @@ -31,12 +38,12 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 21.11b1 + rev: 22.1.0 hooks: - id: black args: [--safe, --quiet] exclude: *fixtures - - repo: https://github.com/Pierre-Sassoulas/black-disable-checker/ + - repo: https://github.com/Pierre-Sassoulas/black-disable-checker rev: 1.0.1 hooks: - id: black-disable-checker @@ -44,7 +51,7 @@ repos: rev: 4.0.1 hooks: - id: flake8 - additional_dependencies: [flake8-typing-imports==1.10.1] + additional_dependencies: [flake8-typing-imports==1.12.0] exclude: *fixtures - repo: local hooks: @@ -77,7 +84,7 @@ repos: types: [text] # necessary to include ChangeLog file files: ^(ChangeLog|doc/(.*/)*.*\.rst) - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910-1 + rev: v0.941 hooks: - id: mypy name: mypy @@ -86,11 +93,18 @@ repos: types: [python] args: [] require_serial: true - additional_dependencies: - ["platformdirs==2.2.0", "types-pkg_resources==0.1.3", "types-toml==0.1.3"] + additional_dependencies: ["platformdirs==2.2.0", "types-pkg_resources==0.1.3"] exclude: tests/functional/|tests/input|tests(/.*)*/data|tests/regrtest_data/|tests/data/|tests(/.*)+/conftest.py|doc/|bin/ - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.5.0 + rev: v2.6.0 hooks: - id: prettier args: [--prose-wrap=always, --print-width=88] + exclude: tests(/.*)*/data + - repo: https://github.com/DanielNoord/pydocstringformatter + rev: v0.5.3 + hooks: + - id: pydocstringformatter + exclude: *fixtures + args: ["--split-summary-body", "--max-summary-lines=2"] + files: "pylint" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..6d30aaaae0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,120 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a +harassment-free experience for everyone, regardless of age, body size, visible or +invisible disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, +inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community +include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and + learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any + kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without + their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional + setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in response to +any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, +commits, code, wiki edits, issues, and other contributions that are not aligned to this +Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an +individual is officially representing the community in public spaces. Examples of +representing our community include using an official e-mail address, posting via an +official social media account, or acting as an appointed representative at an online or +offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to +the community leaders responsible for enforcement at pierre.sassoulas at gmail.com. All +complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter +of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the +consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity +around the nature of the violation and an explanation of why the behavior was +inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with +the people involved, including unsolicited interaction with those enforcing the Code of +Conduct, for a specified period of time. This includes avoiding interactions in +community spaces as well as external channels like social media. Violating these terms +may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained +inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication +with the community for a specified period of time. No public or private interaction with +the people involved, including unsolicited interaction with those enforcing the Code of +Conduct, is allowed during this period. Violating these terms may lead to a permanent +ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, +including sustained inappropriate behavior, harassment of an individual, or aggression +toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, +available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 72df6038c5..e394f5f479 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,589 +1,549 @@ -Contributors ------------- - -Current team: - -* Ashley Whetter: maintainer, contributor - -* Bryce Guinta: maintainer, contributor - -* Claudiu Popa: maintainer, contributor - -* Cara Vinson: astroid committer. - -* Guillaume Peillex: committer - -* Łukasz Rogalski: committer. +# This file is autocompleted by 'contributors-txt', +# using the configuration in 'script/.contributors_aliases.json'. +# Do not add new persons manually and only add information without +# using '-' as the line first character. +# Please verify that your change are stable if you modify manually. + +Ex-maintainers +-------------- +- Claudiu Popa +- Sylvain Thénault : main author / maintainer +- Torsten Marek + + +Maintainers +----------- + +- Pierre Sassoulas +- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com> +- Marc Mueller <30130371+cdce8p@users.noreply.github.com> +- Hippo91 +- Jacob Walls +- Łukasz Rogalski +- Ashley Whetter +- Bryce Guinta +- Andreas Finkler <3929834+DudeNr33@users.noreply.github.com> +- Yu Shao, Pang <36848472+yushao2@users.noreply.github.com> +- Dimitri Prybysh + * multiple-imports, not-iterable, not-a-mapping, various patches. +- Roy Williams (Lyft) + * added check for implementing __eq__ without implementing __hash__, + * Added Python 3 check for accessing Exception.message. + * Added Python 3 check for calling encode/decode with invalid codecs. + * Added Python 3 check for accessing sys.maxint. + * Added Python 3 check for bad import statements. + * Added Python 3 check for accessing deprecated methods on the 'string' module, + various patches. +- Florian Bruhin +- Arianna Yang -* Roy Williams (Lyft): committer - - added check for implementing __eq__ without implementing __hash__, - Added Python 3 check for accessing Exception.message. - Added Python 3 check for calling encode/decode with invalid codecs. - Added Python 3 check for accessing sys.maxint. - Added Python 3 check for bad import statements. - Added Python 3 check for accessing deprecated methods on the 'string' module, - various patches. - -* Dmitri Prybysh: committer - - multiple-imports, not-iterable, not-a-mapping, various patches. - -* Jim Robertson: committer - -Ex-maintainers: - -* Sylvain Thenault (Logilab): main author / maintainer - -* Torsten Marek (Google): committer / contributor +Contributors +------------ We would not be here without folks that contributed patches, pull requests, issues and their time to pylint. We're incredibly grateful to all of these contributors: - -* Daniel Balparda (Google): GPyLint maintainer (Google's pylint variant), - various patches - -* Martin Pool (Google): warnings for anomalous backslashes, symbolic names for - messages (like 'unused'), etc - -* Alexandre Fayolle (Logilab): TkInter gui, documentation, debian support - -* Julien Cristau, Emile Anclin (Logilab): python 3 support - -* Sandro Tosi: Debian packaging - -* Mads Kiilerich, Boris Feld, Bill Wendling, Sebastian Ulrich: - various patches - -* Brian van den Broek: windows installation documentation - -* Amaury Forgeot d'Arc: check names imported from a module exists in the module - -* Benjamin Niemann: allow block level enabling/disabling of messages - -* Nathaniel Manista: suspicious lambda checking - -* David Shea: invalid sequence and slice index - -* Carl Crowder: don't evaluate the value of arguments for 'dangerous-default-value' - -* Michal Nowikowski: wrong-spelling-in-comment, wrong-spelling-in-docstring, - parallel execution on multiple CPUs and other patches. - -* David Lindquist: logging-format-interpolation warning. - -* Brett Cannon: Port source code to be Python 2/3 compatible, Python 3 - checker. - -* Vlad Temian: redundant-unittest-assert and the JSON reporter. - -* Cosmin Poieană: unichr-builtin and improvements to bad-open-mode. - -* Viorel Știrbu: intern-builtin warning. - -* Dan Goldsmith: support for msg-template in HTML reporter. - -* Chris Rebert: unidiomatic-typecheck. - -* Steven Myint: duplicate-except. - -* Radu Ciorba: not-context-manager and confusing-with-statement warnings. - -* Bruno Daniel: check_docs extension. - -* James Morgensen: ignored-modules option applies to import errors. - -* Cezar Elnazli: deprecated-method - -* Stéphane Wirtel: nonlocal-without-binding - -* Laura Medioni (Logilab, on behalf of the CNES): misplaced-comparison-constant, - no-classmethod-decorator, no-staticmethod-decorator, too-many-nested-blocks, - too-many-boolean-expressions, unneeded-not, wrong-import-order, ungrouped-imports, - wrong-import-position, redefined-variable-type - -* Aru Sahni: Git ignoring, regex-based ignores - -* Mike Frysinger: contributor. - -* Moisés López (Vauxoo): Support for deprecated-modules in modules not installed, - Refactor wrong-import-order to integrate it with `isort` library - Add check too-complex with mccabe for cyclomatic complexity - Refactor wrong-import-position to skip try-import and nested cases - Add consider-merging-isinstance, superfluous-else-return - Fix consider-using-ternary for 'True and True and True or True' case - -* Luis Escobar (Vauxoo), Moisés López (Vauxoo): Add bad-docstring-quotes and docstring-first-line-empty - -* Yannick Brehon: contributor. - -* Glenn Matthews: autogenerated documentation for optional extensions, - bug fixes and enhancements for docparams (née check_docs) extension - -* Elias Dorneles: minor adjust to config defaults and docs - -* Yuri Bochkarev: Added epytext support to docparams extension. - -* Alexander Todorov: added new error conditions to 'bad-super-call', - Added new check for incorrect len(SEQUENCE) usage, - Added new extension for comparison against empty string constants, - Added new extension which detects comparing integers to zero, - Added new useless-return checker, - Added new try-except-raise checker - -* Erik Eriksson - Added overlapping-except error check. - -* Anthony Foglia (Google): Added simple string slots check. - -* Derek Gustafson: contributor - -* Petr Pulc: require whitespace around annotations - -* John Paraskevopoulos: add 'differing-param-doc' and 'differing-type-doc' - -* Martin von Gagern (Google): Added 'raising-format-tuple' warning. - -* Ahirnish Pareek, 'keyword-arg-before-var-arg' check - -* Daniel Miller: contributor. - -* Bryce Guinta: contributor - -* Martin Bašti: contributor - Added new check for shallow copy of os.environ - Added new check for useless `with threading.Lock():` statement - -* Jacques Kvam: contributor - -* Brian Shaginaw: prevent error on exception check for functions - -* Ioana Tagirta: fix bad thread instantiation check - -* Reverb Chu: contributor - -* Tobias Hernstig: contributor - -* Konstantin Manna: contributor - -* Andreas Freimuth: fix indentation checking with tabs - -* Renat Galimov: contributor - -* Thomas Snowden: fix missing-docstring for inner functions - -* Mitchell Young: minor adjustment to docparams - -* Marianna Polatoglou: minor contribution for wildcard import check - -* Ben Green: contributor - -* Benjamin Freeman: contributor - -* Fureigh: contributor - -* Jace Browning: updated default report format with clickable paths - -* Sushobhit (sushobhit27): contributor - Added new check 'comparison-with-itself'. - Added new check 'useless-import-alias'. - Added support of annotations in missing-type-doc and missing-return-type-doc. - Added new check 'comparison-with-callable'. - Removed six package dependency. - Added new check 'chained-comparison'. - Added new check 'useless-object-inheritance'. - -* Mariatta Wijaya: contributor - Added new check `logging-fstring-interpolation` - Documentation typo fixes - -* Jason Owen: contributor - -* Mark Roman Miller: fix inline defs in too-many-statements - -* Adam Dangoor: contributor - -* Gary Tyler McLeod: contributor - -* Wolfgang Grafen, Axel Muller, Fabio Zadrozny, Pierre Rouleau, - Maarten ter Huurne, Mirko Friedenhagen and all the Logilab's team (among others). - -* Matej Marusak: contributor - -* Nick Drozd: contributor, performance improvements to astroid - -* Kosarchuk Sergey: contributor - -* Carey Metcalfe: demoted `try-except-raise` from error to warning - -* Marcus Näslund (naslundx): contributor - -* Natalie Serebryakova: contributor - -* Caio Carrara: contributor - -* Roberto Leinardi: PyCharm plugin maintainer - -* Aivar Annamaa: contributor - -* Hornwitser: fix import graph - -* Yuri Gribov: contributor - -* Drew Risinger: committer (docs) - -* Ben James - -* Tomer Chachamu, Richard Goodman: simplifiable-if-expression - -* Alan Chan: contributor - -* Benjamin Drung: contributing Debian Developer - -* Scott Worley: contributor - -* Michael Hudson-Doyle - -* Lucas Cimon: contributor - -* Mike Miller: contributor - -* Sergei Lebedev: contributor - -* Sasha Bagan - -* Pablo Galindo Salgado: contributor - Fix false positive 'Non-iterable value' with async comprehensions. - -* Matus Valo - -* Sardorbek Imomaliev: contributor - -* Justin Li (justinnhli) - -* Nicolas Dickreuter - -* Pascal Corpet - -* Svetoslav Neykov: contributor - -* Federico Bond: contributor - -* Fantix King (UChicago): contributor - -* Yory (yory8): contributor - -* Thomas Hisch: contributor - -* Clément Pit-Claudel : contributor - -* Goudcode: contributor - -* Paul Renvoise : contributor - -* Bluesheeptoken: contributor - -* Michael Scott Cuthbert: contributor - -* Pierre Sassoulas : maintainer, contributor - -* Nathan Marrow - -* Taewon Kim : contributor - -* Daniil Kharkov: contributor - -* Tyler N. Thieding: contributor - -* Zeb Nicholls: contributor - - Made W9011 compatible with 'of' syntax in return types - -* Martin Vielsmaier: contributor - -* Agustin Toledo: contributor - -* Nicholas Smith: contributor - -* Peter Kolbus (Garmin): contributor - -* Oisin Moran: contributor - -* Andrzej Klajnert: contributor - -* Andrés Pérez Hortal: contributor - -* Niko Wenselowski: contributor - -* Danny Hermes: contributor - -* Eric Froemling: contributor - -* Robert Schweizer: contributor - -* Hugo van Kemenade: contributor - -* Mikhail Fesenko: contributor - -* Trevor Bekolay: contributor - - Added --list-msgs-enabled command - -* Rémi Cardona: contributor - -* Daniel Draper: contributor - -* Gabriel R. Sezefredo: contributor - - Fixed "exception-escape" false positive with generators - -* laike9m: contributor - -* Janne Rönkkö: contributor - -* Hugues Bruant: contributor - -* Tim Gates: contributor - -* Enji Cooper: contributor - -* Bastien Vallet: contributor - -* Pek Chhan: contributor - -* Craig Henriques: contributor - -* Matthijs Blom: contributor - -* Andy Palmer: contributor - -* Wes Turner (Google): added new check 'inconsistent-quotes' - -* Athos Ribeiro - Fixed dict-keys-not-iterating false positive for inverse containment checks - -* Anubhav: contributor - -* Ben Graham: contributor - -* Anthony Tan: contributor - -* Benny Müller: contributor - -* Bernie Gray: contributor - -* Slavfox: contributor - -* Matthew Beckers (mattlbeck): contributor - -* Yang Yang: contributor - -* Andrew J. Simmons (anjsimmo): contributor - -* Damien Baty: contributor - -* Daniel R. Neal (danrneal): contributer - -* Jeremy Fleischman (jfly): contributer - -* Shiv Venkatasubrahmanyam - -* Jochen Preusche (iilei): contributor - -* Ram Rachum (cool-RR) - -* D. Alphus (Alphadelta14): contributor - -* Pieter Engelbrecht - -* Ethan Leba: contributor - -* Matěj Grabovský: contributor - -* Yeting Li (yetingli): contributor - -* Frost Ming (frostming): contributor - -* Luigi Bertaco Cristofolini (luigibertaco): contributor - -* Eli Fine (eli88fine): Fixed false positive duplicate code warning for lines with symbols only - -* Ganden Schaffner: contributor - -* Josselin Feist: contributor - -* David Cain: contributor - -* Pedro Algarvio (s0undt3ch): contributor - -* Luigi Bertaco Cristofolini (luigibertaco): contributor - -* Or Bahari - -* Joshua Cannon: contributor - -* Giuseppe Valente: contributor - -* Takashi Hirashima: contributor - -* Joffrey Mander: contributor - -* Julien Palard: contributor - -* Raphael Gaschignard: contributor - -* Sorin Sbarnea: contributor - -* Gergely Kalmár: contributor - -* Batuhan Taskaya: contributor - -* Frank Harrison (doublethefish): contributor - -* Gauthier Sebaux: contributor - -* Logan Miller (komodo472): contributor - -* Matthew Suozzo: contributor - -* Marc Mueller (cdce8p): contributor - -* David Gilman: contributor - -* Ikraduya Edian: contributor - - Added new checks 'consider-using-generator' and 'use-a-generator'. - -* Tiago Honorato: contributor - -* Lefteris Karapetsas: contributor - -* Louis Sautier: contributor - -* Quentin Young: contributor - -* Alexander Kapshuna: contributor - -* Mark Byrne: contributor - -* Konstantina Saketou: contributor - -* Andrew Howe: contributor - -* James Sinclair (irgeek): contributor - -* Andreas Finkler: contributor - -* Aidan Haase, Elizabeth Bott: contributor - -* Sebastian Müller: contributor - -* Ramiro Leal-Cavazos (ramiro050): Fixed bug preventing pylint from working with emacs tramp - -* manderj: contributor - -* qwiddle: contributor - -* das-intensity: contributor - -* Jiajunsu (victor): contributor - -* Andrew Haigh (nelfin): contributor - -* Pang Yu Shao (yushao2): contributor - -* Aditya Gupta (adityagupta1089) : contributor - - Added ignore_signatures to duplicate checker - -* Jacob Walls: contributor - -* ruro: contributor - -* David Liu (david-yz-liu): contributor - -* Bernard Nauwelaerts: contributor - -* Fabian Damken: contributor - -* Markus Siebenhaar: contributor - -* Lorena Buciu (lorena-b): contributor - -* Sergei Lebedev (superbobry): contributor - -* Maksym Humetskyi (mhumetskyi): contributor - - Fixed ignored empty functions by similarities checker with "ignore-signatures" option enabled - - Ignore function decorators signatures as well by similarities checker with "ignore-signatures" option enabled - - Ignore class methods and nested functions signatures as well by similarities checker with "ignore-signatures" option enabled - -* Daniel Dorani (doranid): contributor - -* Will Shanks: contributor - -* Mark Bell: contributor - -* Marco Gorelli: contributor - - Documented Jupyter integration - -* Rebecca Turner (9999years): contributor - -* Yilei Yang: contributor - -* Marcin Kurczewski (rr-): contributor - -* Tanvi Moharir: contributor - - Fix for invalid toml config - -* Eisuke Kawashima (e-kwsm): contributor - -* Daniel van Noord (DanielNoord): contributor - -* Michal Vasilek: contributor - -* Kai Mueller (kasium): contributor - -* Sam Vermeiren (PaaEl): contributor - -* Phil A. (flying-sheep): contributor - -* Melvin Hazeleger (melvio): contributor - -* Hayden Richards (SupImDos): contributor - - Fixed "no-self-use" for async methods - - Fixed "docparams" extension for async functions and methods - -* Jeroen Seegers (jeroenseegers): contributor - - Fixed `toml` dependency issue - -* Tim Martin: contributor - -* Jaehoon Hwang (jaehoonhwang): contributor - -* Samuel Forestier: contributor - -* Nick Pesce: contributor - -* James DesLauriers: contributor - -* Youngsoo Sung: contributor - -* Arianna Yang: contributor - -* Samuel Freilich (sfreilich): contributor - -* Mike Fiedler (miketheman): contributor - -* Takahide Nojima: contributor - -* Tushar Sadhwani (tusharsadhwani): contributor - -* Ikraduya Edian: contributor - -* Antonio Quarta (sgheppy): contributor - -* Harshil (harshil21): contributor - -* Felix von Drigalski (felixvd): contributor - -* Philipp Albrecht (pylbrecht): contributor - -* Allan Chandler (allanc65): contributor - - Fixed issue 5452, false positive missing-param-doc for multi-line Google-style params +- Emile Anclin (Logilab): python 3 support +- Michal Nowikowski : + * wrong-spelling-in-comment + * wrong-spelling-in-docstring + * parallel execution on multiple CPUs +- Bruno Daniel : check_docs extension. +- Sushobhit <31987769+sushobhit27@users.noreply.github.com> (sushobhit27) + * Added new check 'comparison-with-itself'. + * Added new check 'useless-import-alias'. + * Added support of annotations in missing-type-doc and missing-return-type-doc. + * Added new check 'comparison-with-callable'. + * Removed six package dependency. + * Added new check 'chained-comparison'. + * Added new check 'useless-object-inheritance'. +- Brett Cannon : + * Port source code to be Python 2/3 compatible + * Python 3 checker +- Laura Médioni (Logilab, on behalf of the CNES): + * misplaced-comparison-constant + * no-classmethod-decorator + * no-staticmethod-decorator + * too-many-nested-blocks, + * too-many-boolean-expressions + * unneeded-not + * wrong-import-order + * ungrouped-imports, + * wrong-import-position + * redefined-variable-type +- Alexandre Fayolle (Logilab): TkInter gui, documentation, debian support +- Nick Drozd : performance improvements to astroid +- Julien Cristau (Logilab): python 3 support +- Adrien Di Mascio +- Frank Harrison (doublethefish) +- Moisés López (Vauxoo): + * Support for deprecated-modules in modules not installed, + * Refactor wrong-import-order to integrate it with `isort` library + * Add check too-complex with mccabe for cyclomatic complexity + * Refactor wrong-import-position to skip try-import and nested cases + * Add consider-merging-isinstance, superfluous-else-return + * Fix consider-using-ternary for 'True and True and True or True' case + * Add bad-docstring-quotes and docstring-first-line-empty +- Ville Skyttä +- Matus Valo +- Pierre-Yves David +- David Shea : invalid sequence and slice index +- Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> +- Derek Gustafson +- Cezar Elnazli : deprecated-method +- Nicolas Chauvat +- Radu Ciorba : not-context-manager and confusing-with-statement warnings. +- Holger Peters +- Cosmin Poieană : unichr-builtin and improvements to bad-open-mode. +- Steven Myint : duplicate-except. +- Peter Kolbus (Garmin) +- Luigi Bertaco Cristofolini (luigibertaco) +- Glenn Matthews : + * autogenerated documentation for optional extensions, + * bug fixes and enhancements for docparams (née check_docs) extension +- Vlad Temian : redundant-unittest-assert and the JSON reporter. +- Julien Jehannet +- Boris Feld +- Anthony Sottile +- Pedro Algarvio (s0undt3ch) +- Julien Palard +- David Liu (david-yz-liu) +- Dan Goldsmith : support for msg-template in HTML reporter. +- Mariatta Wijaya + * Added new check `logging-fstring-interpolation` + * Documentation typo fixes +- Jakub Wilk +- Émile Crater +- Pavel Roskin +- Eli Fine (eli88fine): Fixed false positive duplicate code warning for lines with symbols only +- David Gilman +- Andrew Haigh (nelfin) +- へーさん +- orSolocate <38433858+orSolocate@users.noreply.github.com> +- Tushar Sadhwani (tusharsadhwani) +- Thomas Hisch +- Marianna Polatoglou : minor contribution for wildcard import check +- Manuel Vázquez Acosta +- Luis Escobar (Vauxoo): Add bad-docstring-quotes and docstring-first-line-empty +- Jim Robertson +- Ethan Leba +- Enji Cooper +- David Lindquist : logging-format-interpolation warning. +- Buck (Yelp) +- Anthony Truchet +- Alexander Todorov : + * added new error conditions to 'bad-super-call', + * Added new check for incorrect len(SEQUENCE) usage, + * Added new extension for comparison against empty string constants, + * Added new extension which detects comparing integers to zero, + * Added new useless-return checker, + * Added new try-except-raise checker +- Téo Bouvard +- Mihai Balint +- Mark Bell +- Konstantina Saketou <56515303+ksaketou@users.noreply.github.com> +- Hugo van Kemenade +- Hornwitser : fix import graph +- Fureigh +- David Douard +- Daniel Balparda (Google): GPyLint maintainer (Google's pylint variant) +- Bastien Vallet (Djailla) +- Aru Sahni : Git ignoring, regex-based ignores +- Andreas Freimuth : fix indentation checking with tabs +- Alexandru Coman +- Takahide Nojima +- Taewon D. Kim +- Sneaky Pete +- Rene Zhang +- Or Bahari +- Mr. Senko +- Martin von Gagern (Google): Added 'raising-format-tuple' warning. +- Martin Vielsmaier +- Martin Pool (Google): + * warnings for anomalous backslashes + * symbolic names for messages (like 'unused') + * etc. +- Martin Bašti + * Added new check for shallow copy of os.environ + * Added new check for useless `with threading.Lock():` statement +- Marcus Näslund (naslundx) +- Marco Forte +- Joseph Young <80432516+jpy-git@users.noreply.github.com> (jpy-git) +- Ionel Maries Cristian +- Gergely Kalmár +- Daniel Harding +- Damien Baty +- Benjamin Drung : contributing Debian Developer +- Anubhav <35621759+anubh-v@users.noreply.github.com> +- Antonio Quarta (sgheppy) +- Andrew J. Simmons (anjsimmo) +- wtracy +- jpkotta +- chohner +- Tim Martin +- Tiago Honorato <61059243+tiagohonorato@users.noreply.github.com> +- Steven M. Vascellaro +- Sergey B Kirpichev +- Roberto Leinardi : PyCharm plugin maintainer +- Ricardo Gemignani +- Pieter Engelbrecht +- Philipp Albrecht (pylbrecht) +- Nicolas Dickreuter +- Nick Bastin +- Nathaniel Manista : suspicious lambda checking +- Mike Frysinger +- Maksym Humetskyi (mhumetskyi) + * Fixed ignored empty functions by similarities checker with "ignore-signatures" option enabled + * Ignore function decorators signatures as well by similarities checker with "ignore-signatures" option enabled + * Ignore class methods and nested functions signatures as well by similarities checker with "ignore-signatures" option enabled +- Lucas Cimon +- Kylian +- Konstantin Manna +- Kai Mueller <15907922+kasium@users.noreply.github.com> (kasium) +- Joshua Cannon +- John Leach +- James Morgensen : ignored-modules option applies to import errors. +- Jaehoon Hwang (jaehoonhwang) +- Ganden Schaffner +- Frost Ming (frostming) +- Federico Bond +- Erik Wright +- Erik Eriksson : Added overlapping-except error check. +- Dan Hemberger <846186+hemberger@users.noreply.github.com> +- Chris Rebert : unidiomatic-typecheck. +- Aurelien Campeas +- Alexander Pervakov +- Alain Leufroy +- xmo-odoo +- root@clnstor.am.local +- grizzly.nyo@gmail.com +- craig-sh +- bernie gray +- Yilei "Dolee" Yang +- Wes Turner (Google): added new check 'inconsistent-quotes' +- Tyler Thieding +- Tobias Hernstig <30827238+thernstig@users.noreply.github.com> +- Thomas Grainger +- Simu Toni +- Sergei Lebedev <185856+superbobry@users.noreply.github.com> (superbobry) +- Scott Worley +- Rémi Cardona +- Raphael Gaschignard +- Ram Rachum (cool-RR) +- Radostin Stoyanov +- Paul Renvoisé +- PHeanEX +- Omega Weapon +- Nikolai Kristiansen +- Nick Pesce +- Nathan Marrow +- Mikhail Fesenko +- Matthew Suozzo +- Matthew Beckers <17108752+mattlbeck@users.noreply.github.com> (mattlbeck) +- Mark Roman Miller : fix inline defs in too-many-statements +- Mads Kiilerich +- Maarten ter Huurne +- Lefteris Karapetsas +- LCD 47 +- Justin Li (justinnhli) +- John Kirkham +- Jens H. Nielsen +- Ioana Tagirta : fix bad thread instantiation check +- Ikraduya Edian : Added new checks 'consider-using-generator' and 'use-a-generator'. +- Hugues Bruant +- Harut +- Grygorii Iermolenko +- Gabriel R. Sezefredo : Fixed "exception-escape" false positive with generators +- Filipe Brandenburger +- Fantix King (UChicago) +- Elias Dorneles : minor adjust to config defaults and docs +- Derek Harland +- David Pursehouse +- Daniel Miller +- Chris Murray +- Chris Lamb +- Charles Hebert +- Carli Freudenberg (CarliJoy) + * Fixed issue 5281, added Unicode checker + * Improve non-ascii-name checker +- Buck Golemon +- Brian Shaginaw : prevent error on exception check for functions +- Benny Mueller +- Ben James +- Ben Green +- Batuhan Taskaya +- Alexander Kapshuna +- Adam Parkin +- 谭九鼎 <109224573@qq.com> +- Łukasz Sznuk +- y2kbugger +- vinnyrose +- ttenhoeve-aa +- thinwybk +- syutbai +- sdet_liang +- pyves@crater.logilab.fr +- paschich +- oittaa <8972248+oittaa@users.noreply.github.com> +- moxian +- mar-chi-pan +- ludal@logilab.fr +- lrjball <50599110+lrjball@users.noreply.github.com> +- laike9m +- jpkotta@shannon +- jaydesl <35102795+jaydesl@users.noreply.github.com> +- jab +- glmdgrielson <32415403+glmdgrielson@users.noreply.github.com> +- glegoux +- gaurikholkar +- flyingbot91 +- fahhem +- fadedDexofan +- danields +- cosven +- cordis-dev +- bluesheeptoken +- anatoly techtonik +- amdev@AMDEV-WS01.cisco.com +- agutole +- Zeckie <49095968+Zeckie@users.noreply.github.com> +- Zeb Nicholls + * Made W9011 compatible with 'of' syntax in return types +- Yuval Langer +- Yury Gribov +- Yuri Bochkarev : Added epytext support to docparams extension. +- Youngsoo Sung +- Yory <39745367+yory8@users.noreply.github.com> (yory8) +- Yoichi Nakayama +- Yeting Li (yetingli) +- Yannack +- Yann Dirson +- Yang Yang +- Xi Shen +- Will Shanks +- Viorel Știrbu : intern-builtin warning. +- Victor Jiajunsu <16359131+jiajunsu@users.noreply.github.com> +- Trevor Bekolay + * Added --list-msgs-enabled command +- Tomer Chachamu : simplifiable-if-expression +- Tomasz Magulski +- Tim Hatch +- Tim Gates +- Tanvi Moharir <74228962+tanvimoharir@users.noreply.github.com>: Fix for invalid toml config +- T.Rzepka +- Svetoslav Neykov +- Stéphane Wirtel : nonlocal-without-binding +- Stephen Longofono <8992396+SLongofono@users.noreply.github.com> +- Stanislav Levin +- Sorin Sbarnea +- Slavfox +- Skip Montanaro +- Shiv Venkatasubrahmanyam +- Sebastian Müller +- Saugat Pachhai +- Sasha Bagan +- Sardorbek Imomaliev +- Santiago Castro +- Sandro Tosi : Debian packaging +- Samuel Freilich (sfreilich) +- Samuel FORESTIER +- Sam Vermeiren <88253337+PaaEl@users.noreply.github.com> (PaaEl) +- Ryan McGuire +- Ry4an Brase +- Ruro +- Roman Ivanov +- Robin Tweedie <70587124+robin-wayve@users.noreply.github.com> +- Robert Schweizer +- Reverb Chu +- Renat Galimov +- Rebecca Turner (9999years) +- Randall Leeds +- Ramiro Leal-Cavazos (ramiro050): Fixed bug preventing pylint from working with emacs tramp +- Qwiddle13 <32040075+Qwiddle13@users.noreply.github.com> +- Quentin Young +- Petr Pulc : require whitespace around annotations +- Peter Dawyndt +- Peter Bittner +- Peter Aronoff +- Paul Cochrane +- Patrik +- Pascal Corpet +- Pablo Galindo Salgado + * Fix false positive 'Non-iterable value' with async comprehensions. +- Oisín Moran +- Obscuron +- Noam Yorav-Raphael +- Nir Soffer +- Niko Wenselowski +- Nikita Sobolev +- Nick Smith +- Ned Batchelder +- Natalie Serebryakova +- Mitchell Young : minor adjustment to docparams +- Mitar +- Mike Fiedler (miketheman) +- Mike Bryant +- Michka Popoff +- Michal Vasilek +- Michael Scott Cuthbert +- Michael Kefeder +- Michael Hudson-Doyle +- Michael Giuffrida +- Melvin Hazeleger <31448155+melvio@users.noreply.github.com> (melvio) +- Matěj Grabovský +- Matthijs Blom <19817960+MatthijsBlom@users.noreply.github.com> +- Matej Marušák +- Markus Siebenhaar <41283549+siehar@users.noreply.github.com> +- Marco Edward Gorelli : Documented Jupyter integration +- Marcin Kurczewski (rr-) +- Maik Röder +- Louis Sautier +- Lorena Buciu <46202743+lorena-b@users.noreply.github.com> (lorena-b) +- Logan Miller <14319179+komodo472@users.noreply.github.com> (komodo472) +- Kári Tristan Helgason +- Kurian Benoy <70306694+kurianbenoy-aot@users.noreply.github.com> +- Krzysztof Czapla +- Kraig Brockschmidt +- Kound +- Kosarchuk Sergey +- Konrad Weihmann <46938494+priv-kweihmann@users.noreply.github.com> +- Kian Meng, Ang +- Kevin Phillips +- Kevin Jing Qiu +- Kayran Schmidt <59456929+yumasheta@users.noreply.github.com> +- Jürgen Hermann +- Jérome Perrin (perrinjerome) +- Josselin Feist +- Jonathan Kotta +- John Paraskevopoulos : add 'differing-param-doc' and 'differing-type-doc' +- John McGehee +- John Gabriele +- John Belmonte +- Joffrey Mander +- Jochen Preusche (iilei) +- Jeroen Seegers (jeroenseegers) + * Fixed `toml` dependency issue +- Jeremy Fleischman (jfly) +- Jason Owen +- Jared Garst +- Jared Deckard +- Janne Rönkkö +- James Sinclair (irgeek) +- James M. Allen +- James Lingard +- James Broadhead +- Jakob Normark +- Jake Lishman (jakelishman) +- Jacques Kvam +- Jace Browning : updated default report format with clickable paths +- JT Olds +- Hayden Richards <62866982+SupImDos@users.noreply.github.com> (SupImDos) + * Fixed "no-self-use" for async methods + * Fixed "docparams" extension for async functions and methods +- Harshil <37377066+harshil21@users.noreply.github.com> (harshil21) +- Grant Welch +- Giuseppe Valente +- Gary Tyler McLeod +- Felix von Drigalski (felixvd) +- Fabrice Douchant +- Fabio Natali +- Fabian Damken +- Eric Froemling +- Emmanuel Chaudron +- Elizabeth Bott <52465744+elizabethbott@users.noreply.github.com> +- Eisuke Kawashima (e-kwsm) +- Edgemaster +- Drew Risinger +- Dr. Nick +- Don Jayamanne +- Dmytro Kyrychuk +- Denis Laxalde +- David Cain +- Danny Hermes +- Daniele Procida +- Daniela Plascencia +- Daniel R. Neal (danrneal) +- Daniel Draper +- Daniel Dorani (doranid) +- Daniel Brookman <53625739+dbrookman@users.noreply.github.com> +- Dan Garrette +- Damien Nozay +- Craig Citro +- Clément Pit-Claudel +- Christopher Zurcher +- Carl Crowder : don't evaluate the value of arguments for 'dangerous-default-value' +- Carey Metcalfe : demoted `try-except-raise` from error to warning +- Cameron Olechowski +- Calin Don +- Caio Carrara +- C.A.M. Gerlach +- Bruno P. Kinoshita +- Brian C. Lane +- Brandon W Maister +- BioGeek +- Benjamin Graham +- Benedikt Morbach +- Banjamin Freeman +- Athos Ribeiro : Fixed dict-keys-not-iterating false positive for inverse containment checks +- Arun Persaud +- Arthur Lutz +- Antonio Ossa +- Anthony VEREZ +- Anthony Tan +- Anthony Foglia (Google): Added simple string slots check. +- Anentropic +- Andy Palmer <25123779+ninezerozeronine@users.noreply.github.com> +- Andrzej Klajnert +- Andrew Howe +- Andres Perez Hortal +- Alok Singh <8325708+alok@users.noreply.github.com> +- Allan Chandler <95424144+allanc65@users.noreply.github.com> (allanc65) + * Fixed issue 5452, false positive missing-param-doc for multi-line Google-style params +- Alex Jurkiewicz +- Alex Hearn +- Alan Evangelista +- Alan Chan +- Aivar Annamaa +- Aidan Haase <44787650+haasea@users.noreply.github.com> +- Ahirnish Pareek : 'keyword-arg-before-var-arg' check +- Adrian Chirieac +- Aditya Gupta (adityagupta1089) + * Added ignore_signatures to duplicate checker +- Adam Dangoor + + +Co-Author +--------- +The following persons were credited manually but did not commit themselves +under this name, or we did not manage to find their commits in the history. + +- Agustin Toledo +- Amaury Forgeot d'Arc: check names imported from a module exists in the module +- Anthony Tan +- Axel Muller +- Benjamin Niemann: allow block level enabling/disabling of messages +- Bernard Nauwelaerts +- Bill Wendling +- Brian van den Broek: windows installation documentation +- Craig Henriques +- D. Alphus (Alphadelta14) +- Daniil Kharkov +- Eero Vuojolahti +- Fabio Zadrozny +- Gauthier Sebaux +- James DesLauriers +- manderj +- Mirko Friedenhagen +- Nicholas Smith +- Nuzula H. Yudaka (Nuzhuka) +- Pek Chhan +- Peter Hammond +- Pierre Rouleau +- Richard Goodman: simplifiable-if-expression (with Tomer Chachamu) +- Sebastian Ulrich +- Takashi Hirashima +- Thomas Snowden: fix missing-docstring for inner functions +- Wolfgang Grafen +- Yannick Brehon diff --git a/ChangeLog b/ChangeLog index 4dd010abbf..32c5122f04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,12 +2,13 @@ Pylint's ChangeLog ------------------ -What's New in Pylint 2.13.0? +What's New in Pylint 2.14.0? ============================ Release date: TBA .. - Put new features here and also in 'doc/whatsnew/2.13.rst' + Put new features here and also in 'doc/whatsnew/2.14.rst' + .. @@ -15,17 +16,682 @@ Release date: TBA (Ie. not necessarily at the end) -What's New in Pylint 2.12.3? +What's New in Pylint 2.13.6? ============================ Release date: TBA -.. - Put bug fixes that should not wait for a new minor version here -.. - Insert your changelog randomly, it will reduce merge conflicts - (Ie. not necessarily at the end) +What's New in Pylint 2.13.5? +============================ +Release date: 2022-04-06 + +* Fix false positive regression in 2.13.0 for ``used-before-assignment`` for + homonyms between variable assignments in try/except blocks and variables in + subscripts in comprehensions. + + Closes #6069 + Closes #6136 + +* ``lru-cache-decorating-method`` has been renamed to ``cache-max-size-none`` and + will only be emitted when ``maxsize`` is ``None``. + + Closes #6180 + +* Fix false positive for ``unused-import`` when disabling both ``used-before-assignment`` and ``undefined-variable``. + + Closes #6089 + +* Narrow the scope of the ``unnecessary-ellipsis`` checker to: + * functions & classes which contain both a docstring and an ellipsis. + * A body which contains an ellipsis ``nodes.Expr`` node & at least one other statement. + +* Fix false positive for ``used-before-assignment`` for assignments taking place via + nonlocal declarations after an earlier type annotation. + + Closes #5394 + +* Fix crash for ``redefined-slots-in-subclass`` when the type of the slot is not a const or a string. + + Closes #6100 + +* Only raise ``not-callable`` when all the inferred values of a property are not callable. + + Closes #5931 + + +* Fix a false negative for ``subclassed-final-class`` when a set of other messages were disabled. + + +What's New in Pylint 2.13.4? +============================ +Release date: 2022-03-31 + +* Fix false positive regression in 2.13.0 for ``used-before-assignment`` for + homonyms between variable assignments in try/except blocks and variables in + a comprehension's filter. + + Closes #6035 + +* Include ``testing_pylintrc`` in source and wheel distributions. + + Closes #6028 + +* Fix crash in ``super-init-not-called`` checker when using ``ctypes.Union``. + + Closes #6027 + + +* Fix crash for ``unneccessary-ellipsis`` checker when an ellipsis is used inside of a container or a lambda expression. + + Closes #6036 + Closes #6037 + Closes #6048 + + +What's New in Pylint 2.13.3? +============================ +Release date: 2022-03-29 + +* Fix false positive for ``unnecessary-ellipsis`` when using an ellipsis as a default argument. + + Closes #5973 + +* Fix crash involving unbalanced tuple unpacking. + + Closes #5998 + +* Fix false positive for 'nonexistent-operator' when repeated '-' are + separated (e.g. by parens). + + Closes #5769 + + +What's New in Pylint 2.13.2? +============================ +Release date: 2022-03-27 + +* Fix crash when subclassing a ``namedtuple``. + + Closes #5982 + +* Fix false positive for ``superfluous-parens`` for patterns like + "return (a or b) in iterable". + + Closes #5803 + +* Fix a false negative regression in 2.13.0 where ``protected-access`` was not + raised on functions. + + Fixes #5989 + +* Better error messages in case of crash if pylint can't write the issue template. + + Refer to #5987 + + +What's New in Pylint 2.13.1? +============================ +Release date: 2022-03-26 + +* Fix a regression in 2.13.0 where ``used-before-assignment`` was emitted for + the usage of a nonlocal in a try block. + + Fixes #5965 + +* Avoid emitting ``raising-bad-type`` when there is inference ambiguity on + the variable being raised. + + Closes #2793 + +* Loosen TypeVar default name pattern a bit to allow names with multiple uppercase + characters. E.g. ``HVACModeT`` or ``IPAddressT``. + + Closes #5981 + +* Fixed false positive for ``unused-argument`` when a ``nonlocal`` name is used + in a nested function that is returned without being called by its parent. + + Closes #5187 + +* Fix program crash for ``modified_iterating-list/set/dict`` when the list/dict/set + being iterated through is a function call. + + Closes #5969 + +* Don't emit ``broken-noreturn`` and ``broken-collections-callable`` errors + inside ``if TYPE_CHECKING`` blocks. + + +What's New in Pylint 2.13.0? +============================ +Release date: 2022-03-24 + +* Add missing dunder methods to ``unexpected-special-method-signature`` check. + +* No longer emit ``no-member`` in for loops that reference ``self`` if the binary operation that + started the for loop uses a ``self`` that is encapsulated in tuples or lists. + + Ref PyCQA/astroid#1360 + Closes #4826 + +* Output better error message if unsupported file formats are used with ``pyreverse``. + + Closes #5950 + +* Fix pyreverse diagrams type hinting for classmethods and staticmethods. + +* Fix pyreverse diagrams type hinting for methods returning None. + +* Fix matching ``--notes`` options that end in a non-word character. + + Closes #5840 + +* Updated the position of messages for class and function defintions to no longer cover + the complete definition. Only the ``def`` or ``class`` + the name of the class/function + are covered. + + Closes #5466 + +* ``using-f-string-in-unsupported-version`` and ``using-final-decorator-in-unsupported-version`` msgids + were renamed from ``W1601`` and ``W1602`` to ``W2601`` and ``W2602``. Disabling using these msgids will break. + This is done in order to restore consistency with the already existing msgids for ``apply-builtin`` and + ``basestring-builtin`` from the now deleted python 3K+ checker. There is now a check that we're not using + existing msgids or symbols from deleted checkers. + + Closes #5729 + +* The line numbering for messages related to function arguments is now more accurate. This can + require some message disables to be relocated to updated positions. + +* Add ``--recursive`` option to allow recursive discovery of all modules and packages in subtree. Running pylint with + ``--recursive=y`` option will check all discovered ``.py`` files and packages found inside subtree of directory provided + as parameter to pylint. + + Closes #352 + +* Add ``modified-iterating-list``, ``modified-iterating-dict`` and ``modified-iterating-set``, + emitted when items are added to or removed from respectively a list, dictionary or + set being iterated through. + + Closes #5348 + +* Fix false-negative for ``assignment-from-none`` checker using list.sort() method. + + closes #5722 + +* New extension ``import-private-name``: indicate imports of external private packages + and objects (prefixed with ``_``). It can be loaded using ``load-plugins=pylint.extensions.private_import``. + + Closes #5463 + +* Fixed crash from ``arguments-differ`` and ``arguments-renamed`` when methods were + defined outside the top level of a class. + + Closes #5648 + +* Removed the deprecated ``check_docs`` extension. You can use the ``docparams`` checker + to get the checks previously included in ``check_docs``. + + Closes #5322 + +* Added a ``testutil`` extra require to the packaging, as ``gitpython`` should not be a dependency + all the time but is still required to use the primer helper code in ``pylint.testutil``. You can + install it with ``pip install pylint[testutil]``. + + Closes #5486 + +* Reinstated checks from the python3 checker that are still useful for python 3 + (``eq-without-hash``). This is now in the ``pylint.extensions.eq_without_hash`` optional + extension. + + Closes #5025 + +* Fixed an issue where ``ungrouped-imports`` could not be disabled without raising + ``useless-suppression``. + + Ref #2366 + +* Added several checkers to deal with unicode security issues + (see `Trojan Sources `_ and + `PEP 672 `_ for details) that also + concern the readability of the code. In detail the following checks were added: + + * ``bad-file-encoding`` checks that the file is encoded in UTF-8 as suggested by + `PEP8 `_. + UTF-16 and UTF-32 are `not supported by Python `_ + at the moment. If this ever changes + ``invalid-unicode-codec`` checks that they aren't used, to allow for backwards + compatibility. + + * ``bidirectional-unicode`` checks for bidirectional unicode characters that + could make code execution different than what the user expects. + + * ``invalid-character-backspace``, ``invalid-character-carriage-return``, + ``invalid-character-sub``, ``invalid-character-esc``, + ``invalid-character-zero-width-space`` and ``invalid-character-nul`` + to check for possibly harmful unescaped characters. + + Closes #5281 + +* Use the ``tomli`` package instead of ``toml`` to parse ``.toml`` files. + + Closes #5885 + +* Fix false positive - Allow unpacking of ``self`` in a subclass of ``typing.NamedTuple``. + + Closes #5312 + +* Fixed false negative ``unpacking-non-sequence`` when value is an empty list. + + Closes #5707 + +* Better warning messages for useless else or elif when a function returns early. + + Closes #5614 + +* Fixed false positive ``consider-using-dict-comprehension`` when creating a dict + using a list of tuples where key AND value vary depending on the same condition. + + Closes #5588 + +* Fixed false positive for ``global-variable-undefined`` when ``global`` is used with a class name + + Closes #3088 + +* Fixed false positive for ``unused-variable`` when a ``nonlocal`` name is assigned as part of a multi-name assignment. + + Closes #3781 + +* Fixed a crash in ``unspecified-encoding`` checker when providing ``None`` + to the ``mode`` argument of an ``open()`` call. + + Closes #5731 + +* Fixed a crash involving a ``NewType`` named with an f-string. + + Closes #5770 + Ref PyCQA/astroid#1400 + +* Improved ``bad-open-mode`` message when providing ``None`` to the ``mode`` + argument of an ``open()`` call. + + Closes #5733 + +* Added ``lru-cache-decorating-method`` checker with checks for the use of ``functools.lru_cache`` + on class methods. This is unrecommended as it creates memory leaks by never letting the instance + getting garbage collected. + + Closes #5670 + +* Fixed crash with recursion error for inference of class attributes that referenced + the class itself. + + Closes #5408 + Ref PyCQA/astroid#1392 + +* Fixed false positive for ``unused-argument`` when a method overridden in a subclass + does nothing with the value of a keyword-only argument. + + Closes #5771 + Ref PyCQA/astroid#1382 + +* The issue template for crashes is now created for crashes which were previously not covered + by this mechanism. + + Closes #5668 + +* Rewrote checker for ``non-ascii-name``. + It now ensures __all__ Python names are ASCII and also properly + checks the names of imports (``non-ascii-module-import``) as + well as file names (``non-ascii-file-name``) and emits their respective new warnings. + + Non ASCII characters could be homoglyphs (look alike characters) and hard to + enter on a non specialized keyboard. + See `Confusable Characters in PEP 672 `_ + +* When run in parallel mode ``pylint`` now pickles the data passed to subprocesses with + the ``dill`` package. The ``dill`` package has therefore been added as a dependency. + +* An astroid issue where symlinks were not being taken into account + was fixed + + Closes #1470 + Closes #3499 + Closes #4302 + Closes #4798 + Closes #5081 + +* Fix a crash in ``unused-private-member`` checker when analyzing code using + ``type(self)`` in bound methods. + + Closes #5569 + +* Optimize parsing of long lines when ``missing-final-newline`` is enabled. + + Closes #5724 + +* Fix false positives for ``used-before-assignment`` from using named + expressions in a ternary operator test and using that expression as + a call argument. + + Closes #5177, #5212 + +* Fix false positive for ``undefined-variable`` when ``namedtuple`` class + attributes are used as return annotations. + + Closes #5568 + +* Fix false negative for ``undefined-variable`` and related variable messages + when the same undefined variable is used as a type annotation and is + accessed multiple times, or is used as a default argument to a function. + + Closes #5399 + +* Pyreverse - add output in mermaidjs format + +* Emit ``used-before-assignment`` instead of ``undefined-variable`` when attempting + to access unused type annotations. + + Closes #5713 + +* Added confidence level ``CONTROL_FLOW`` for warnings relying on assumptions + about control flow. + +* ``used-before-assignment`` now considers that assignments in a try block + may not have occurred when the except or finally blocks are executed. + + Closes #85, #2615 + +* Fixed false negative for ``used-before-assignment`` when a conditional + or context manager intervened before the try statement that suggested + it might fail. + + Closes #4045 + +* Fixed false negative for ``used-before-assignment`` in finally blocks + if an except handler did not define the assignment that might have failed + in the try block. + +* Fixed extremely long processing of long lines with comma's. + + Closes #5483 + +* Fixed crash on properties and inherited class methods when comparing them for + equality against an empty dict. + + Closes #5646 + +* Fixed a false positive for ``assigning-non-slot`` when the slotted class + defined ``__setattr__``. + + Closes #3793 + +* Fixed a false positive for ``invalid-class-object`` when the object + being assigned to the ``__class__`` attribute is uninferable. + +* Fixed false positive for ``used-before-assignment`` with self-referential type + annotation in conditional statements within class methods. + + Closes #5499 + +* Add checker ``redefined-slots-in-subclass``: Emitted when a slot is redefined in a subclass. + + Closes #5617 + +* Fixed false positive for ``global-variable-not-assigned`` when the ``del`` statement is used + + Closes #5333 + +* By default, pylint does no longer take files starting with ``.#`` into account. Those are + considered `emacs file locks`. See + https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Locks.html. + This behavior can be reverted by redefining the ``ignore-patterns`` option. + + Closes #367 + +* Fixed a false positive for ``used-before-assignment`` when a named expression + appears as the first value in a container. + + Closes #5112 + +* ``used-before-assignment`` now assumes that assignments in except blocks + may not have occurred and warns accordingly. + + Closes #4761 + +* When evaluating statements after an except block, ``used-before-assignment`` + assumes that assignments in the except blocks took place if the + corresponding try block contained a return statement. + + Closes #5500 + +* Fixed a false negative for ``used-before-assignment`` when some but not all + except handlers defined a name relied upon after an except block when the + corresponding try block contained a return statement. + + Closes #5524 + +* When evaluating statements in the ``else`` clause of a loop, ``used-before-assignment`` + assumes that assignments in the except blocks took place if the + except handlers constituted the only ways for the loop to finish without + breaking early. + + Closes #5683 + +* ``used-before-assignment`` now checks names in try blocks. + +* Fixed false positive with ``used-before-assignment`` for assignment expressions + in lambda statements. + + Closes #5360, #3877 + +* Fixed a false positive (affecting unreleased development) for + ``used-before-assignment`` involving homonyms between filtered comprehensions + and assignments in except blocks. + + Closes #5586 + +* Fixed crash with slots assignments and annotated assignments. + + Closes #5479 + +* Fixed crash on list comprehensions that used ``type`` as inner variable name. + + Closes #5461 + +* Fixed crash in ``use-maxsplit-arg`` checker when providing the ``sep`` argument + to ``str.split()`` by keyword. + + Closes #5737 + +* Fix false positive for ``unused-variable`` for a comprehension variable matching + an outer scope type annotation. + + Closes #5326 + +* Fix false negative for ``undefined-variable`` for a variable used multiple times + in a comprehension matching an unused outer scope type annotation. + + Closes #5654 + +* Some files in ``pylint.testutils`` were deprecated. In the future imports should be done from the + ``pylint.testutils.functional`` namespace directly. + +* Fixed false positives for ``no-value-for-parameter`` with variadic + positional arguments. + + Closes #5416 + +* ``safe_infer`` no longer makes an inference when given two function + definitions with differing numbers of arguments. + + Closes #3675 + +* Fix ``comparison-with-callable`` false positive for callables that raise, such + as typing constants. + + Closes #5557 + +* Fixed a crash on ``__init__`` nodes when the attribute was previously uninferable due to a cache + limit size. This limit can be hit when the inheritance pattern of a class (and therefore of the ``__init__`` attribute) is very large. + + Closes #5679 + +* Fix false positive for ``used-before-assignment`` from a class definition + nested under a function subclassing a class defined outside the function. + + Closes #4590 + +* Fix ``unnecessary_dict_index_lookup`` false positive when deleting a dictionary's entry. + + Closes #4716 + +* Fix false positive for ``used-before-assignment`` when an except handler + shares a name with a test in a filtered comprehension. + + Closes #5817 + +* Fix crash in ``unnecessary-dict-index-lookup`` checker if the output of + ``items()`` is assigned to a 1-tuple. + + Closes #5504 + +* When invoking ``pylint``, ``epylint``, ``symilar`` or ``pyreverse`` by importing them in a python file + you can now pass an ``argv`` keyword besides patching ``sys.argv``. + + Closes #5320 + +* The ``PyLinter`` class will now be initialized with a ``TextReporter`` + as its reporter if none is provided. + +* Fix ``super-init-not-called`` when parent or ``self`` is a ``Protocol`` + + Closes #4790 + +* Fix false positive ``not-callable`` with attributes that alias ``NamedTuple`` + + Partially closes #1730 + +* Emit ``redefined-outer-name`` when a nested except handler shadows an outer one. + + Closes #4434 + Closes #5370 + +* Fix false positive ``super-init-not-called`` for classes that inherit their ``init`` from + a parent. + + Closes #4941 + +* ``encoding`` can now be supplied as a positional argument to calls that open + files without triggering ``unspecified-encoding``. + + Closes #5638 + +* Fatal errors now emit a score of 0.0 regardless of whether the linted module + contained any statements + + Closes #5451 + +* ``fatal`` was added to the variables permitted in score evaluation expressions. + +* The default score evaluation now uses a floor of 0. + + Closes #2399 + +* Fix false negative for ``consider-iterating-dictionary`` during membership checks encapsulated in iterables + or ``not in`` checks + + Closes #5323 + +* Fixed crash on uninferable decorators on Python 3.6 and 3.7 + +* Add checker ``unnecessary-ellipsis``: Emitted when the ellipsis constant is used unnecessarily. + + Closes #5460 + +* Disable checker ``bad-docstring-quotes`` for Python <= 3.7, because in these versions the line + numbers for decorated functions and classes are not reliable which interferes with the checker. + + Closes #3077 + +* Fixed incorrect classification of Numpy-style docstring as Google-style docstring for + docstrings with property setter documentation. + Docstring classification is now based on the highest amount of matched sections instead + of the order in which the docstring styles were tried. + +* Fixed detection of ``arguments-differ`` when superclass static + methods lacked a ``@staticmethod`` decorator. + + Closes #5371 + +* ``TypingChecker`` + + * Added new check ``broken-noreturn`` to detect broken uses of ``typing.NoReturn`` + if ``py-version`` is set to Python ``3.7.1`` or below. + https://bugs.python.org/issue34921 + + * Added new check ``broken-collections-callable`` to detect broken uses of ``collections.abc.Callable`` + if ``py-version`` is set to Python ``3.9.1`` or below. + https://bugs.python.org/issue42965 + +* The ``testutils`` for unittests now accept ``end_lineno`` and ``end_column``. Tests + without these will trigger a ``DeprecationWarning``. + +* ``arguments-differ`` will no longer complain about method redefinitions with extra parameters + that have default values. + + Closes #1556, #5338 + +* Fixed false positive ``unexpected-keyword-arg`` for decorators. + + Closes #258 + +* Importing the deprecated stdlib module ``xml.etree.cElementTree`` now emits ``deprecated_module``. + + Closes #5862 + +* Disables for ``deprecated-module`` and similar warnings for stdlib features deprecated + in newer versions of Python no longer raise ``useless-suppression`` when linting with + older Python interpreters where those features are not yet deprecated. + +* Importing the deprecated stdlib module ``distutils`` now emits ``deprecated_module`` on Python 3.10+. + +* ``missing-raises-doc`` will now check the class hierarchy of the raised exceptions + + .. code-block:: python + + def my_function() + """My function. + + Raises: + Exception: if something fails + """ + raise ValueError + + Closes #4955 + +* Allow disabling ``duplicate-code`` with a disable comment when running through + pylint. + + Closes #214 + +* Improve ``invalid-name`` check for ``TypeVar`` names. + The accepted pattern can be customized with ``--typevar-rgx``. + + Closes #3401 + +* Added new checker ``typevar-name-missing-variance``. Emitted when a covariant + or contravariant ``TypeVar`` does not end with ``_co`` or ``_contra`` respectively or + when a ``TypeVar`` is not either but has a suffix. + +* Allow usage of mccabe 0.7.x release + + Closes #5878 + +* Fix ``unused-private-member`` false positive when accessing private methods through ``property``. + + Closes #4756 What's New in Pylint 2.12.2? @@ -124,8 +790,8 @@ Release date: 2021-11-24 output files without these will trigger a ``DeprecationWarning``. Expected output files can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command. -* The functional ``testutils`` now correctly check the distinction betweeen ``HIGH`` and - ``UNDEFINED`` confidence. Expected output files without defiend ``confidence`` levels will now +* The functional ``testutils`` now correctly check the distinction between ``HIGH`` and + ``UNDEFINED`` confidence. Expected output files without defined ``confidence`` levels will now trigger a ``DeprecationWarning``. Expected output files can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command. @@ -146,6 +812,7 @@ Release date: 2021-11-24 * Properly identify parameters with no documentation and add new message called ``missing-any-param-doc`` Closes #3799 + * Add checkers ``overridden-final-method`` & ``subclassed-final-class`` Closes #3197 @@ -248,7 +915,7 @@ Release date: 2021-11-24 Closes #5194 -* Fix double emitting of ``not-callable`` on inferrable ``properties`` +* Fix double emitting of ``not-callable`` on inferable ``properties`` Closes #4426 @@ -412,7 +1079,7 @@ Release date: 2021-09-16 Closes #4776 -* Added ``py-version`` config key (if ``[MASTER]`` section). Used for version dependant checks. +* Added ``py-version`` config key (if ``[MASTER]`` section). Used for version dependent checks. Will default to whatever Python version pylint is executed with. * ``CodeStyleChecker`` @@ -431,7 +1098,7 @@ Release date: 2021-09-16 Closes #4751 -* https is now prefered in the documentation and http://pylint.pycqa.org correctly redirect to https://pylint.pycqa.org +* https is now preferred in the documentation and http://pylint.pycqa.org correctly redirect to https://pylint.pycqa.org Closes #3802 @@ -645,7 +1312,7 @@ Release date: 2021-08-20 * Fixed bug with ``cell-var-from-loop`` checker: it no longer has false negatives when both ``unused-variable`` and ``used-before-assignment`` are disabled. -* Fix false postive for ``invalid-all-format`` if the list or tuple builtin functions are used +* Fix false positive for ``invalid-all-format`` if the list or tuple builtin functions are used Closes #4711 @@ -1373,7 +2040,7 @@ Release date: 2021-02-21 Close #3862 -* Fix linter multiprocessing pool shutdown (triggered warnings when runned in parallels with other pytest plugins) +* Fix linter multiprocessing pool shutdown (triggered warnings when ran in parallels with other pytest plugins) Closes #3779 @@ -1400,7 +2067,7 @@ Release date: 2021-02-21 Closes #3468 -* Fix ``useless-super-delegation`` false positive when default keyword argument is a dictionnary. +* Fix ``useless-super-delegation`` false positive when default keyword argument is a dictionary. Close #3773 @@ -3401,7 +4068,7 @@ Release date: 2017-04-13 This message is emitted when pylint finds an one-element tuple, created by a stray comma. This can suggest a potential problem in the - code and it is recommended to use parantheses in order to emphasise the + code and it is recommended to use parentheses in order to emphasise the creation of a tuple, rather than relying on the comma itself. * Don't emit not-callable for instances with unknown bases. @@ -4101,7 +4768,7 @@ Release date: 2015-11-29 directory 'test/extensions' and documentation file 'doc/extensions.rst'. * Added new checker 'extensions.check_docs' that verifies parameter - documention in Sphinx, Google, and Numpy style. + documentation in Sphinx, Google, and Numpy style. * Detect undefined variable cases, where the "definition" of an undefined variable was in del statement. Instead of emitting used-before-assignment, @@ -4197,7 +4864,7 @@ Release date: 2015-11-29 two a binary arithmetic operation is executed between two objects which don't support it (a number plus a string for instance). This is currently disabled, since the it exhibits way too many false - positives, but it will be reenabled as soon as possible. + positives, but it will be re-enabled as soon as possible. * New imported features from astroid into pyreverse: pyreverse.inspector.Project, pyreverse.inspector.project_from_files and pyreverse.inspector.interfaces. @@ -5172,7 +5839,7 @@ Release date: 2012-10-05 * #105337: allow custom reporter in output-format (patch by Kevin Jing Qiu) - * #104420: check for protocol completness and avoid false R0903 + * #104420: check for protocol completeness and avoid false R0903 (patch by Peter Hammond) * #100654: fix grammatical error for W0332 message (using 'l' as @@ -5200,7 +5867,7 @@ Release date: 2012-07-17 except handler contains a tuple of names instead of a single name. (patch by tmarek@google.com) - * #7394: W0212 (access to protected member) not emitted on assigments + * #7394: W0212 (access to protected member) not emitted on assignments (patch by lothiraldan@gmail.com) * #18772; no prototype consistency check for mangled methods (patch by @@ -5795,7 +6462,7 @@ Release date: 2006-03-06 - the C0101 check with its min-name-length option has been removed (this can be specified in the regxp after all...) - W0103 and W0121 are now handled by the variables checker - (W0103 is now W0603 and W0604 has been splitted into different messages) + (W0103 is now W0603 and W0604 has been split into different messages) - W0131 and W0132 messages have been reclassified to C0111 and C0112 respectively - new W0104 message on statement without effect @@ -5832,7 +6499,7 @@ Release date: 2006-01-10 or the default ~/.pylintrc or /etc/pylintrc * fixed W0706 (Identifier used to raise an exception is assigned...) - false positive and reraising a catched exception instance + false positive and reraising a caught exception instance * fixed E0611 (No name get in module blabla) false positive when accessing to a class'__dict__ diff --git a/Dockerfile b/Dockerfile index aafe62a6ae..2667145da8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9.0-alpine3.12 +FROM python:3.10.0-alpine3.15 COPY ./ /tmp/build WORKDIR /tmp/build diff --git a/README.rst b/README.rst index 32871e01cc..4967a00f9e 100644 --- a/README.rst +++ b/README.rst @@ -149,7 +149,27 @@ Do not forget to clone astroid_ and install the last version:: cd astroid python3 -m pip install -e . +Show your usage +----------------- +You can place this badge in your README to let others know your project uses pylint. + + .. image:: https://img.shields.io/badge/linting-pylint-yellowgreen + :target: https://github.com/PyCQA/pylint + +Use the badge in your project's README.md (or any other Markdown file):: + + [![linting: pylint](https://img.shields.io/badge/linting-pylint-yellowgreen)](https://github.com/PyCQA/pylint) + +Use the badge in your project's README.rst (or any other rst file):: + + .. image:: https://img.shields.io/badge/linting-pylint-yellowgreen + :target: https://github.com/PyCQA/pylint + + +If you use GitHub Actions, and one of your CI workflows begins with "name: pylint", you +can use GitHub's `workflow status badges `_ +to show an up-to-date indication of whether pushes to your default branch pass pylint. For more detailed information, check the documentation. .. _here: https://pylint.pycqa.org/en/latest/user_guide/installation.html diff --git a/doc/Makefile b/doc/Makefile index 9d8ba83356..39266a91ea 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -150,6 +150,8 @@ features.rst: $(shell find ../pylint/checkers -type f -regex '.*\.py') rm -f features.rst PYTHONPATH=$(PYTHONPATH) $(PYTHON) ./exts/pylint_features.py +messages: $(PYTHONPATH) $(PYTHON) ./exts/pylint_messages.py + gen-examples: chmod u+w ../examples/pylintrc pylint --rcfile=/dev/null --generate-rcfile > ../examples/pylintrc diff --git a/doc/additional_commands/index.rst b/doc/additional_commands/index.rst index e4c92cab30..b8ebb15cb6 100644 --- a/doc/additional_commands/index.rst +++ b/doc/additional_commands/index.rst @@ -9,7 +9,7 @@ Pyreverse --------- ``pyreverse`` analyzes your source code and generates package and class diagrams. -It supports output to ``.dot``/``.gv``, ``.vcg`` and ``.puml``/``.plantuml`` (PlantUML) file formats. +It supports output to ``.dot``/``.gv``, ``.vcg``, ``.puml``/``.plantuml`` (PlantUML) and ``.mmd``/``.html`` (MermaidJS) file formats. If Graphviz (or the ``dot`` command) is installed, all `output formats supported by Graphviz `_ can be used as well. In this case, ``pyreverse`` first generates a temporary ``.gv`` file, which is then fed to Graphviz to generate the final image. diff --git a/doc/conf.py b/doc/conf.py index d76cc67e3b..8b548ddc33 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,4 +1,7 @@ -# +# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt + # Pylint documentation build configuration file, created by # sphinx-quickstart on Thu Apr 4 20:31:25 2013. # @@ -36,6 +39,7 @@ extensions = [ "pylint_features", "pylint_extensions", + "pylint_messages", "sphinx.ext.autosectionlabel", "sphinx.ext.intersphinx", ] @@ -72,7 +76,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ["_build"] +exclude_patterns = ["_build", "data/**"] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None diff --git a/doc/data/messages/a/abstract-class-instantiated/bad.py b/doc/data/messages/a/abstract-class-instantiated/bad.py new file mode 100644 index 0000000000..f514a5c3df --- /dev/null +++ b/doc/data/messages/a/abstract-class-instantiated/bad.py @@ -0,0 +1,10 @@ +import abc + + +class Animal(abc.ABC): + @abc.abstractmethod + def make_sound(self): + pass + + +sheep = Animal() # [abstract-class-instantiated] diff --git a/doc/data/messages/a/abstract-class-instantiated/good.py b/doc/data/messages/a/abstract-class-instantiated/good.py new file mode 100644 index 0000000000..c9dbce107b --- /dev/null +++ b/doc/data/messages/a/abstract-class-instantiated/good.py @@ -0,0 +1,15 @@ +import abc + + +class Animal(abc.ABC): + @abc.abstractmethod + def make_sound(self): + pass + + +class Sheep(Animal): + def make_sound(self): + print("bhaaaaa") + + +sheep = Sheep() diff --git a/doc/data/messages/a/abstract-method/bad.py b/doc/data/messages/a/abstract-method/bad.py new file mode 100644 index 0000000000..8b8ddf0f97 --- /dev/null +++ b/doc/data/messages/a/abstract-method/bad.py @@ -0,0 +1,20 @@ +class Pet: + def make_sound(self): + raise NotImplementedError + + +class Cat(Pet): # [abstract-method] + pass + + +import abc + + +class WildAnimal: + @abc.abstractmethod + def make_sound(self): + pass + + +class Panther(WildAnimal): # [abstract-method] + pass diff --git a/doc/data/messages/a/abstract-method/good.py b/doc/data/messages/a/abstract-method/good.py new file mode 100644 index 0000000000..4c4cda3f44 --- /dev/null +++ b/doc/data/messages/a/abstract-method/good.py @@ -0,0 +1,22 @@ +class Pet: + def make_sound(self): + raise NotImplementedError + + +class Cat(Pet): + def make_sound(self): + print("Meeeow") + + +import abc + + +class WildAnimal: + @abc.abstractmethod + def make_sound(self): + pass + + +class Panther(WildAnimal): + def make_sound(self): + print("MEEEOW") diff --git a/doc/data/messages/a/access-member-before-definition/bad.py b/doc/data/messages/a/access-member-before-definition/bad.py new file mode 100644 index 0000000000..cb17c86eef --- /dev/null +++ b/doc/data/messages/a/access-member-before-definition/bad.py @@ -0,0 +1,5 @@ +class Foo: + def __init__(self, param): + if self.param: # [access-member-before-definition] + pass + self.param = param diff --git a/doc/data/messages/a/access-member-before-definition/good.py b/doc/data/messages/a/access-member-before-definition/good.py new file mode 100644 index 0000000000..b2c877a4bd --- /dev/null +++ b/doc/data/messages/a/access-member-before-definition/good.py @@ -0,0 +1,5 @@ +class Foo: + def __init__(self, param): + self.param = param + if self.param: + pass diff --git a/doc/data/messages/a/anomalous-backslash-in-string/bad.py b/doc/data/messages/a/anomalous-backslash-in-string/bad.py new file mode 100644 index 0000000000..08d8d1d6f4 --- /dev/null +++ b/doc/data/messages/a/anomalous-backslash-in-string/bad.py @@ -0,0 +1 @@ +string = "\z" # [anomalous-backslash-in-string] diff --git a/doc/data/messages/a/anomalous-backslash-in-string/good.py b/doc/data/messages/a/anomalous-backslash-in-string/good.py new file mode 100644 index 0000000000..c2465e711c --- /dev/null +++ b/doc/data/messages/a/anomalous-backslash-in-string/good.py @@ -0,0 +1,2 @@ +string = r"\z" +string = "\n" diff --git a/doc/data/messages/a/anomalous-unicode-escape-in-string/bad.py b/doc/data/messages/a/anomalous-unicode-escape-in-string/bad.py new file mode 100644 index 0000000000..40a2a0caff --- /dev/null +++ b/doc/data/messages/a/anomalous-unicode-escape-in-string/bad.py @@ -0,0 +1 @@ +print(b"\u{0}".format("0394")) # [anomalous-unicode-escape-in-string] diff --git a/doc/data/messages/a/anomalous-unicode-escape-in-string/good.py b/doc/data/messages/a/anomalous-unicode-escape-in-string/good.py new file mode 100644 index 0000000000..f2285d70c9 --- /dev/null +++ b/doc/data/messages/a/anomalous-unicode-escape-in-string/good.py @@ -0,0 +1 @@ +print(b"\\u{0}".format("0394")) diff --git a/doc/data/messages/a/assert-on-string-literal/bad.py b/doc/data/messages/a/assert-on-string-literal/bad.py new file mode 100644 index 0000000000..d7c735baba --- /dev/null +++ b/doc/data/messages/a/assert-on-string-literal/bad.py @@ -0,0 +1,2 @@ +def test(): + assert "There is an AssertionError" # [assert-on-string-literal] diff --git a/doc/data/messages/a/assert-on-string-literal/good.py b/doc/data/messages/a/assert-on-string-literal/good.py new file mode 100644 index 0000000000..436a8502f3 --- /dev/null +++ b/doc/data/messages/a/assert-on-string-literal/good.py @@ -0,0 +1,2 @@ +def test(): + # Nothing, as an assert of a string literal will always pass diff --git a/doc/data/messages/a/assert-on-tuple/bad.py b/doc/data/messages/a/assert-on-tuple/bad.py new file mode 100644 index 0000000000..ffcc34c536 --- /dev/null +++ b/doc/data/messages/a/assert-on-tuple/bad.py @@ -0,0 +1 @@ +assert (1, None) # [assert-on-tuple] diff --git a/doc/data/messages/a/assert-on-tuple/good.py b/doc/data/messages/a/assert-on-tuple/good.py new file mode 100644 index 0000000000..cea57cf274 --- /dev/null +++ b/doc/data/messages/a/assert-on-tuple/good.py @@ -0,0 +1,3 @@ +x, y = (1, None) +assert x +assert y diff --git a/doc/data/messages/b/bad-open-mode/bad.py b/doc/data/messages/b/bad-open-mode/bad.py new file mode 100644 index 0000000000..28cfb62283 --- /dev/null +++ b/doc/data/messages/b/bad-open-mode/bad.py @@ -0,0 +1,3 @@ +def foo(file_path): + with open(file_path, "rwx") as file: # [bad-open-mode] + contents = file.read() diff --git a/doc/data/messages/b/bad-open-mode/good.py b/doc/data/messages/b/bad-open-mode/good.py new file mode 100644 index 0000000000..64a853b38c --- /dev/null +++ b/doc/data/messages/b/bad-open-mode/good.py @@ -0,0 +1,3 @@ +def foo(file_path): + with open(file_path, "r") as file: + contents = file.read() diff --git a/doc/data/messages/e/empty-docstring/bad.py b/doc/data/messages/e/empty-docstring/bad.py new file mode 100644 index 0000000000..33dbb5f881 --- /dev/null +++ b/doc/data/messages/e/empty-docstring/bad.py @@ -0,0 +1,2 @@ +def foo(): # [empty-docstring] + """""" diff --git a/doc/data/messages/e/empty-docstring/good.py b/doc/data/messages/e/empty-docstring/good.py new file mode 100644 index 0000000000..b587ca4c6c --- /dev/null +++ b/doc/data/messages/e/empty-docstring/good.py @@ -0,0 +1,2 @@ +def foo(): + """A dummy description.""" diff --git a/doc/data/messages/r/redundant-unittest-assert/bad.py b/doc/data/messages/r/redundant-unittest-assert/bad.py new file mode 100644 index 0000000000..dcfc2e2e4b --- /dev/null +++ b/doc/data/messages/r/redundant-unittest-assert/bad.py @@ -0,0 +1,6 @@ +import unittest + + +class DummyTestCase(unittest.TestCase): + def test_dummy(self): + self.assertTrue("foo") # [redundant-unittest-assert] diff --git a/doc/data/messages/r/redundant-unittest-assert/good.py b/doc/data/messages/r/redundant-unittest-assert/good.py new file mode 100644 index 0000000000..b176d020da --- /dev/null +++ b/doc/data/messages/r/redundant-unittest-assert/good.py @@ -0,0 +1,6 @@ +import unittest + + +class DummyTestCase(unittest.TestCase): + def test_dummy(self): + # Nothing, as an assert of a string literal will always pass diff --git a/doc/data/messages/u/unspecified-encoding/bad.py b/doc/data/messages/u/unspecified-encoding/bad.py new file mode 100644 index 0000000000..4645923c58 --- /dev/null +++ b/doc/data/messages/u/unspecified-encoding/bad.py @@ -0,0 +1,3 @@ +def foo(file_path): + with open(file_path) as file: # [unspecified-encoding] + contents = file.read() diff --git a/doc/data/messages/u/unspecified-encoding/good.py b/doc/data/messages/u/unspecified-encoding/good.py new file mode 100644 index 0000000000..a267a36070 --- /dev/null +++ b/doc/data/messages/u/unspecified-encoding/good.py @@ -0,0 +1,3 @@ +def foo(file_path): + with open(file_path, encoding="utf-8") as file: + contents = file.read() diff --git a/doc/data/messages/y/yield-inside-async-function/bad.py b/doc/data/messages/y/yield-inside-async-function/bad.py new file mode 100644 index 0000000000..6e1d6bd28b --- /dev/null +++ b/doc/data/messages/y/yield-inside-async-function/bad.py @@ -0,0 +1,2 @@ +async def foo(): + yield from [1, 2, 3] # [yield-inside-async-function] diff --git a/doc/data/messages/y/yield-inside-async-function/details.rst b/doc/data/messages/y/yield-inside-async-function/details.rst new file mode 100644 index 0000000000..7d05701aeb --- /dev/null +++ b/doc/data/messages/y/yield-inside-async-function/details.rst @@ -0,0 +1 @@ +The message can't be emitted when using Python < 3.5. diff --git a/doc/data/messages/y/yield-inside-async-function/good.py b/doc/data/messages/y/yield-inside-async-function/good.py new file mode 100644 index 0000000000..1af96506b5 --- /dev/null +++ b/doc/data/messages/y/yield-inside-async-function/good.py @@ -0,0 +1,7 @@ +async def foo(): + def _inner_foo(): + yield from [1, 2, 3] + + +async def foo(): + yield 42 diff --git a/doc/data/messages/y/yield-inside-async-function/related.rst b/doc/data/messages/y/yield-inside-async-function/related.rst new file mode 100644 index 0000000000..98cb4e3a92 --- /dev/null +++ b/doc/data/messages/y/yield-inside-async-function/related.rst @@ -0,0 +1 @@ +- `PEP 525 `_ diff --git a/doc/development_guide/contribute.rst b/doc/development_guide/contribute.rst index 8e484a5147..a157532406 100644 --- a/doc/development_guide/contribute.rst +++ b/doc/development_guide/contribute.rst @@ -87,8 +87,8 @@ of Pylint as it gives you access to the latest ``ast`` parser. - Add a short entry in :file:`doc/whatsnew/VERSION.rst`. -- Add yourself to the `CONTRIBUTORS` file, flag yourself appropriately - (if in doubt, you're a ``contributor``). +- If you used multiple emails or multiple names when contributing, add your mails + and preferred name in the ``script/.contributors_aliases.json`` file. - Write a comprehensive commit message @@ -101,8 +101,6 @@ of Pylint as it gives you access to the latest ``ast`` parser. - Send a pull request from GitHub (see `About pull requests`_ for more insight about this topic) - - .. _`Closing issues via commit messages`: https://help.github.com/articles/closing-issues-via-commit-messages/ .. _`About pull requests`: https://help.github.com/articles/using-pull-requests/ .. _tox: https://tox.readthedocs.io/en/latest/ diff --git a/doc/development_guide/index.rst b/doc/development_guide/index.rst index 50343e4c9e..190efa3692 100644 --- a/doc/development_guide/index.rst +++ b/doc/development_guide/index.rst @@ -8,3 +8,4 @@ Development contribute testing + profiling diff --git a/doc/development_guide/profiling.rst b/doc/development_guide/profiling.rst new file mode 100644 index 0000000000..13a8bbaf4d --- /dev/null +++ b/doc/development_guide/profiling.rst @@ -0,0 +1,118 @@ +.. -*- coding: utf-8 -*- +.. _profiling: + +=================================== + Profiling and performance analysis +=================================== + +Performance analysis for Pylint +------------------------------- + +To analyse the performance of Pylint we recommend to use the ``cProfile`` module +from ``stdlib``. Together with the ``pstats`` module this should give you all the tools +you need to profile a Pylint run and see which functions take how long to run. + +The documentation for both modules can be found at cProfile_. + +To profile a run of Pylint over itself you can use the following code and run it from the base directory. +Note that ``cProfile`` will create a document called ``stats`` that is then read by ``pstats``. The +human-readable output will be stored by ``pstats`` in ``./profiler_stats``. It will be sorted by +``cumulative time``: + +.. sourcecode:: python + + import cProfile + import pstats + import sys + + sys.argv = ["pylint", "pylint"] + cProfile.run("from pylint import __main__", "stats") + + with open("profiler_stats", "w", encoding="utf-8") as file: + stats = pstats.Stats("stats", stream=file) + stats.sort_stats("cumtime") + stats.print_stats() + +You can also interact with the stats object by sorting or restricting the output. +For example, to only print functions from the ``pylint`` module and sort by cumulative time you could +use: + +.. sourcecode:: python + + import cProfile + import pstats + import sys + + sys.argv = ["pylint", "pylint"] + cProfile.run("from pylint import __main__", "stats") + + with open("profiler_stats", "w", encoding="utf-8") as file: + stats = pstats.Stats("stats", stream=file) + stats.sort_stats("cumtime") + stats.print_stats("pylint/pylint") + +Lastly, to profile a run over your own module or code you can use: + +.. sourcecode:: python + + import cProfile + import pstats + import sys + + sys.argv = ["pylint", "your_dir/your_file"] + cProfile.run("from pylint import __main__", "stats") + + with open("profiler_stats", "w", encoding="utf-8") as file: + stats = pstats.Stats("stats", stream=file) + stats.sort_stats("cumtime") + stats.print_stats() + +The documentation of the ``pstats`` module discusses other possibilites to interact with +the profiling output. + + +Performance analysis of a specific checker +------------------------------------------ + +To analyse the performance of specific checker within Pylint we can use the human-readable output +created by ``pstats``. + +If you search in the ``profiler_stats`` file for the file name of the checker you will find all functional +calls from functions within the checker. Let's say we want to check the ``visit_importfrom`` method of the +``variables`` checker:: + + ncalls tottime percall cumtime percall filename:lineno(function) + 622 0.006 0.000 8.039 0.013 /MY_PROGRAMMING_DIR/pylint/pylint/checkers/variables.py:1445(visit_importfrom) + +The previous line tells us that this method was called 622 times during the profile and we were inside the +function itself for 6 ms in total. The time per call is less than a millisecond (0.006 / 622) +and thus is displayed as being 0. + +Often you are more interested in the cumulative time (per call). This refers to the time spend within the function +and any of the functions it called or they functions they called (etc.). In our example, the ``visit_importfrom`` +method and all of its child-functions took a little over 8 seconds to exectute, with an execution time of +0.013 ms per call. + +You can also search the ``profiler_stats`` for an individual function you want to check. For example +``_analyse_fallback_blocks``, a function called by ``visit_importfrom`` in the ``variables`` checker. This +allows more detailed analysis of specific functions:: + + ncalls tottime percall cumtime percall filename:lineno(function) + 1 0.000 0.000 0.000 0.000 /MY_PROGRAMMING_DIR/pylint/pylint/checkers/variables.py:1511(_analyse_fallback_blocks) + + +Parsing the profiler stats with other tools +------------------------------------------- + +Often you might want to create a visual representation of your profiling stats. A good tool +to do this is gprof2dot_. This tool can create a ``.dot`` file from the profiling stats +created by ``cProfile`` and ``pstats``. You can then convert the ``.dot`` file to a ``.png`` +file with one of the many converters found online. + +You can read the gprof2dot_ documentation for installation instructions for your specific environment. + +Another option would be snakeviz_. + +.. _cProfile: https://docs.python.org/3/library/profile.html +.. _gprof2dot: https://github.com/jrfonseca/gprof2dot +.. _snakeviz: https://jiffyclub.github.io/snakeviz/ diff --git a/doc/development_guide/testing.rst b/doc/development_guide/testing.rst index 85d1043ef8..af14ad4aba 100644 --- a/doc/development_guide/testing.rst +++ b/doc/development_guide/testing.rst @@ -12,6 +12,14 @@ Test your code! Pylint is very well tested and has a high code coverage. New contributions are not accepted unless they include tests. + +Before you start testing your code, you need to install your source-code package locally. +To set up your environment for testing, open a terminal outside of your forked repository and run: + + pip install -e + +This ensures your testing environment is similar to Pylint's testing environment on GitHub. + Pylint uses two types of tests: unittests and functional tests. - The unittests can be found in the ``/pylint/test`` directory and they can @@ -75,12 +83,32 @@ can have sections of Pylint's configuration. The .rc file can also contain a section ``[testoptions]`` to pass options for the functional test runner. The following options are currently supported: - "min_pyver": Minimal python version required to run the test - "max_pyver": Python version from which the test won't be run. If the last supported version is 3.9 this setting should be set to 3.10. - "min_pyver_end_position": Minimal python version required to check the end_line and end_column attributes of the message - "requires": Packages required to be installed locally to run the test - "except_implementations": List of python implementations on which the test should not run - "exclude_platforms": List of operating systems on which the test should not run +- "min_pyver": Minimal python version required to run the test +- "max_pyver": Python version from which the test won't be run. If the last supported version is 3.9 this setting should be set to 3.10. +- "min_pyver_end_position": Minimal python version required to check the end_line and end_column attributes of the message +- "requires": Packages required to be installed locally to run the test +- "except_implementations": List of python implementations on which the test should not run +- "exclude_platforms": List of operating systems on which the test should not run + +**Functional test file locations** + +For existing checkers, new test cases should preferably be appended to the existing test file. +For new checkers, a new file ``new_checker_message.py`` should be created (Note the use of +underscores). This file should then be placed in the ``test/functional/n`` sub-directory. + +Some additional notes: + +- If the checker is part of an extension the test should go in ``test/functional/ext/extension_name`` +- If the test is a regression test it should go in ``test/r/regression`` or ``test/r/regression_02``. + The file name should start with ``regression_``. +- For some sub-directories, such as ``test/functional/u``, there are additional sub-directories (``test/functional/u/use``). + Please check if your test file should be placed in any of these directories. It should be placed there + if the sub-directory name matches the word before the first underscore of your test file name. + +The folder structure is enforced when running the test suite, so you might be directed to put the file +in a different sub-directory. + +**Running and updating functional tests** During development, it's sometimes helpful to run all functional tests in your current environment in order to have faster feedback. Run from Pylint root directory with:: diff --git a/doc/exts/pylint_extensions.py b/doc/exts/pylint_extensions.py index 31678735d7..da1b9ee2e4 100755 --- a/doc/exts/pylint_extensions.py +++ b/doc/exts/pylint_extensions.py @@ -1,6 +1,8 @@ #!/usr/bin/env python + # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt """Script used to generate the extensions file before building the actual documentation.""" @@ -14,16 +16,9 @@ from pylint.lint import PyLinter from pylint.utils import get_rst_title -# Some modules have been renamed and deprecated under their old names. -# Skip documenting these modules since: -# 1) They are deprecated, why document them moving forward? -# 2) We can't load the deprecated module and the newly renamed module at the -# same time without getting naming conflicts -DEPRECATED_MODULES = ["check_docs"] # ==> docparams - def builder_inited(app): - """Output full documentation in ReST format for all extension modules""" + """Output full documentation in ReST format for all extension modules.""" # PACKAGE/docs/exts/pylint_extensions.py --> PACKAGE/ base_path = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -34,7 +29,7 @@ def builder_inited(app): doc_files = {} for filename in os.listdir(ext_path): name, ext = os.path.splitext(filename) - if name[0] == "_" or name in DEPRECATED_MODULES: + if name[0] == "_": continue if ext == ".py": modules.append(f"pylint.extensions.{name}") diff --git a/doc/exts/pylint_features.py b/doc/exts/pylint_features.py index a867dd05fe..a605102243 100755 --- a/doc/exts/pylint_features.py +++ b/doc/exts/pylint_features.py @@ -1,6 +1,8 @@ #!/usr/bin/env python + # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt """Script used to generate the features file before building the actual documentation.""" diff --git a/doc/exts/pylint_messages.py b/doc/exts/pylint_messages.py new file mode 100644 index 0000000000..5c63171264 --- /dev/null +++ b/doc/exts/pylint_messages.py @@ -0,0 +1,304 @@ +# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt + +"""Script used to generate the messages files.""" + +import os +from collections import defaultdict +from pathlib import Path +from typing import DefaultDict, Dict, List, NamedTuple, Optional, Tuple + +from sphinx.application import Sphinx + +from pylint.checkers import initialize as initialize_checkers +from pylint.constants import MSG_TYPES +from pylint.extensions import initialize as initialize_extensions +from pylint.lint import PyLinter +from pylint.message import MessageDefinition +from pylint.utils import get_rst_title + +PYLINT_BASE_PATH = Path(__file__).resolve().parent.parent.parent +"""Base path to the project folder.""" + +PYLINT_MESSAGES_PATH = PYLINT_BASE_PATH / "doc" / "messages" +"""Path to the messages documentation folder.""" + +PYLINT_MESSAGES_DATA_PATH = PYLINT_BASE_PATH / "doc" / "data" / "messages" +"""Path to the folder with data for the messages documentation.""" + +MSG_TYPES_DOC = {k: v if v != "info" else "information" for k, v in MSG_TYPES.items()} + + +class MessageData(NamedTuple): + checker: str + id: str + name: str + definition: MessageDefinition + good_code: str + bad_code: str + details: str + related_links: str + + +MessagesDict = Dict[str, List[MessageData]] +OldMessagesDict = Dict[str, DefaultDict[Tuple[str, str], List[Tuple[str, str]]]] +"""DefaultDict is indexed by tuples of (old name symbol, old name id) and values are +tuples of (new name symbol, new name category) +""" + + +def _register_all_checkers_and_extensions(linter: PyLinter) -> None: + """Registers all checkers and extensions found in the default folders.""" + initialize_checkers(linter) + initialize_extensions(linter) + + +def _get_message_data(data_path: Path) -> Tuple[str, str, str, str]: + """Get the message data from the specified path.""" + good_code, bad_code, details, related = "", "", "", "" + + if not data_path.exists(): + return good_code, bad_code, details, related + + if (data_path / "good.py").exists(): + with open(data_path / "good.py", encoding="utf-8") as file: + file_content = file.readlines() + indented_file_content = "".join(" " + i for i in file_content) + good_code = f""" +**Correct code:** + +.. code-block:: python + +{indented_file_content}""" + + if (data_path / "bad.py").exists(): + with open(data_path / "bad.py", encoding="utf-8") as file: + file_content = file.readlines() + indented_file_content = "".join(" " + i for i in file_content) + bad_code = f""" +**Problematic code:** + +.. code-block:: python + +{indented_file_content}""" + + if (data_path / "details.rst").exists(): + with open(data_path / "details.rst", encoding="utf-8") as file: + file_content_string = file.read() + details = f""" +**Additional details:** + +{file_content_string}""" + + if (data_path / "related.rst").exists(): + with open(data_path / "related.rst", encoding="utf-8") as file: + file_content_string = file.read() + related = f""" +**Related links:** + +{file_content_string}""" + + return good_code, bad_code, details, related + + +def _get_all_messages( + linter: PyLinter, +) -> Tuple[MessagesDict, OldMessagesDict]: + """Get all messages registered to a linter and return a dictionary indexed by message + type. + + Also return a dictionary of old message and the new messages they can be mapped to. + """ + messages_dict: MessagesDict = { + "fatal": [], + "error": [], + "warning": [], + "convention": [], + "refactor": [], + "information": [], + } + old_messages: OldMessagesDict = { + "fatal": defaultdict(list), + "error": defaultdict(list), + "warning": defaultdict(list), + "convention": defaultdict(list), + "refactor": defaultdict(list), + "information": defaultdict(list), + } + for message in linter.msgs_store.messages: + message_data_path = ( + PYLINT_MESSAGES_DATA_PATH / message.symbol[0] / message.symbol + ) + good_code, bad_code, details, related = _get_message_data(message_data_path) + + message_data = MessageData( + message.checker_name, + message.msgid, + message.symbol, + message, + good_code, + bad_code, + details, + related, + ) + messages_dict[MSG_TYPES_DOC[message.msgid[0]]].append(message_data) + + if message.old_names: + for old_name in message.old_names: + category = MSG_TYPES_DOC[old_name[0][0]] + old_messages[category][(old_name[1], old_name[0])].append( + (message.symbol, MSG_TYPES_DOC[message.msgid[0]]) + ) + + return messages_dict, old_messages + + +def _write_message_page(messages_dict: MessagesDict) -> None: + """Create or overwrite the file for each message.""" + for category, messages in messages_dict.items(): + category_dir = PYLINT_MESSAGES_PATH / category + if not category_dir.exists(): + category_dir.mkdir(parents=True, exist_ok=True) + for message in messages: + messages_file = os.path.join(category_dir, f"{message.name}.rst") + with open(messages_file, "w", encoding="utf-8") as stream: + stream.write( + f""".. _{message.name}: + +{get_rst_title(f"{message.name} / {message.id}", "=")} +**Message emitted:** + +{message.definition.msg} + +**Description:** + +*{message.definition.description}* + +{message.good_code} +{message.bad_code} +{message.details} +{message.related_links} + +Created by ``{message.checker}`` checker +""" + ) + + +def _write_messages_list_page( + messages_dict: MessagesDict, old_messages_dict: OldMessagesDict +) -> None: + """Create or overwrite the page with the list of all messages.""" + messages_file = os.path.join(PYLINT_MESSAGES_PATH, "messages_list.rst") + with open(messages_file, "w", encoding="utf-8") as stream: + # Write header of file + stream.write( + f""".. _messages-list: + +{get_rst_title("Overview of all Pylint messages", "=")} +.. + NOTE This file is auto-generated. Make any changes to the associated + docs extension in 'pylint_messages.py'. + +Pylint can emit the following messages: + +""" + ) + + # Iterate over tuple to keep same order + for category in ( + "fatal", + "error", + "warning", + "convention", + "refactor", + "information", + ): + messages = sorted(messages_dict[category], key=lambda item: item.name) + old_messages = sorted(old_messages_dict[category], key=lambda item: item[0]) + messages_string = "".join( + f" {category}/{message.name}.rst\n" for message in messages + ) + old_messages_string = "".join( + f" {category}/{old_message[0]}.rst\n" for old_message in old_messages + ) + + # Write list per category + stream.write( + f"""{get_rst_title(category.capitalize(), "-")} +All messages in the {category} category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +{messages_string} +All renamed messages in the {category} category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + +{old_messages_string} + +""" + ) + + +def _write_redirect_pages(old_messages: OldMessagesDict) -> None: + """Create redirect pages for old-messages.""" + for category, old_names in old_messages.items(): + category_dir = PYLINT_MESSAGES_PATH / category + if not os.path.exists(category_dir): + os.makedirs(category_dir) + for old_name, new_names in old_names.items(): + old_name_file = os.path.join(category_dir, f"{old_name[0]}.rst") + with open(old_name_file, "w", encoding="utf-8") as stream: + new_names_string = "".join( + f" ../{new_name[1]}/{new_name[0]}.rst\n" for new_name in new_names + ) + stream.write( + f""".. _{old_name[0]}: + +{get_rst_title(" / ".join(old_name), "=")} +"{old_name[0]} has been renamed. The new message can be found at: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +{new_names_string} +""" + ) + + +# pylint: disable-next=unused-argument +def build_messages_pages(app: Optional[Sphinx]) -> None: + """Overwrite messages files by printing the documentation to a stream. + + Documentation is written in ReST format. + """ + # Create linter, register all checkers and extensions and get all messages + linter = PyLinter() + _register_all_checkers_and_extensions(linter) + messages, old_messages = _get_all_messages(linter) + + # Write message and category pages + _write_message_page(messages) + _write_messages_list_page(messages, old_messages) + + # Write redirect pages + _write_redirect_pages(old_messages) + + +def setup(app: Sphinx) -> None: + """Connects the extension to the Sphinx process.""" + # Register callback at the builder-inited Sphinx event + # See https://www.sphinx-doc.org/en/master/extdev/appapi.html + app.connect("builder-inited", build_messages_pages) + + +if __name__ == "__main__": + pass + # Uncomment to allow running this script by your local python interpreter + # build_messages_pages(None) diff --git a/doc/faq.rst b/doc/faq.rst index 6a401bf25d..04e3b14935 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -59,7 +59,7 @@ The supported running environment since Pylint 2.12.1 is Python 3.6.2+. Pylint expects the name of a package or module as its argument. As a convenience, you can give it a file name if it's possible to guess a module name from -the file's path using the python path. Some examples : +the file's path using the python path. Some examples: "pylint mymodule.py" should always work since the current working directory is automatically added on top of the python path @@ -116,28 +116,48 @@ For example:: Much probably. Read :ref:`ide-integration` +3.5 I need to run pylint over all modules and packages in my project directory. +------------------------------------------------------------------------------- + +By default the ``pylint`` command only accepts a list of python modules and packages. Using a +directory which is not a package results in an error:: + + pylint mydir + ************* Module mydir + mydir/__init__.py:1:0: F0010: error while code parsing: Unable to load file mydir/__init__.py: + [Errno 2] No such file or directory: 'mydir/__init__.py' (parse-error) + +To execute pylint over all modules and packages under the directory, the ``--recursive=y`` option must +be provided. This option makes ``pylint`` attempt to discover all modules (files ending with ``.py`` extension) +and all packages (all directories containing a ``__init__.py`` file). +Those modules and packages are then analyzed:: + + pylint --recursive=y mydir + +When ``--recursive=y`` option is used, modules and packages are also accepted as parameters:: + + pylint --recursive=y mydir mymodule mypackage 4. Message Control ================== 4.1 How to disable a particular message? ------------------------------------------------------------ +---------------------------------------- -For a single line : Add ``#pylint: disable=some-message,another-one`` at the -end of the desired line of code. Since Pylint 2.10 you can also use -``#pylint: disable-next=...`` on the line just above the problem. -``...`` in the following example is a short hand for the list of -messages you want to disable. +For just a single line, add ``#pylint: disable=some-message,another-one`` at the end of +the desired line of code. Since Pylint 2.10 you can also use ``#pylint: disable-next=...`` +on the line just above the problem. ``...`` in the following example is short for the +list of messages you want to disable. -For larger disable : You can add ``#pylint: disable=...`` at the block level to -disable for the block. It's possible to enable for the reminder of the block -with ``#pylint: enable=...`` A block is either a scope (say a function, a module), -or a multiline statement (try, finally, if statements, for loops). -`It's currently impossible to disable inside an else block`_ +For larger amounts of code, you can add ``#pylint: disable=...`` at the block level +to disable messages for the entire block. It's possible to re-enable a message for the +remainder of the block with ``#pylint: enable=...``. A block is either a scope (say a +function, a module) or a multiline statement (try, finally, if statements, for loops). +Note: It's currently impossible to `disable inside an else block`_. Read :ref:`message-control` for details and examples. -.. _`It's currently impossible to disable inside an else block`: https://github.com/PyCQA/pylint/issues/872 +.. _`disable inside an else block`: https://github.com/PyCQA/pylint/issues/872 4.2 Is there a way to disable a message for a particular module only? --------------------------------------------------------------------- @@ -201,7 +221,7 @@ You can see the plugin you need to explicitly `load in the technical reference`_ 4.8 I am using another popular linter alongside pylint. Which messages should I disable to avoid duplicates? ------------------------------------------------------------------------------------------------------------ -pycodestyle_: unneeded-not, line-too-long, unnecessary-semicolon, trailing-whitespace, missing-final-newline, bad-indentation, multiple-statements, bare-except +pycodestyle_: unneeded-not, line-too-long, unnecessary-semicolon, trailing-whitespace, missing-final-newline, bad-indentation, multiple-statements, bare-except, wrong-import-position pyflakes_: undefined-variable, unused-import, unused-variable @@ -249,15 +269,16 @@ default value by changing the mixin-class-rgx option. 6.1 Pylint gave my code a negative rating out of ten. That can't be right! -------------------------------------------------------------------------- -Even though the final rating Pylint renders is nominally out of ten, there's no -lower bound on it. By default, the formula to calculate score is :: - - 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) +Prior to Pylint 2.13.0, the score formula used by default had no lower +bound. The new default score formula is :: -However, this option can be changed in the Pylint rc file. If having negative -values really bugs you, you can set the formula to be the maximum of 0 and the -above expression. + max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) +If your project contains a configuration file created by an earlier version of +Pylint, you can set ``evaluation`` to the above expression to get the new +behavior. Likewise, since negative values are still technically supported, +``evaluation`` can be set to a version of the above expression that does not +enforce a floor of zero. 6.2 I think I found a bug in Pylint. What should I do? ------------------------------------------------------- diff --git a/doc/how_tos/custom_checkers.rst b/doc/how_tos/custom_checkers.rst index 0f6ff60626..bfa623a9d4 100644 --- a/doc/how_tos/custom_checkers.rst +++ b/doc/how_tos/custom_checkers.rst @@ -37,30 +37,36 @@ Firstly we will need to fill in some required boilerplate: import astroid from astroid import nodes + from typing import TYPE_CHECKING, Optional from pylint.checkers import BaseChecker from pylint.interfaces import IAstroidChecker - from pylint.lint import PyLinter + + if TYPE_CHECKING: + from pylint.lint import PyLinter + class UniqueReturnChecker(BaseChecker): __implements__ = IAstroidChecker - name = 'unique-returns' + name = "unique-returns" priority = -1 msgs = { - 'W0001': ( - 'Returns a non-unique constant.', - 'non-unique-returns', - 'All constants returned in a function should be unique.' + "W0001": ( + "Returns a non-unique constant.", + "non-unique-returns", + "All constants returned in a function should be unique.", ), } options = ( ( - 'ignore-ints', + "ignore-ints", { - 'default': False, 'type': 'yn', 'metavar' : '', - 'help': 'Allow returning non-unique integers', - } + "default": False, + "type": "yn", + "metavar": "", + "help": "Allow returning non-unique integers", + }, ), ) @@ -79,20 +85,19 @@ So far we have defined the following required components of our checker: going to emit. It has the following format:: msgs = { - 'message-id': ( - 'displayed-message', 'message-symbol', 'message-help' + "message-id": ( + "displayed-message", "message-symbol", "message-help" ) } + * The ``message-id`` should be a 4-digit number, prefixed with a **message category**. There are multiple message categories, these being ``C``, ``W``, ``E``, ``F``, ``R``, standing for ``Convention``, ``Warning``, ``Error``, ``Fatal`` and ``Refactoring``. - The rest of the 5 digits should not conflict with existing checkers - and they should be consistent across the checker. - For instance, - the first two digits should not be different across the checker. + The 4 digits should not conflict with existing checkers + and the first 2 digits should consistent across the checker. * The ``displayed-message`` is used for displaying the message to the user, once it is emitted. @@ -107,9 +112,10 @@ The options list defines any user configurable options. It has the following format:: options = ( - 'option-symbol': {'argparse-like-kwarg': 'value'}, + ("option-symbol", {"argparse-like-kwarg": "value"}), ) + * The ``option-symbol`` is a unique name for the option. This is used on the command line and in config files. The hyphen is replaced by an underscore when used in the checker, @@ -119,8 +125,8 @@ Next we'll track when we enter and leave a function. .. code-block:: python - def __init__(self, linter: PyLinter =None) -> None: - super(UniqueReturnChecker, self).__init__(linter) + def __init__(self, linter: Optional["PyLinter"] = None) -> None: + super().__init__(linter) self._function_stack = [] def visit_functiondef(self, node: nodes.FunctionDef) -> None: @@ -145,7 +151,7 @@ which is called with an :class:`.astroid.nodes.Return` node. .. _astroid_extract_node: .. TODO We can shorten/remove this bit once astroid has API docs. -We'll need to be able to figure out what attributes a +We'll need to be able to figure out what attributes an :class:`.astroid.nodes.Return` node has available. We can use :func:`astroid.extract_node` for this:: @@ -163,7 +169,7 @@ We could also construct a more complete example:: ... if True: ... return 5 #@ ... return 5 #@ - """) + ... """) >>> node_a.value >>> node_a.value.value @@ -183,13 +189,11 @@ Now we know how to use the astroid node, we can implement our check. def visit_return(self, node: nodes.Return) -> None: if not isinstance(node.value, nodes.Const): return - for other_return in self._function_stack[-1]: - if (node.value.value == other_return.value.value and - not (self.config.ignore_ints and node.value.pytype() == int)): - self.add_message( - 'non-unique-returns', node=node, - ) + if node.value.value == other_return.value.value and not ( + self.config.ignore_ints and node.value.pytype() == int + ): + self.add_message("non-unique-returns", node=node) self._function_stack[-1].append(node) @@ -201,7 +205,10 @@ Add the ``register`` function to the top level of the file. .. code-block:: python - def register(linter): + def register(linter: "PyLinter") -> None: + """This required method auto registers the checker during initialization. + :param linter: The linter to register the checker to. + """ linter.register_checker(UniqueReturnChecker(linter)) We are now ready to debug and test our checker! @@ -257,6 +264,7 @@ We can use the example code that we used for debugging as our test cases. import my_plugin import pylint.testutils + class TestUniqueReturnChecker(pylint.testutils.CheckerTestCase): CHECKER_CLASS = my_plugin.UniqueReturnChecker @@ -272,7 +280,7 @@ We can use the example code that we used for debugging as our test cases. self.checker.visit_return(return_node_a) with self.assertAddsMessages( pylint.testutils.MessageTest( - msg_id='non-unique-returns', + msg_id="non-unique-returns", node=return_node_b, ), ): diff --git a/doc/how_tos/plugins.rst b/doc/how_tos/plugins.rst index a68bd22f82..bc2c0f14cb 100644 --- a/doc/how_tos/plugins.rst +++ b/doc/how_tos/plugins.rst @@ -25,7 +25,19 @@ So a basic hello-world plugin can be implemented as: .. sourcecode:: python # Inside hello_plugin.py - def register(linter): + from typing import TYPE_CHECKING + + import astroid + + if TYPE_CHECKING: + from pylint.lint import PyLinter + + + def register(linter: "PyLinter") -> None: + """This required method auto registers the checker during initialization. + + :param linter: The linter to register the checker to. + """ print('Hello world') @@ -43,7 +55,19 @@ We can extend hello-world plugin to ignore some specific names using .. sourcecode:: python # Inside hello_plugin.py - def register(linter): + from typing import TYPE_CHECKING + + import astroid + + if TYPE_CHECKING: + from pylint.lint import PyLinter + + + def register(linter: "PyLinter") -> None: + """This required method auto registers the checker during initialization. + + :param linter: The linter to register the checker to. + """ print('Hello world') def load_configuration(linter): diff --git a/doc/how_tos/transform_plugins.rst b/doc/how_tos/transform_plugins.rst index 30e057820d..031faa0f13 100644 --- a/doc/how_tos/transform_plugins.rst +++ b/doc/how_tos/transform_plugins.rst @@ -66,10 +66,19 @@ Module, Class, Function etc. In our case we need to transform a class. It can be .. sourcecode:: python + from typing import TYPE_CHECKING + import astroid - def register(linter): - # Needed for registering the plugin. + if TYPE_CHECKING: + from pylint.lint import PyLinter + + + def register(linter: "PyLinter") -> None: + """This required method auto registers the checker during initialization. + + :param linter: The linter to register the checker to. + """ pass def transform(cls): diff --git a/doc/index.rst b/doc/index.rst index 1508ff679e..ff2bfd6014 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -17,6 +17,7 @@ refactored and can offer you details about the code's complexity. user_guide/index.rst how_tos/index.rst + messages/index.rst technical_reference/index.rst development_guide/index.rst additional_commands/index.rst diff --git a/doc/messages/index.rst b/doc/messages/index.rst new file mode 100644 index 0000000000..aceca53f61 --- /dev/null +++ b/doc/messages/index.rst @@ -0,0 +1,11 @@ +.. _messages: + +Messages +=================== + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + messages_introduction + messages_list diff --git a/doc/messages/messages_introduction.rst b/doc/messages/messages_introduction.rst new file mode 100644 index 0000000000..e351d1b9bd --- /dev/null +++ b/doc/messages/messages_introduction.rst @@ -0,0 +1,15 @@ +.. _messages-introduction: + +Message categories +===================== + +Pylint can emit various messages. These are categorized according to categories:: + + Convention + Error + Fatal + Information + Refactor + Warning + +A list of these messages can be found here: :ref:`messages-list` diff --git a/doc/messages/messages_list.rst b/doc/messages/messages_list.rst new file mode 100644 index 0000000000..d288857414 --- /dev/null +++ b/doc/messages/messages_list.rst @@ -0,0 +1,520 @@ +.. _messages-list: + +Overview of all Pylint messages +=============================== + +.. + NOTE This file is auto-generated. Make any changes to the associated + docs extension in 'pylint_messages.py'. + +Pylint can emit the following messages: + +Fatal +----- + +All messages in the fatal category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + fatal/astroid-error.rst + fatal/config-parse-error.rst + fatal/fatal.rst + fatal/method-check-failed.rst + fatal/parse-error.rst + +All renamed messages in the fatal category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + fatal/old-import-error.rst + + +Error +----- + +All messages in the error category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + error/abstract-class-instantiated.rst + error/access-member-before-definition.rst + error/assigning-non-slot.rst + error/assignment-from-no-return.rst + error/assignment-from-none.rst + error/await-outside-async.rst + error/bad-configuration-section.rst + error/bad-except-order.rst + error/bad-exception-context.rst + error/bad-format-character.rst + error/bad-option-value.rst + error/bad-plugin-value.rst + error/bad-reversed-sequence.rst + error/bad-str-strip-call.rst + error/bad-string-format-type.rst + error/bad-super-call.rst + error/bidirectional-unicode.rst + error/catching-non-exception.rst + error/class-variable-slots-conflict.rst + error/continue-in-finally.rst + error/dict-iter-missing-items.rst + error/duplicate-argument-name.rst + error/duplicate-bases.rst + error/format-needs-mapping.rst + error/function-redefined.rst + error/import-error.rst + error/inconsistent-mro.rst + error/inherit-non-class.rst + error/init-is-generator.rst + error/invalid-all-format.rst + error/invalid-all-object.rst + error/invalid-bool-returned.rst + error/invalid-bytes-returned.rst + error/invalid-character-backspace.rst + error/invalid-character-carriage-return.rst + error/invalid-character-esc.rst + error/invalid-character-nul.rst + error/invalid-character-sub.rst + error/invalid-character-zero-width-space.rst + error/invalid-class-object.rst + error/invalid-envvar-value.rst + error/invalid-format-returned.rst + error/invalid-getnewargs-ex-returned.rst + error/invalid-getnewargs-returned.rst + error/invalid-hash-returned.rst + error/invalid-index-returned.rst + error/invalid-length-hint-returned.rst + error/invalid-length-returned.rst + error/invalid-metaclass.rst + error/invalid-repr-returned.rst + error/invalid-sequence-index.rst + error/invalid-slice-index.rst + error/invalid-slots.rst + error/invalid-slots-object.rst + error/invalid-star-assignment-target.rst + error/invalid-str-returned.rst + error/invalid-unary-operand-type.rst + error/invalid-unicode-codec.rst + error/logging-format-truncated.rst + error/logging-too-few-args.rst + error/logging-too-many-args.rst + error/logging-unsupported-format.rst + error/method-hidden.rst + error/misplaced-bare-raise.rst + error/misplaced-format-function.rst + error/missing-format-string-key.rst + error/missing-kwoa.rst + error/mixed-format-string.rst + error/modified-iterating-dict.rst + error/modified-iterating-set.rst + error/no-member.rst + error/no-method-argument.rst + error/no-name-in-module.rst + error/no-self-argument.rst + error/no-value-for-parameter.rst + error/non-iterator-returned.rst + error/nonexistent-operator.rst + error/nonlocal-and-global.rst + error/nonlocal-without-binding.rst + error/not-a-mapping.rst + error/not-an-iterable.rst + error/not-async-context-manager.rst + error/not-callable.rst + error/not-context-manager.rst + error/not-in-loop.rst + error/notimplemented-raised.rst + error/raising-bad-type.rst + error/raising-non-exception.rst + error/redundant-keyword-arg.rst + error/relative-beyond-top-level.rst + error/repeated-keyword.rst + error/return-arg-in-generator.rst + error/return-in-init.rst + error/return-outside-function.rst + error/star-needs-assignment-target.rst + error/syntax-error.rst + error/too-few-format-args.rst + error/too-many-format-args.rst + error/too-many-function-args.rst + error/too-many-star-expressions.rst + error/truncated-format-string.rst + error/undefined-all-variable.rst + error/undefined-variable.rst + error/unexpected-keyword-arg.rst + error/unexpected-special-method-signature.rst + error/unhashable-dict-key.rst + error/unpacking-non-sequence.rst + error/unrecognized-inline-option.rst + error/unsubscriptable-object.rst + error/unsupported-assignment-operation.rst + error/unsupported-binary-operation.rst + error/unsupported-delete-operation.rst + error/unsupported-membership-test.rst + error/used-before-assignment.rst + error/used-prior-global-declaration.rst + error/yield-inside-async-function.rst + error/yield-outside-function.rst + +All renamed messages in the error category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + error/bad-context-manager.rst + error/maybe-no-member.rst + error/old-non-iterator-returned-2.rst + error/old-unbalanced-tuple-unpacking.rst + + +Warning +------- + +All messages in the warning category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + warning/abstract-method.rst + warning/anomalous-backslash-in-string.rst + warning/anomalous-unicode-escape-in-string.rst + warning/arguments-differ.rst + warning/arguments-out-of-order.rst + warning/arguments-renamed.rst + warning/assert-on-string-literal.rst + warning/assert-on-tuple.rst + warning/assign-to-new-keyword.rst + warning/attribute-defined-outside-init.rst + warning/bad-builtin.rst + warning/bad-format-string.rst + warning/bad-format-string-key.rst + warning/bad-indentation.rst + warning/bad-open-mode.rst + warning/bad-staticmethod-argument.rst + warning/bad-thread-instantiation.rst + warning/bare-except.rst + warning/binary-op-exception.rst + warning/boolean-datetime.rst + warning/broad-except.rst + warning/cell-var-from-loop.rst + warning/comparison-with-callable.rst + warning/confusing-with-statement.rst + warning/consider-ternary-expression.rst + warning/dangerous-default-value.rst + warning/deprecated-argument.rst + warning/deprecated-class.rst + warning/deprecated-decorator.rst + warning/deprecated-method.rst + warning/deprecated-module.rst + warning/deprecated-typing-alias.rst + warning/differing-param-doc.rst + warning/differing-type-doc.rst + warning/duplicate-except.rst + warning/duplicate-key.rst + warning/duplicate-string-formatting-argument.rst + warning/eval-used.rst + warning/exec-used.rst + warning/expression-not-assigned.rst + warning/f-string-without-interpolation.rst + warning/fixme.rst + warning/forgotten-debug-statement.rst + warning/format-combined-specification.rst + warning/format-string-without-interpolation.rst + warning/global-at-module-level.rst + warning/global-statement.rst + warning/global-variable-not-assigned.rst + warning/global-variable-undefined.rst + warning/implicit-str-concat.rst + warning/import-self.rst + warning/inconsistent-quotes.rst + warning/invalid-envvar-default.rst + warning/invalid-format-index.rst + warning/invalid-overridden-method.rst + warning/isinstance-second-argument-not-valid-type.rst + warning/keyword-arg-before-vararg.rst + warning/logging-format-interpolation.rst + warning/logging-fstring-interpolation.rst + warning/logging-not-lazy.rst + warning/lost-exception.rst + warning/lru-cache-decorating-method.rst + warning/misplaced-future.rst + warning/missing-any-param-doc.rst + warning/missing-format-argument-key.rst + warning/missing-format-attribute.rst + warning/missing-param-doc.rst + warning/missing-parentheses-for-call-in-test.rst + warning/missing-raises-doc.rst + warning/missing-return-doc.rst + warning/missing-return-type-doc.rst + warning/missing-type-doc.rst + warning/missing-yield-doc.rst + warning/missing-yield-type-doc.rst + warning/modified-iterating-list.rst + warning/multiple-constructor-doc.rst + warning/nan-comparison.rst + warning/no-init.rst + warning/non-ascii-file-name.rst + warning/non-parent-init-called.rst + warning/non-str-assignment-to-dunder-name.rst + warning/overlapping-except.rst + warning/overridden-final-method.rst + warning/pointless-statement.rst + warning/pointless-string-statement.rst + warning/possibly-unused-variable.rst + warning/preferred-module.rst + warning/protected-access.rst + warning/raise-missing-from.rst + warning/raising-format-tuple.rst + warning/redeclared-assigned-name.rst + warning/redefined-builtin.rst + warning/redefined-outer-name.rst + warning/redefined-slots-in-subclass.rst + warning/redundant-returns-doc.rst + warning/redundant-u-string-prefix.rst + warning/redundant-unittest-assert.rst + warning/redundant-yields-doc.rst + warning/reimported.rst + warning/self-assigning-variable.rst + warning/self-cls-assignment.rst + warning/shallow-copy-environ.rst + warning/signature-differs.rst + warning/subclassed-final-class.rst + warning/subprocess-popen-preexec-fn.rst + warning/subprocess-run-check.rst + warning/super-init-not-called.rst + warning/too-many-try-statements.rst + warning/try-except-raise.rst + warning/unbalanced-tuple-unpacking.rst + warning/undefined-loop-variable.rst + warning/unnecessary-ellipsis.rst + warning/unnecessary-lambda.rst + warning/unnecessary-pass.rst + warning/unnecessary-semicolon.rst + warning/unreachable.rst + warning/unspecified-encoding.rst + warning/unused-argument.rst + warning/unused-format-string-argument.rst + warning/unused-format-string-key.rst + warning/unused-import.rst + warning/unused-private-member.rst + warning/unused-variable.rst + warning/unused-wildcard-import.rst + warning/useless-else-on-loop.rst + warning/useless-param-doc.rst + warning/useless-super-delegation.rst + warning/useless-type-doc.rst + warning/useless-with-lock.rst + warning/using-constant-test.rst + warning/using-f-string-in-unsupported-version.rst + warning/using-final-decorator-in-unsupported-version.rst + warning/while-used.rst + warning/wildcard-import.rst + warning/wrong-exception-operation.rst + +All renamed messages in the warning category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + warning/implicit-str-concat-in-sequence.rst + warning/old-assignment-from-none.rst + warning/old-empty-docstring.rst + warning/old-missing-param-doc.rst + warning/old-missing-returns-doc.rst + warning/old-missing-type-doc.rst + warning/old-missing-yields-doc.rst + warning/old-non-iterator-returned-1.rst + warning/old-unidiomatic-typecheck.rst + warning/old-unpacking-non-sequence.rst + + +Convention +---------- + +All messages in the convention category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + convention/bad-classmethod-argument.rst + convention/bad-docstring-quotes.rst + convention/bad-file-encoding.rst + convention/bad-mcs-classmethod-argument.rst + convention/bad-mcs-method-argument.rst + convention/compare-to-empty-string.rst + convention/compare-to-zero.rst + convention/consider-iterating-dictionary.rst + convention/consider-using-any-or-all.rst + convention/consider-using-dict-items.rst + convention/consider-using-enumerate.rst + convention/consider-using-f-string.rst + convention/disallowed-name.rst + convention/docstring-first-line-empty.rst + convention/empty-docstring.rst + convention/import-outside-toplevel.rst + convention/invalid-characters-in-docstring.rst + convention/invalid-name.rst + convention/line-too-long.rst + convention/misplaced-comparison-constant.rst + convention/missing-class-docstring.rst + convention/missing-final-newline.rst + convention/missing-function-docstring.rst + convention/missing-module-docstring.rst + convention/mixed-line-endings.rst + convention/multiple-imports.rst + convention/multiple-statements.rst + convention/non-ascii-module-import.rst + convention/non-ascii-name.rst + convention/single-string-used-for-slots.rst + convention/singleton-comparison.rst + convention/superfluous-parens.rst + convention/too-many-lines.rst + convention/trailing-newlines.rst + convention/trailing-whitespace.rst + convention/unexpected-line-ending-format.rst + convention/ungrouped-imports.rst + convention/unidiomatic-typecheck.rst + convention/unneeded-not.rst + convention/use-implicit-booleaness-not-comparison.rst + convention/use-implicit-booleaness-not-len.rst + convention/use-maxsplit-arg.rst + convention/use-sequence-for-iteration.rst + convention/useless-import-alias.rst + convention/wrong-import-order.rst + convention/wrong-import-position.rst + convention/wrong-spelling-in-comment.rst + convention/wrong-spelling-in-docstring.rst + +All renamed messages in the convention category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + convention/blacklisted-name.rst + convention/len-as-condition.rst + convention/missing-docstring.rst + convention/old-misplaced-comparison-constant.rst + convention/old-non-ascii-name.rst + + +Refactor +-------- + +All messages in the refactor category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + refactor/chained-comparison.rst + refactor/comparison-with-itself.rst + refactor/condition-evals-to-constant.rst + refactor/confusing-consecutive-elif.rst + refactor/consider-alternative-union-syntax.rst + refactor/consider-merging-isinstance.rst + refactor/consider-swap-variables.rst + refactor/consider-using-alias.rst + refactor/consider-using-assignment-expr.rst + refactor/consider-using-dict-comprehension.rst + refactor/consider-using-from-import.rst + refactor/consider-using-generator.rst + refactor/consider-using-get.rst + refactor/consider-using-in.rst + refactor/consider-using-join.rst + refactor/consider-using-max-builtin.rst + refactor/consider-using-min-builtin.rst + refactor/consider-using-namedtuple-or-dataclass.rst + refactor/consider-using-set-comprehension.rst + refactor/consider-using-sys-exit.rst + refactor/consider-using-ternary.rst + refactor/consider-using-tuple.rst + refactor/consider-using-with.rst + refactor/cyclic-import.rst + refactor/duplicate-code.rst + refactor/else-if-used.rst + refactor/empty-comment.rst + refactor/inconsistent-return-statements.rst + refactor/literal-comparison.rst + refactor/no-classmethod-decorator.rst + refactor/no-else-break.rst + refactor/no-else-continue.rst + refactor/no-else-raise.rst + refactor/no-else-return.rst + refactor/no-self-use.rst + refactor/no-staticmethod-decorator.rst + refactor/property-with-parameters.rst + refactor/redefined-argument-from-local.rst + refactor/redefined-variable-type.rst + refactor/simplifiable-condition.rst + refactor/simplifiable-if-expression.rst + refactor/simplifiable-if-statement.rst + refactor/simplify-boolean-expression.rst + refactor/stop-iteration-return.rst + refactor/super-with-arguments.rst + refactor/too-complex.rst + refactor/too-few-public-methods.rst + refactor/too-many-ancestors.rst + refactor/too-many-arguments.rst + refactor/too-many-boolean-expressions.rst + refactor/too-many-branches.rst + refactor/too-many-instance-attributes.rst + refactor/too-many-locals.rst + refactor/too-many-nested-blocks.rst + refactor/too-many-public-methods.rst + refactor/too-many-return-statements.rst + refactor/too-many-statements.rst + refactor/trailing-comma-tuple.rst + refactor/unnecessary-comprehension.rst + refactor/unnecessary-dict-index-lookup.rst + refactor/use-a-generator.rst + refactor/use-dict-literal.rst + refactor/use-list-literal.rst + refactor/use-set-for-membership.rst + refactor/useless-object-inheritance.rst + refactor/useless-return.rst + +All renamed messages in the refactor category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + refactor/old-simplifiable-if-statement.rst + refactor/old-too-many-nested-blocks.rst + + +Information +----------- + +All messages in the information category: + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + information/bad-inline-option.rst + information/c-extension-no-member.rst + information/deprecated-pragma.rst + information/file-ignored.rst + information/locally-disabled.rst + information/raw-checker-failed.rst + information/suppressed-message.rst + information/use-symbolic-message-instead.rst + information/useless-suppression.rst + +All renamed messages in the information category: + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + information/deprecated-disable-all.rst diff --git a/doc/release.md b/doc/release.md index 0854464af9..556de5c0ae 100644 --- a/doc/release.md +++ b/doc/release.md @@ -2,51 +2,87 @@ So, you want to release the `X.Y.Z` version of pylint ? -## Process +## Releasing a major or minor version -1. Check if the dependencies of the package are correct, make sure that astroid is - pinned to the latest version. -2. Install the release dependencies `pip3 install pre-commit tbump` -3. Bump the version by using `tbump X.Y.Z --no-tag --no-push` -4. Check the result (Do `git diff vX.Y.Z-1 ChangeLog doc/whatsnew/` in particular). -5. Move back to a dev version for pylint with `tbump`: +**Before releasing a major or minor version check if there are any unreleased commits on +the maintenance branch. If so, release a last patch release first. See +`Releasing a patch version`.** + +- Write the `Summary -- Release highlights` in `doc/whatsnew` and upgrade the release + date. +- Remove the empty changelog for the last unreleased patch version `X.Y-1.Z'`. (For + example: `v2.3.5`) +- Check the result of `git diff vX.Y-1.Z' ChangeLog`. (For example: + `git diff v2.3.4 ChangeLog`) +- Install the release dependencies: `pip3 install -r requirements_test.txt` +- Bump the version and release by using `tbump X.Y.0 --no-push --no-tag`. (For example: + `tbump 2.4.0 --no-push --no-tag`) +- Check the commit created with `git show` amend the commit if required. +- Create a new `What's new in Pylint X.Y+1` document. Add it to `doc/index.rst`. Take a + look at the examples from `doc/whatsnew`. Commit that with `git commit -am "wip"`. +- Move the `main` branch up to a dev version with `tbump`: ```bash -tbump X.Y.Z+1-dev0 --no-tag --no-push # You can interrupt during copyrite -git commit -am "Move back to a dev version following X.Y.Z release" +tbump X.Y+1.0-dev0 --no-tag --no-push # You can interrupt after the first step +git commit -am "Upgrade the version to x.y+1.0-dev0 following x.y.0 release" ``` -4. Check the result -5. Open a merge request with the two commits (no one can push directly on `main`) -6. After the merge recover the merged commits and tag the first one (the version should - be `X.Y.Z`) as `vX.Y.Z` -7. Push the tag -8. Go to GitHub, click on "Releases" then on the `vX.Y.Z` tag, choose edit tag, and copy - past the changelog in the description. This will trigger the release to pypi. +For example: -## Post release +```bash +tbump 2.5.0-dev0 --no-tag --no-push +git commit -am "Upgrade the version to 2.5.0-dev0 following 2.4.0 release" +``` -### Merge tags in main for pre-commit +Check the commit, fixup the 'wip' commit with the what's new then push to a release +branch -If the tag you just made is not part of the main branch, merge the tag `vX.Y.Z` in the -main branch by doing a history only merge. It's done in order to signal that this is an -official release tag, and for `pre-commit autoupdate` to works. +- Open a merge request with the two commits (no one can push directly on `main`) +- After the merge, recover the merged commits on `main` and tag the first one (the + version should be `X.Y.Z`) as `vX.Y.Z` (For example: `v2.4.0`) +- Push the tag. +- Release the version on GitHub with the same name as the tag and copy and paste the + appropriate changelog in the description. This triggers the PyPI release. +- Delete the `maintenance/X.Y-1.x` branch. (For example: `maintenance/2.3.x`) +- Create a `maintenance/X.Y.x` (For example: `maintenance/2.4.x` from the `v2.4.0` tag.) +- Close the current milestone and create the new ones (For example: close `2.4.0`, + create `2.4.1` and `2.6.0`) -```bash -git checkout main -git merge --no-edit --strategy=ours vX.Y.Z -git push -``` +## Backporting a fix from `main` to the maintenance branch + +Whenever a commit on `main` should be released in a patch release on the current +maintenance branch we cherry-pick the commit from `main`. + +- During the merge request on `main`, make sure that the changelog is for the patch + version `X.Y-1.Z'`. (For example: `v2.3.5`) +- After the PR is merged on `main` cherry-pick the commits on the `maintenance/X.Y.x` + branch (For example: from `maintenance/2.4.x` cherry-pick a commit from `main`) +- Remove the "need backport" label from cherry-picked issues +- Release a patch version -### Milestone handling +## Releasing a patch version -We move issue that were not done in the next milestone and block release only if it's an -issue labelled as blocker. +We release patch versions when a crash or a bug is fixed on the main branch and has been +cherry-picked on the maintenance branch. -- Close milestone `X.Y.Z` -- Create the milestones for `X.Y.Z+1`, (or `X.Y+1.0`, and `X+1.0.0` if applicable) +- Check the result of `git diff vX.Y-1.Z-1 ChangeLog`. (For example: + `git diff v2.3.4 ChangeLog`) +- Install the release dependencies: `pip3 install -r requirements_test.txt` +- Bump the version and release by using `tbump X.Y-1.Z --no-push`. (For example: + `tbump 2.3.5 --no-push`) +- Check the result visually with `git show`. +- Push the tag. +- Release the version on GitHub with the same name as the tag and copy and paste the + appropriate changelog in the description. This triggers the PyPI release. +- Merge the `maintenance/X.Y.x` branch on the main branch. The main branch should have + the changelog for `X.Y-1.Z+1` (For example `v2.3.6`). This merge is required so + `pre-commit autoupdate` works for pylint. +- Fix version conflicts properly, or bump the version to `X.Y.0-devZ` (For example: + `2.4.0-dev6`) before pushing on the main branch +- Close the current milestone and create the new one (For example: close `2.3.5`, create + `2.3.6`) -#### What's new +## Milestone handling -If it's a minor release, create a new `What's new in Pylint X.Y+1` document. Add it to -`doc/index.rst`. Take a look at the examples from `doc/whatsnew`. +We move issues that were not done to the next milestone and block releases only if there +are any open issues labelled as `blocker`. diff --git a/doc/requirements.txt b/doc/requirements.txt index 586c5d9672..acaea1e853 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,3 @@ -Sphinx==4.3.1 -python-docs-theme==2021.11.1 +Sphinx==4.4.0 +python-docs-theme==2022.1 -e . diff --git a/doc/test_messages_documentation.py b/doc/test_messages_documentation.py new file mode 100644 index 0000000000..19a35b6d91 --- /dev/null +++ b/doc/test_messages_documentation.py @@ -0,0 +1,115 @@ +# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt + +"""Functional tests for the code examples in the messages documentation.""" + +from collections import Counter +from pathlib import Path +from typing import Counter as CounterType +from typing import List, TextIO, Tuple + +import pytest + +from pylint import checkers +from pylint.config.config_initialization import _config_initialization +from pylint.lint import PyLinter +from pylint.message.message import Message +from pylint.testutils.constants import _EXPECTED_RE +from pylint.testutils.reporter_for_tests import FunctionalTestReporter + +MessageCounter = CounterType[Tuple[int, str]] + + +def get_functional_test_files_from_directory(input_dir: Path) -> List[Tuple[str, Path]]: + """Get all functional tests in the input_dir.""" + suite: List[Tuple[str, Path]] = [] + + for subdirectory in input_dir.iterdir(): + for message_dir in subdirectory.iterdir(): + if (message_dir / "good.py").exists(): + suite.append( + (message_dir.stem, message_dir / "good.py"), + ) + if (message_dir / "bad.py").exists(): + suite.append( + (message_dir.stem, message_dir / "bad.py"), + ) + return suite + + +TESTS_DIR = Path(__file__).parent.resolve() / "data" / "messages" +TESTS = get_functional_test_files_from_directory(TESTS_DIR) +TESTS_NAMES = [f"{t[0]}-{t[1].stem}" for t in TESTS] + + +class LintModuleTest: + def __init__(self, test_file: Tuple[str, Path]) -> None: + self._test_file = test_file + + _test_reporter = FunctionalTestReporter() + + self._linter = PyLinter() + self._linter.config.persistent = 0 + checkers.initialize(self._linter) + + _config_initialization( + self._linter, + args_list=[ + str(test_file[1]), + "--disable=all", + f"--enable={test_file[0]}", + ], + reporter=_test_reporter, + ) + + def runTest(self) -> None: + self._runTest() + + @staticmethod + def get_expected_messages(stream: TextIO) -> MessageCounter: + """Parse a file and get expected messages.""" + messages: MessageCounter = Counter() + for i, line in enumerate(stream): + match = _EXPECTED_RE.search(line) + if match is None: + continue + + line = match.group("line") + if line is None: + lineno = i + 1 + else: + lineno = int(line) + + for msg_id in match.group("msgs").split(","): + messages[lineno, msg_id.strip()] += 1 + return messages + + def _get_expected(self) -> MessageCounter: + """Get the expected messages for a file.""" + with open(self._test_file[1], encoding="utf8") as f: + expected_msgs = self.get_expected_messages(f) + return expected_msgs + + def _get_actual(self) -> MessageCounter: + """Get the actual messages after a run.""" + messages: List[Message] = self._linter.reporter.messages + messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) + received_msgs: MessageCounter = Counter() + for msg in messages: + received_msgs[msg.line, msg.symbol] += 1 + return received_msgs + + def _runTest(self) -> None: + """Run the test and assert message differences.""" + self._linter.check([str(self._test_file[1])]) + expected_messages = self._get_expected() + actual_messages = self._get_actual() + assert expected_messages == actual_messages + + +@pytest.mark.parametrize("test_file", TESTS, ids=TESTS_NAMES) +@pytest.mark.filterwarnings("ignore::DeprecationWarning") +def test_code_examples(test_file: Tuple[str, Path]) -> None: + lint_test = LintModuleTest(test_file) + lint_test.runTest() diff --git a/doc/user_guide/options.rst b/doc/user_guide/options.rst index 898c7a60a7..d89e5e988b 100644 --- a/doc/user_guide/options.rst +++ b/doc/user_guide/options.rst @@ -39,6 +39,8 @@ name is found in, and not the type of object assigned. +--------------------+---------------------------------------------------------------------------------------------------+ | ``inlinevar`` | Loop variables in list comprehensions and generator expressions. | +--------------------+---------------------------------------------------------------------------------------------------+ +| ``typevar`` | Type variable declared with ``TypeVar``. | ++--------------------+---------------------------------------------------------------------------------------------------+ Default behavior ~~~~~~~~~~~~~~~~ @@ -82,6 +84,20 @@ Following options are exposed: .. option:: --inlinevar-naming-style=