What's New in Pylint 4.1

:Release:4.1 :Date: TBA

Summary -- Release highlights

The required astroid version is now 4.1.1. See the astroid changelog for additional fixes, features, and performance improvements applicable to pylint.

What's new in Pylint 4.0.0-dev0?

Release date: TBA

New Features

  • Add support for ignore-pattern-in-long-lines to allow ignoring specific parts of a line when checking line length.

    Refs #3352 (#3352)

  • The dict-init-mutate message now includes a suggested dictionary literal showing how to combine the initialization and subsequent mutations into a single statement.

    Closes #7819 (#7819)

  • pyreverse: add --no-signatures to show method names without parameter lists or return type annotations in class diagrams.

    Closes #10772 (#10772)

  • Add support for --known-first-party similar to --known-third-party.

    Refs #10803 (#10803)

False Positives Fixed

  • Fix a false positive for too-many-arguments in (non-static) methods and classmethods.

    Closes #8675 (#8675)

  • Fix used-before-assignment false positive for names bound in only some arms of an if/elif/else chain.

    Closes #9879 (#9879)

  • Fix a false positive for unexpected-keyword-arg for dataclasses using generic type aliases (PEP 695).

    Closes #10703 (#10703)

  • Fix possibly-used-before-assignment false positive when using self.fail() in tests.

    Closes #10743 (#10743)

  • Fixed false positive for logging-unsupported-format when no arguments are provided to logging functions.

    According to Python's logging documentation, no formatting is performed when no arguments are supplied, so strings like logging.error("%test") are valid.

    Closes #10752 (#10752)

  • Fix false positive unreachable when calling a function with @overload where one signature returns NoReturn.

    Closes #10785 (#10785)

  • Fix a false positive for too-many-function-args for dataclasses using generic type aliases (PEP 695).

    Closes #10788 (#10788)

  • Fix a false positive for invalid-name where a dataclass field typed with Final was evaluated against the class_const regex instead of the class_attribute regex.

    Closes #10790 (#10790)

  • Avoid emitting unspecified-encoding (W1514) when py-version is 3.15+.

    Refs #10791 (#10791)

  • Fix a false positive relative-beyond-top-level error when linting specific files in namespace packages in parallel mode by augmenting sys.path before loading plugins and expanding files consistently for parallel workers.

    Closes #10794 (#10794)

  • Fix undefined-variable false positive when a name used as a metaclass argument in a nested class is referenced again later in the module.

    Closes #10823 (#10823)

  • Fix a false positive for unused-variable where global variables matching dummy-variables-rgx were still reported as unused when allow-global-unused-variables was disabled.

    Closes #10890 (#10890)

  • Fix # pylint: enable inside a try block leaking into the except handler. For example in the following code, no-member is no longer incorrectly re-enabled in the except block:

    class Basket:
        # pylint: disable=no-member
        def pick(self):
            try:
                # pylint: enable=no-member
                print(self.apple)  # no-member emitted here
            except KeyError:
                print(self.banana)  # no-member NOT emitted here (correct)
    

    Requires astroid 4.2.

    Refs #10933 (#10933)

  • Fix a false positive for bad-dunder-name when there is a user-defined __suppress_context__ attribute on exception subclasses.

    Closes #10960 (#10960)

  • Fix used-before-assignment false positive for names bound by from X import * in every branch of an if/elif/else chain.

    Refs #10980 (#10980)

Other Bug Fixes

  • Fix enabling checks from extensions which are disabled by default if multiple jobs are used.

    Closes #10037 (#10037)

  • wrong-import-position now exempts try, if, with, and match blocks from marking the import boundary. Fixed async def not being detected as an import boundary. Pragma on non-import lines now suppresses following imports until the next non-import.

    Closes #10589 (#10589)

  • Fix duplicate messages for extension checks if multiple jobs are used.

    Refs #10642 (#10642)

  • Fix --known_third_party config being ignored.

    Closes #10801 (#10801)

  • Fixed dynamic color mapping for "fail-on" messages when using multiple reporter/output formats.

    Closes #10825 (#10825)

  • dependency on isort is now set to <9, permitting to use isort 8.

    Closes #10857 (#10857)

  • Fix crash when checking attribute-defined-outside-init on classes that inherit from a base class pylint cannot fully analyze.

    Closes #10892 (#10892)

  • Fixed inflated message occurrence counts in the final Messages report when running pylint in parallel mode with --jobs greater than 1.

    Closes #10996 (#10996)

Other Changes

  • You can now set the files option in configuration files and on the command line. Passing files without the --files flag is still supported. This allows to set files to files = my_source_directory and invoking pylint with only the pylint command similar to how other CLI tools allow to do so. The help message can always be invoked with pylint -h or pylint --help.

    Closes #5701 (#5701)

  • Document that the wrong-import-order (C0411) classification of imports as third-party vs first-party depends on the current working directory and recommend known-first-party as the deterministic workaround.

    Closes #8801 (#8801)

Performance Improvements

  • Lazily import isort, dill, multiprocessing/concurrent.futures, and tomlkit so they are only loaded when actually needed. This reduces startup time by ~25% (e.g. --version: 91 => 67 ms, --help: 176 => 133 ms, single-file lint: 272 => 226 ms).

    Closes #2866 (#2866)

  • The duplicate-code checker no longer runs when its message (R0801) is disabled, even if reports=yes is set. Previously, the checker's report (RP0801) would cause the expensive similarity computation to run regardless.

    Closes #3443 (#3443)

  • Skip isort classification in the import checker when no import-ordering message is enabled, and cache the isort configuration so it is built once instead of once per import statement. Skipping the isort processing become a negligible improvement once the caching is applied. pylint became ~17% faster on ansible (~=4500 imports) even with isort enabled.

    Refs #10886, #2866, #10637 (#10886)