Skip to content

Releases: pylint-dev/pylint

v4.1.3

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 11 Oct 07:41
e75de10

What's new in Pylint 4.1.3?

Release date: 2026-10-11

False Positives Fixed

  • Fixed a false positive for attribute-defined-outside-init when an
    attribute is assigned inside the setter of an old-style, non-decorator
    property(fget, fset) call. The decorator form (@property /
    @x.setter) was already exempted by the fix for #409; the classic
    call form was not.

    Closes #3325

  • Fix a false positive for used-before-assignment when a name bound by an earlier
    target of the same assignment is used by a later target, as in a = b[a] = 0.

    Closes #5955

  • Fix a no-member false positive in a comprehension inside a branch that
    cannot run, such as if sys.platform == "win32": on Linux. Like the rest of
    the branch, the comprehension is no longer checked for missing members.

    Closes #7240

  • Fix a false positive for used-before-assignment when a name bound by a tuple
    or list target of a with item is used by a later item of the same with statement.

    Closes #7545

  • Fix false positives such as not-callable, not-an-iterable,
    unpacking-non-sequence and no-member on the result of a function whose
    body is only ..., like @overload and .pyi stubs. Such calls were
    inferred as returning None. This affected sqlalchemy.func,
    pydantic.Field, and the torch functions wrapped by _add_docstr,
    such as torch.linalg.qr.

    Closes #8138
    Closes #9218
    Closes #9354
    Closes #10087

  • Fix a false positive for protected-access when a subclass of a subscripted
    generic base, such as class Child(Parent[T]), accesses a protected member
    through that base, such as Parent._foo(self).

    Closes #8600

  • Avoid emitting unreachable for a yield immediately after raise or
    sys.exit() that marks a function as a generator, matching the existing
    handling of return.

    Closes #8909

  • Fix a false positive for super-init-not-called in .pyi stub files, where
    every __init__ body is ... and cannot call the parent's __init__.

    Closes #9096

  • Fix a false positive for possibly-used-before-assignment when a lambda
    uses its parameters, including from a nested lambda, and that name is assigned
    later in the module.

    Closes #9126

  • Fix a false positive for useless-parent-delegation when a keyword-only
    parameter is passed to the parent under the same keyword but with a different value.

    Closes #9226

  • Fix a false positive for unused-argument in .pyi stub files, where
    function bodies are ... and cannot use their arguments.

    Closes #9417

  • Fix a false positive for used-before-assignment when a name assigned with an
    assignment expression in the condition of a comprehension is used in its element,
    for example [y for x in data if (y := f(x))].

    Closes #9460

  • Fixed false positive arguments-differ and signature-differs for
    typing.overload stubs. Overload stubs in a subclass are no longer compared
    to the overridden method, and an overridden method with overloads is compared
    through its implementation instead of its first stub.

    Closes #10186
    Closes #5264

  • Stop emitting redefined-variable-type when the bare _ variable is
    reused to discard values of different types.

    Closes #10374

  • Allow the __main__ module name in the camelCase, PascalCase and
    UPPER_CASE naming styles without reporting invalid-name.

    Closes #10442

  • Fixed a false positive for unexpected-keyword-arg when a decorator that
    returns its argument unchanged is stacked above a decorator accepting **kwargs.

    Closes #10831

  • Fix invalid-name false positives for module-level all-caps aliases that
    preserve the name of an external callable.

    Closes #11012

  • redefined-builtin no longer warns for method parameters that retain a
    built-in name from an overridden method.

    Closes #11438

  • Fixed a false positive for useless-suppression of line-too-long when a # inside a string literal comes before the # pylint: disable=line-too-long comment.

    Closes #11440

  • Fix a false positive for unnecessary-ellipsis when an ellipsis is the
    sole body statement of a Protocol method defined inside a conditional block
    such as if TYPE_CHECKING:.

    Closes #11459

  • Fix a false positive for unnecessary-negation when negating a comparison
    between instances of a set or frozenset subclass.

    Refs #11513

