What’s New in astroid 4.3¶
What’s new in astroid 4.3.1?¶
Release date: 2026-08-17
Fix inference of the attributes of a
namedtuplecreated withrename=True. The renamed fields were applied to_fieldsand to the class body, but the instance kept the field names as written, so an instance ofnamedtuple("Tuple", "abc def", rename=True)was inferred as having adefattribute instead of_1, and duplicate field names collapsed into a single attribute instead of being renamed.Closes #242
What’s new in astroid 4.3.0?¶
Release date: 2026-08-07
Version 4.2.0 was skipped: a v4.2.0 tag was created by mistake during an
aborted release attempt, so the changes from the 4.2.0 betas are released
as 4.3.0.
Fix a crash on a functional
namedtuplewhose field name changes under NFKC normalization, such asnamedtuple("mu", ["µ"]). Python normalizes identifiers, so the parsed class stores the field under"μ"while the brain looked it up as written, raisingKeyErroron a definition thatnamedtupleitself accepts.Closes pylint-dev/pylint#8746
Fix inference of a method’s first argument (
selforcls) when the method’s return value is stored on an unrelated object. This avoids inferringclsas the caller’s class when indexing a tuple returned by a classmethod such asA.c()[0].Closes pylint-dev/pylint#11101
super()with no argument now resolves against the class of the object the method was called on, instead of the class the method is written in. One consequence is that atyping.Selfreturn value survives a chain ofsuper()calls.Closes #2852 Closes pylint-dev/pylint#10807
typing.overloadstubs no longer shadow the implementation when a special method is looked up in the MRO.Closes #2448
Fix a crash when the field names of a functional
Enumornamedtuplecall are bytes, as inEnum("", b""). Such a definition is invalid, so inference now falls back to its default instead of raisingTypeError.Closes #3189
Fix a crash when the body of a
typing.NamedTuplesubclass contains an assignment whose target is not a single name, such ascat.color = "black",basket[0] = "apple"orapple, banana = "red", "yellow". The names bound by unpacking are now copied to the inferred class as well.Closes #3190
Fix a crash when a binary operation involves a class whose metaclass is not a class, as in
class C(metaclass=sum)followed byC | None. The type of such a class is a function, which has no bases, sohas_known_bases()now returnsFalsefor anything that is not a class.Closes #3191
Fix a crash when a dataclass inherits from a dataclass that annotates
__init__as a field, as in__init__: int. Such a base binds__init__to a name instead of a function, so it no longer contributes arguments to the generated__init__.Closes #3200
The documentation build now fails on any Sphinx warning, so a cross-reference that does not resolve is caught by CI instead of quietly rendering as plain text.
Uninferable,Positionand theBadOperationMessageclasses are documented as part of the public API, and a number of docstrings that Sphinx could not parse were repaired.The
>>>examples in the documentation are run when the documentation is built, so one that stops being true is noticed. Most of them could not run before: they printed node addresses recorded in 2018, and the multi-line ones were missing the...continuation prompt. The example forDecoratorsreported the wrong line numbers.Fix the example in the docstring of
BoolOp, which showed the node it was copied from:astroid.extract_node("a and b")gives aBoolOp, not aBinOp.Names written between single backticks in the ChangeLog render as code again, rather than as italics.
Prevent crashes while processing extension-module classes whose bases cannot be resolved when applying enum inference transformations.
Closes pylint-dev/pylint#11179
The API documentation now covers the proxies, the objects with no node of their own, the inference context, the manager, the object models and the extension call signatures. The
EvaluatedObject,Interpolation,NamedExprandTemplateStrnodes were missing from the list of nodes and are listed now.Add
__required_keys__and__optional_keys__to the inferredTypedDictbase class, so subclasses no longer raise ano-memberfalse positive in pylint when accessing those attributes at runtime.Closes pylint-dev/pylint#10158
Comprehension conditions now constrain the inference of names used in the comprehension, like
ifstatement conditions already did:[x for x in lst if x is not None]no longer infersNoneforxin the element expression.Refs #3094
Fix
isinstance()constraints only filtering the first inferred value of a variable: checking a value made theisinstanceclassinfo uninferable for the checks of the following values.Remove Python 2 era dead code and outdated comments. Notably: the internal
TreeRebuilderconstructor no longer takes aparser_moduleargument.Refs #3154
Fix inference of a starred target that is not last in a
forloop, such asfor a, *b, c in .... The elements following the starred one were counted from the target’s own arity rather than from the end of the iterable, sobwas truncated whenever the iterable was longer than the target.Add
qname()method to theSlicenode class, returning"builtins.slice", so that the node can be used in contexts that require a qualified name (e.g. pylint’sbasic_checker).Closes #3115
Add brain tip for
numpy.fromfileso that calls tonp.fromfile(...)are correctly inferred as returningnumpy.ndarrayinstead ofUninferable.Closes #600
Add brain for
decimalthat gets applied if_decimalisn’t available.Removed the
**kwargsargument from allinferfunctions. Users upgrading theirastroidversions should ensure they do no pass values other thancontexttoinfer.Deduplicate keys when inferring
dict.fromkeys.dict.fromkeys("aab")now infers a dict with keys"a","b"instead of"a","a","b", matching the runtime. This also stopsdict.fromkeysfrom materializing oneConstnode per character for a repeated string such asdict.fromkeys("x" * 10 ** 8), which is a single-key dict.Bound str/bytes and list/tuple concatenation (
a + b) during inference.Bound oversized old-style (
%) string/bytes formatting during inference. A tiny literal such as"%1000000000d" % 1made_infer_old_style_string_formattingeagerly build a multi-gigabyteConstwhile inferring otherwise untrusted source. The width and precision are now read out of the conversion specifiers (including*fields) and the interpolation infers asUninferablepast1e8, mirroring the repetition, concatenation andstr.formatcaps. Bytes%formatting is routed through the same handler so it is bounded too; small format strings keep inferring their exact value.Fix crash (
TypeError: 'UninferableBase' object is not iterable) in themultiprocessingbrain when a local package shadows the stdlibmultiprocessingmodule.Closes pylint-dev/pylint#10014
Bound the number of nodes built when inferring
list/set/tuple/frozensetanddict.fromkeysfrom astr/bytesconstant. These built oneConstnode per character with no cap, solist(("a" * 10 ** 8) + "b")(concatenation is not size-bounded) materialized hundreds of millions of nodes. They now fall back to the default inference past1e8characters, matching the sequence-repetition guard.
Refs #3127
Bound string/bytes multiplication (
"x" * n) and integer left shifts (1 << n) inconst_infer_binary_opthe same way list/tuple multiplication and**already are. Inferring a constant such as"A" * 10 ** 10previously materialized the multi-gigabyte result eagerly; these operations now infer asUninferablewhen the result would be oversized.Refs #3107
Bound the field width and precision when inferring
str.formatcalls. A template such as"{:>2000000000}".format("x")(or a width/precision supplied through a nested{}field) previously built the padded multi-gigabyte string eagerly during inference; such calls now infer asUninferablewhen the field size would be oversized.Refs #3131
Remove the
asnamekeyword argument fromImport._inferandImportFrom._infer. The alias-to-real-name translation thatasname=Trueperformed is now hoisted intoImportNode._infer_name, which runs in_infer_stmtsbefore_inferis dispatched. Direct callers ofImport.infer/ImportFrom.infer(previously theasname=Falsepath) now consistently resolve the lookup name as-is.The two flows used to collapse into a single inference cache entry because the
asnamekwarg was not part of the cache key, so the second call returned the cached result of the first regardless of which one ran. With the translation hoisted upstream, the two flows set differentlookupnamevalues and therefore land on distinct cache keys, eliminating the collision.Refs pylint-dev/pylint#10193 Closes #3007
Avoid materializing a multi-gigabyte string while inferring a small literal such as
"{:>2000000000}".format("x")orf"{1.5:.2000000000f}"._infer_str_format_callandFormattedValue._infernow yieldUninferablewhen a format spec asks for a width or precision over 1e8, mirroring the sequence/repetition caps inastroid.protocols.
Refs #3108
Fix uncaught
IndentationErrorwhen parsing code whose lines end in\r: the slice of source tokenized to compute a class or functionpositionis split on\nonly and could be misaligned with the AST line numbers. Such nodes now simply have no position information, as already done whentokenizeraisesTokenError.Closes #3091
Support PEP 810 lazy imports (new in Python 3.15).
ImportandImportFromnodes gain anis_lazyinteger attribute, mirroring theastfield of the same name.Support PEP 798 comprehension unpacking (
{**d for d in dicts}, new in Python 3.15).Fix astroid bootstrap crash on PyPy 7.3.22 (
TypeError: expected str, got getset_descriptor object) by also catchingTypeErrorfromgetattr(obj, alias)inInspectBuilder.object_build. PyPy 7.3.22 raisesTypeErrorinstead ofAttributeErrorfor unset getset descriptors liketypes.FunctionType.__text_signature__, which made_astroid_bootstrapping()blow up on any call into astroid.Refs pylint-dev/pylint#10999
Shorten
import astroidby deferring imports only needed on cold paths.logging(used bymodutilsandraw_buildingsolely to report stderr/stdout captured while importing a module) andpprint(used only to format debug__repr__/repr_treeoutput) are now imported lazily, andastroid.exceptionsimportsastroid.typingunderTYPE_CHECKING.Fix
AttributeErrorcrash instarred_assigned_stmtswhen a starred unpacking target is an attribute (e.g.for *o.attr, x in ...) rather than a simple name.Closes #2646
Fix
AttributeErrorcrash in theArgumentsassigned_stmtsprotocol when called without an inference context (the publicassigned_stmtsAPI defaultscontexttoNone). Resolving a function’s first parameter dereferencedcontext.boundnodewhile the matchingcontext and ...guard a few lines below was missing; it now degrades to Uninferable.Fix
AttributeErrorcrash inClassDef.infer_call_resultwhen called through the public API without a context (it defaults toNone) for a class whose metaclass defines__call__: the callee was assigned tocontext.callcontext.calleewithout checking that a call context exists. It is now guarded, matching the surrounding code.Wrap assignment expressions (
:=) in parentheses when emittingas_stringoutput so the rendered code remains syntactically valid in contexts such as comparisons, where Python requires the walrus expression to be parenthesized.Closes #2668
Catch
MemoryError/RecursionError(andValueError) when validating type comments withast.parse. Pathological type comments produced by fuzzers (e.g.# type: i{{{{{{{...) previously crashed parsing with aMemoryErrororRecursionErrordepending on the runtime; astroid now treats them as invalid type comments and skips them, mirroring the f-string fix from #2762.Closes #2993
Bypass
__init__inInferenceContext.clone()and write the slots directly.clone()is called ~85k times per pandas/frame.py pylint run; skipping the conditional defaults shaves measurable time off the hottest constructor in inference.Refs #1115
Fix
TypeErrorinbrain_randomwhenrandom.sampleis called with a sequence containing nodes whose__init__does not acceptlineno(e.g.Module). The clone helper now filters init params to those the class actually accepts.Closes #3043
Fix
RecursionErrorin_compute_mro()when circular class hierarchies are created through runtime name rebinding. Circular bases are now resolved to the original class instead of recursing.Closes #3023 Closes pylint-dev/pylint#10821
Changed
block_rangeto considerelseits own block, allowingpylintto apply disables to just the block.References pylint-dev/pylint#872
Fix uncaught
TokenErrorwhen building a class or function whose source slice is malformed.tokenize.generate_tokensmay raise (e.g. on an unterminated bracket on Python < 3.12); position computation now treats such a node as having no position information instead of crashing.Closes #2527
str()of a constant argument now infers the actual string value instead of always inferring"". When every inference path of the argument resolves toConstvalues that stringify to the same string,infer_strreturns that string; otherwise it keeps falling back toConst("").Closes #2994
Fix
AttributeErrorcrash when looking up a special method on a class whose explicit metaclass infers to a non-class node (e.g. a function). Such a metaclass has no MRO, so the dunder lookup now raisesAttributeInferenceErrorinstead of crashing.Closes #3063
Fix
AttributeErrorcrash inClassDef.getitemwhen__class_getitem__resolves to a non-callable node (e.g. anAssignName).getitemnow raisesAstroidTypeErrorin that case, consistent with its documented behaviour.Closes #3064
Fix
DuplicateBasesErrorcrash in the enum brain when inferring an enum class with duplicate bases (e.g.class C(enum.Enum, enum.Enum)).infer_enum_classnow catchesMroErrorand leaves such a malformed class untransformed.Closes #3065
Fix
InferenceErrorcrash inClassDef.slots()when__slots__is declared as an annotation without a value (e.g.__slots__: None). Such a__slots__cannot be inferred, soslots()now returnsNone.Closes #3067
Fix
TypeErrorcrash in the enum brain when a functionalEnumcall has a non-string member name (e.g.Enum("e", (1,))). Such a definition is invalid, so inference now falls back to the default instead of crashing.Closes #3068
Fix detecting static/class methods and inspecting IntFlag types in GObject-based libraries (GLib, Gtk etc)
Only inject the
_HAS_DEFAULT_FACTORYsentinel into a module’s locals when the generated dataclass__init__actually references it. Parsing a module containing a dataclass without anyfield(default_factory=...)no longer exposes an unexpected_HAS_DEFAULT_FACTORYname.Closes #2808
Fix a crash when inferring
__func__on a bound method that proxies its function directly, such asA.method.__func__for a classmethod, or a lambda assigned to a class attribute such asA().lam.__func__.
Closes pylint-dev/pylint#11198
Add
qname()andpytype()to theTypeVar,ParamSpec,TypeVarTupleandTypeAliasnode classes, returning"typing.TypeVar","typing.ParamSpec","typing.TypeVarTuple"and"typing.TypeAliasType". PEP 695 type parameters and type aliases are inferred as themselves, so callers that ask an inferred value for its type crashed with anAttributeError, asFunctionDef.decoratornames()did for@Tinsideclass Basket[T].Refs #3115
Infer the value of a data descriptor of a C-implemented class as unknown instead of as a class named after the attribute. Reading such an attribute, for instance
exc.__traceback__.tb_frameorgen.gi_frame, inferred a class, so the attributes of the value the descriptor returns were reported as missing.raw_building.object_build_datadescriptor()now returns anEmptyNode.Closes pylint-dev/pylint#11218