Other Bug Fixes

  • Fix pyreverse hanging or crashing with a RecursionError when
    --all-associated (-S) follows an attribute whose inferred class is rebuilt by
    astroid on every inference, such as a numpy array.

    Closes #3602

  • Fix a crash in pyreverse when a diagram includes a class created by
    namedtuple, or an argparse.Namespace.

    Closes #10767

  • The "difference" column of the "Messages by category" and "Duplication" reports
    (--reports=y) now shows the change since the previous run instead of repeating
    the previous count.

    Closes #11520

  • Fixed nested-min-max suggesting a non-equivalent rewrite when an inner
    min/max call had multiple arguments.

    Refs #11593

  • Using several output formats that all write to stdout (for example --output-format=colorized,no-header)
    now raises an error instead of printing every message more than once.

    Closes #11597

  • Fixed an IndexError crash in the typecheck checker when an Enum class defines an __init__ method without arguments.

    Closes #11608

  • Fix a crash in the duplicate-code checker when min-similarity-lines is set to 0.
    The checker is now disabled in that case, as documented.

    Closes #11625

v4.1.2

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 02 Oct 22:13
40be3a2

What's new in Pylint 4.1.2?

Release date: 2026-10-03

False Positives Fixed

  • Fixed a false positive unbalanced-tuple-unpacking when unpacking a tuple
    concatenation whose elements have several possible values.

    Fixed by upgrading astroid to 4.3.3.

    Closes #2621

Other Bug Fixes

  • Fixed a crash when calling __bases__ on a class.

    Fixed by upgrading astroid to 4.3.3.

    Closes #11491

  • Fix a crash (astroid-error) when the class of a called attribute cannot
    be fully inferred, for example when the attribute is used as a with
    statement target or inside a comprehension.

    Closes #11492

  • Fix a crash when a name bound by a type statement (a TypeVar) is used in a with statement.

    Closes #11510

  • Fixed a crash (TypeError) in the variables checker when checking a class
    whose metaclass name binding has no line number, for example a class defined
    with metaclass=__annotations__.

    Closes #11511

  • Fix a crash in the using-final-decorator-in-unsupported-version check
    when import final is used.

    Closes #11521

  • Fix a crash when a plugin passes confidence=None to add_message, as
    pylint-pytest does, for a message that is disabled. confidence=None is
    accepted again and means UNDEFINED, like in pylint 4.0. Passing it
    explicitly to add_message, add_ignored_message or Message now emits a
    DeprecationWarning: it will raise an error in pylint 5.0.

    Closes #11530

v4.1.1

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 29 Sep 21:09
8c6daca

What's new in Pylint 4.1.1?

Release date: 2026-09-29

Other Changes

  • Pylint 4.1.0 could not be uploaded to PyPI, because it required an unreleased
    version of dill on Python 3.15, and PyPI refuses such a dependency. 4.1.1 is
    the first 4.1 release available on PyPI, see the 4.1.0 changes below.

    Refs #11495

v4.1.0

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 29 Sep 20:00

What's new in Pylint 4.1.0?

Release date: 2026-09-29

Startup is about 25% faster thanks to lazy imports. The import checker caches
its isort configuration, which makes pylint about 17% faster on ansible.
Finding the files to lint with --recursive=y no longer walks ignored
directories such as .venv or node_modules, which took seconds on large
trees. The duplicate-code checker and symilar also received optimizations
that result in considerable performance improvements and memory use reduction
on larger codebases. For example, pandas analysis went from 20 min to 55 s and
pylint does not get OOM-killed when analyzing cpython anymore.

Python 3.15 support progresses: the unpacking in comprehensions added by
PEP 798 no longer raises false positives, and the standard library
deprecations of Python 3.15 are followed.

For CI, there is a new built-in junit output format
(--output-format=junit), the NO_COLOR and FORCE_COLOR environment
variables are respected, and the files to lint can now be set with the
files option in the configuration file.

New checks: looping-through-iterator, impossible-comparison,
chained-comparison-all-equal and
using-comprehension-unpacking-in-unsupported-version.

Running with --jobs no longer duplicates the messages of extensions or
ignores extensions enabled in the configuration.

Plugin authors: the confidence parameter can no longer be None, except
in is_message_enabled, and the MSG_STATE_* constants are deprecated in
favor of the MessageDisableReason enum.

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

Breaking Changes

  • The confidence parameter is no longer nullable on any APIs except for
    is_message_enabled (where confidence=None means "don't filter by
    confidence"). The default became interfaces.UNDEFINED (an immutable value);
    the behavior is unchanged unless you were passing an explicit None. This
    avoids a runtime check in multiple function to set the default value conditionally.

    The constants.MSG_STATE_* integer were replaced by a MessageDisableReason enum.
    The old names remain as deprecated aliases pointing at the enum members.
    MessageDisableReason is an IntEnum so existing code comparing the return of
    _get_message_state_scope to the literal 0 / 1 / 2 keeps working.

    Refs #11018

New Features

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

    Refs #3352

  • Support for the NO_COLOR and FORCE_COLOR environment variables has been added.
    When running pylint, the reporter that writes to stdout is switched between text
    and colorized according to the requested mode.
    The order is: NO_COLOR > FORCE_COLOR > --output-format=....

    Closes #3995

  • 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

  • Add a built-in junit output format (--output-format=junit) that produces JUnit-compatible XML output for CI/CD integration with Jenkins, Azure DevOps, GitLab CI, and GitHub Actions.

    Closes #9143

  • Trailing pragmas understood by other common tooling (# type: ignore,
    # pyright: ignore, # noqa, # pragma: no cover and
    # pragma: no branch) are no longer counted toward the line length, so a line
    is not flagged as line-too-long solely because of such a pragma. This mirrors
    the existing behaviour for Pylint's own # pylint: pragmas.

    Closes #10172

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

    Closes #10772

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

    Refs #10803

New Checks

  • Added a new checker looping-through-iterator (W4801) to detect when an iterator from an outer scope is consumed in a nested loop, which can lead to the iterator being unexpectedly exhausted.

    Refs #2996

  • Add new checks impossible-comparison and chained-comparison-all-equal.
    impossible-comparison flags boolean conditions whose chain of numeric
    comparisons is logically contradictory and can never be true (for example
    a > b and b > a). chained-comparison-all-equal flags boolean conditions
    whose operands form a cycle of weak inequalities (<= or >=) and can be
    simplified to a chain of equalities (for example a >= b and b >= a is
    equivalent to a == b).

    Closes #5814

  • Add using-comprehension-unpacking-in-unsupported-version (W2607), emitted when
    the code uses the unpacking in comprehensions added by PEP 798 while
    py-version still includes a Python version that cannot compile it.

    Refs #10982

False Positives Fixed

  • Fix a false positive for unnecessary-negation (C0117) when negating a
    comparison between dict views (dict.keys()/dict.items()), which like
    set/frozenset support only a partial (subset/superset) ordering, so
    not a.items() <= b.items() is not equivalent to a.items() > b.items().

    Closes #3668

  • Fix false positives for attribute-defined-outside-init where __init__
    (etc.) uses a helper method to create attributes.

    Closes #5214

  • Fix a false positive for consider-using-generator and use-a-generator
    with an asynchronous list comprehension. Turning it into a generator expression
    would create an asynchronous generator, which those functions cannot consume.

    Closes #7271

  • Fixed a false positive assigning-non-slot when assigning to an inherited
    descriptor through an instance returned by a method annotated with the
    subclass. This regressed in pylint 3.0.0.

    Fixed by upgrading astroid to 4.1.0.

    Closes #8053

  • Fixed a false positive no-member when a classmethod annotated with
    typing.Self is overridden in a subclass and its result is used directly,
    as in Subclass.build().only_on_subclass(). The return type is now narrowed
    to the subclass rather than the base class. This regressed in pylint 3.0.0.

    Fixed by upgrading astroid to 4.1.0.

    Closes #9159

  • Avoid emitting deprecated-class for imports inside a recognized
    sys.version_info guard.

    Closes #9533

  • Fix a false positive for inconsistent-return-statements when an instance
    method annotated with NoReturn (or Never) is called via the class
    rather than an instance (e.g. MyClass.raise_method(obj)). The unbound
    method form is now recognised as never returning, matching the existing
    behaviour for the bound-method form.

    Closes #9692

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

    Closes #9879

  • Fix a false positive for useless-parent-delegation when a method overrides a
    method of a C-level parent whose signature cannot be inspected, such as
    Exception.__init__. Because Exception.__init__ accepts *args, an
    override taking only self narrows the accepted arguments and is not useless.
    Overrides of object.__init__ are still reported.

    Closes #9994

  • Fixed a false positive no-name-in-module when a module is imported with
    an alias that shadows its base module and a function named format is
    called on the alias.

    Fixed by upgrading astroid to 4.3.1.

    Closes #10193

  • Fixed a false positive unsubscriptable-object on instances of a generic class defining __class_getitem__.

    Closes #10360

  • Fixed a false positive unexpected-keyword-argument when passing dtype
    to numpy.concatenate().

    Fixed by upgrading astroid to 4.3.1.

    Closes #10548

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

    Closes #10703

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

    Closes #10785

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

    Closes #10788

  • 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

  • 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

  • Fix false positives for the Python 3.15 syntax added by PEP 798, unpacking in
    comprehensions:

    • star-needs-assignment-target (E0114) was emitted for the unpacked element
      of a comprehension, e.g. [*sub for sub in lists].
    • consider-using-dict-comprehension (R1717) was emitted for
      dict([*pairs for pairs in nested]), which flattens its argument and is
      therefore not equivalent to a key/value dict comprehension.

    Refs #1...

Read more

v4.0.10

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 29 Sep 15:47

What's new in Pylint 4.0.10?

Release date: 2026-09-29

False Positives Fixed

  • Fix false positives for :ref:unnecessary-lambda when a variable referenced in
    the called expression is assigned, reassigned, or deleted later in the same scope.

    Closes #8192

  • Fix a false positive for unused-argument in dataclass __new__ methods
    when the arguments are consumed by a generated __init__ method.

    Closes #9843

  • Fix a false positive for missing-kwoa when keyword-only arguments are passed
    through a **kwargs dictionary that is not a literal at the call site, for
    example one filled with options["key"] = value after its creation.

    Closes #10029

  • ungrouped-imports no longer reports imports inside mutually exclusive
    OS guard branches (if os.name == "nt": / if sys.platform == "win32":),
    matching the existing behavior for sys.version_info guards.

    Closes #10460

Other Bug Fixes

  • A TypeError crash could occur when checking a for loop that
    iterates over a subscript with non-numeric constant bounds or a zero
    step, e.g. for a, b in {"k": [][0: ""]}.values():.

    Closes #11472

  • Fix a crash (AttributeError: 'ClassDef' object has no attribute 'expr') in the
    import-private-name extension when an annotated assignment's value is an
    attribute access on a call rooted at a non-Name node, e.g. x: str = ''().a.

    Closes #11479

v4.0.9

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 23 Sep 15:25
303703f

What's new in Pylint 4.0.9?

Release date: 2026-09-23

Security Fixes

  • Someone without access to the configuration or linted code, but with access
    to the cache directory (predictable PYLINT_HOME on a multi-user host) can no
    longer write a crafted pickle that will runs arbitrary code when pylint access its
    stat cache. The result cache is now stored as JSON instead of pickle,
    preventing code-execution. The workaround is upgrading or not pointing PYLINT_HOME
    to an untrusted, shared, or group-writable directory. The default value, ~/.cache/pylint,
    is writable only by the user running pylint. (CVE with the same information pending)

False Positives Fixed

  • Fixed a false positive for no-self-use on a method that only uses
    self before a locally defined class (or other nested method), because
    the checker's could-be-a-function tracking state was not restored after
    visiting the nested method.

    Closes #3705

  • Fix a false positive for :ref:not-callable when calling functions constructed with
    types.FunctionType or types.LambdaType.

    Closes #7500

  • Fix a false positive for unnecessary-direct-lambda-call when a directly called
    lambda in a class body wraps a comprehension containing an assignment expression.
    PEP 572 makes that a SyntaxError without the lambda's scope, so following the
    message produced code that would not compile.

    Closes #9294

  • Fix a false positive for :ref:unnecessary-ellipsis when an ellipsis is the
    sole body statement of a method defined on a Protocol.

    Closes #9319

  • Fix a false positive for :ref:bad-exception-cause when the bases of the class
    being raised from cannot be inferred, such as an exception deriving from a
    C extension class. :ref:raising-non-exception and
    :ref:catching-non-exception already guard the same inherit_from_std_ex
    helper with has_known_bases.

    Refs #11399

False Negatives Fixed

  • method-hidden is no longer silenced when the hidden method shares its name with
    a builtin function or with a function defined at module level. Only members of the
    ancestor classes themselves can excuse the method now.

    Refs #11361

Other Bug Fixes

  • Fix a block-scoped # pylint: disable= directive placed inside an if
    body leaking into sibling elif/else blocks for messages such as
    stop-iteration-return, which default to a line-based (rather than
    node-based) message scope.

    Closes #3136

  • Fix a false positive for declare-non-slot when a class variable is
    annotated with ClassVar without an initial value.

    Closes #9950

  • Fix a crash in the no-member checker when attribute lookup raises an
    InferenceError.

    Closes #11356

  • Fix a crash in the unnecessary-default-type-args check when a Generator
    or AsyncGenerator subscript holds an empty tuple, such as Generator[()].

    Closes #11357

  • Fix a crash in method-hidden when a method shadows a name that builtins
    binds to a node without a statement, such as help or license. Every class
    inherits from object, which lives in the builtins module, so no base class
    was needed to trigger it.

    Closes #11361
    Closes #8079

v4.0.8

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 29 Aug 12:21
ecb84ba

What's new in Pylint 4.0.8?

Release date: 2026-08-29

False Positives Fixed

  • Fix a false positive for :ref:unspecified-encoding when an open call uses a mode
    argument that cannot be inferred.

    Closes #10201

  • Fix a false positive for invalid-name (C0103) on names assigned in an
    if __name__ == "__main__": block. Such a block reads like a script body, so
    a name there is now accepted if it matches either the constant or the variable
    naming style.

    Closes #10766

  • Fix false positives for :ref:invalid-str-returned, :ref:invalid-repr-returned,
    :ref:invalid-format-returned, :ref:invalid-bytes-returned, :ref:invalid-hash-returned,
    :ref:invalid-index-returned, :ref:invalid-length-returned,
    :ref:invalid-length-hint-returned, :ref:invalid-getnewargs-returned and
    :ref:invalid-getnewargs-ex-returned when the returned value is an instance of a
    subclass of the expected builtin type, such as self in a str subclass or a
    namedtuple.

    Closes #11306

  • Fix false positives for :ref:bad-string-format-type when the argument is an
    instance of a subclass of int, float or str, such as bool or an
    IntEnum member formatted with %d.

    Closes #11315

False Negatives Fixed

  • redundant-unittest-assert now also flags assertEqual and assertNotEqual
    when both compared values are constants, e.g. self.assertEqual(5, 5).

    Closes #11321

Other Bug Fixes

  • Fix a crash in the docparams extension when a raised name does not infer to an exception, such as raise sum or raise some_module. Such objects have no ancestors(), which aborted the whole file with an astroid-error fatal message.

    Closes #11228

  • Fix a crash in the use-yield-from checker (AttributeError: 'Subscript' object has no attribute 'name') when a loop target is a subscript, attribute, or tuple.

    Closes #11286

  • Fix a crash in the docparams extension (AttributeError: 'AssignName' object has no attribute 'decorators') when a class has non-function attributes sharing the name of a property setter.

    Closes #11287

Other Changes

  • Upgrade the isort upper bound so isort 9 can be installed alongside pylint.

    Closes #11351

v4.0.7

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 09 Aug 19:12
c6768d3

What's new in Pylint 4.0.7?

Release date: 2026-08-09

False Positives Fixed

  • Fix a false positive for invalid-name when a module-level variable is assigned
    an instance of a TypedDict subclass. Such a name is a value, not a type
    definition, so it is now checked against the constant or variable regex instead
    of class-rgx.

    Closes #11231

Other Bug Fixes

  • Fix a crash in the bad-open-mode check when the mode argument of
    open is the NotImplemented constant (Python >= 3.14).

    Closes #11099

  • Fix a crash in the not-context-manager and not-async-context-manager
    checks when the context manager infers to a value without a name, such as the
    slice returned by with slice(...) / async with slice(...).

    Closes #11102

  • Fix a false positive for nested-min-max (W3301) when the inner min/max call carries a keyword argument such as key=. Flattening the call dropped the keyword and changed the result, so nested calls whose inner call has keyword arguments are no longer flagged.

    Closes #11130

  • Fix a false suggestion from nested-min-max (W3301): when rewriting a nested min/max into a splat call, arguments positioned after the splatted call were silently dropped, so the suggested code changed the result.

    Closes #11134

  • Fix a false positive for too-many-locals (R0914): PEP 695 type parameters, i.e. the T1 and T2 in a generic def f[T1, T2] signature, were counted as local variables. They are type-system constructs, not runtime locals, and are now excluded from the local-variable count.

    Closes #11136

  • Fix literal-comparison (R0123) emitting a corrupted suggestion for identifiers
    that contain is (e.g. axis is 5 was rendered ax== == 5). The suggestion
    is now rebuilt from the operands and operator.

    Closes #11146

  • Fix false positives in bad-string-format-type (E1307) for valid % formatting:
    %i/%u applied to a float (both truncate like %d) and %a applied to any
    non-int type (%a is type-agnostic like %s/%r).

    Closes #11147

  • Fix a false positive for :ref:useless-parent-delegation when an override changes
    the default value of a positional-only parameter.

    Closes #11148

  • Fixed a crash in comparison-with-callable when comparing a lambda assigned as a class attribute.

    Closes #11175

  • too-many-lines could be reported at the line of a # pylint: disable=too-many-lines
    pragma found in a previously linted module. Pragma positions are now reset between
    modules, so the message is reported at line 1 (or at the current module's own pragma)
    regardless of which files were linted before.

    Refs #11191

  • Fix a crash when a call unpacks a dictionary whose keys are not string
    constants, e.g. copy.copy(**{-1: 1}).

    Closes #11222

v4.0.6

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 14 Jun 14:42
8a39635

What's new in Pylint 4.0.6?

Release date: 2026-06-14

False Positives Fixed

  • implicit-str-concat is no longer emitted for an implicit concatenation of
    a raw string with a non-raw one (e.g. r"\d" "\n"). Such literals cannot be
    merged into a single string, so the concatenation is intentional rather than a
    forgotten comma.

    Closes #6663

  • Fix a false positive for invalid-name (C0103) where the default
    typevar-rgx rejected TypeVar names containing digits, such as
    Ec2T.

    Closes #8499

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

    Closes #8675

  • Fix a false positive for no-member when a value is inferred to several
    possible types and at least one of them defines a dynamic __getattr__.

    Closes #9833

  • Fix a false positive for function-redefined (E0102) when reusing names that
    match dummy-variables-rgx (such as _), which is common for
    pytest-bdd step definitions. This restores the behavior from before pylint
    4.0.0; as a consequence the false negative fixed in #9894 is reintroduced for
    functions whose name matches dummy-variables-rgx.

    Closes #10665

  • 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

  • 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

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

    Closes #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

  • Check for metaclass call signature when evaluating arguments of a class call.

    Closes #11032

  • Fix false positive method-hidden when cached_property is imported directly with from functools import cached_property.

    Refs #11037

Other Bug Fixes

  • Fix the suggestion of unnecessary-comprehension for a dict comprehension
    that iterates a dict directly, e.g. {a: b for a, b in d}. Iterating a dict
    yields its keys, so the suggestion is now dict(d.keys()) instead of the
    incorrect dict(d), which would simply copy d.

    Closes #8256

  • Fix a crash in consider-using-enumerate when the for loop target is an attribute (e.g. for self.idx in range(len(x))) rather than a simple variable name.

    Closes #10099

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

    Closes #10892

  • Fix add_message silently overwriting an explicit col_offset=0 (or any other zero-valued line/end_lineno/end_col_offset) with the AST node's value. The internal _add_one_message helper used a falsey check (if not col_offset:) to detect an omitted argument, which incorrectly treated a legitimate 0 the same as None. It now uses an identity check against None.

    Refs #11020

  • Fix a crash in the name checker when a non-constant value is passed as the covariant or contravariant argument of a TypeVar.

    Closes #11022

  • Fix a crash in the variable checker when a name resolves to a dataclass-synthesized __init__, which has no line number.

    Closes #11023

  • Fix a crash in the variables checker when NotImplemented is used as the test of an if statement, which raised a TypeError in a boolean context on Python 3.14.

    Closes #11025

  • Avoided a crash from the implicit booleaness checker for len() calls without arguments.

    Closes #11028

  • Fix a crash in the variables checker when a class declares a metaclass whose
    attribute-access chain does not bottom out at a name (e.g.
    class C(metaclass=None._)).
    Originally reported as pylint-dev/astroid#3066.

    Refs #11031

  • Fix a crash in the name checker when a chained assignment of a TypeAlias
    value has a non-name target such as a Subscript (for example
    a[0] = b = TypeAlias).

    Closes #11056

  • Fix a crash in the deprecated checker when __import__ is called with a
    non-string constant argument (for example __import__(1)).

    Closes #11059

  • Avoid crashing when enum member inference fails while checking enum subclasses.

    Closes #11069

  • Prevent a crash in unexpected-keyword-arg analysis when
    infer_call_result() raises InferenceError while inspecting
    decorator return signatures.

    Closes #11070

  • Fix a crash in the typecheck checker when a class uses a non-class object
    (for example a function) as its metaclass= argument.

    Closes #11071

  • Allow digits in ParamSpec and TypeVarTuple names for invalid-name check.

    The default paramspec-rgx and typevartuple-rgx patterns rejected names
    containing digits (e.g. Ec2P, S3Ts), emitting a false invalid-name
    (C0103). Allow digits in the lowercase segments, consistent with the
    typevar and typealias patterns.

    Closes #11090

Performance Improvements

  • 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

v4.0.5

Choose a tag to compare

@Pierre-Sassoulas Pierre-Sassoulas released this 20 Feb 09:06
88e1ab7

What's new in Pylint 4.0.5?

Release date: 2026-02-20

False Positives Fixed

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

    Closes #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

  • 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

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

    Refs #10791

Other Bug Fixes

  • Fix --known_third_party config being ignored.

    Closes #10801

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

    Closes #10825

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

    Closes #10857