Library / SDK
pylint-dev/astroid avatar
pylint-dev/astroid

astroid: the inference layer underneath pylint's static analysis

A common base representation of python source code for pylint and other projects

586 stars378 forksPythonLGPL-2.1

At a glance

What is it?
astroid is the library that gives pylint its understanding of Python code, rebuilding the builtin _ast tree into node classes that carry scope information and can infer what a name actually refers to. It suits anyone writing a Python static analysis tool, and it is a large codebase with a steep learning curve and a Python 3.11 floor.
Who is it for?
astroid is worth using if you are writing a Python linter, a type checker or a code intelligence tool and you do not want to reimplement scope resolution and inference, because the inference engine is the hard part of static analysis and it is already written and tested against a real linter. It is the wrong choice for a one-off script that just needs to walk a syntax tree, because the builtin ast module is enough for that.
Can I use it commercially?
Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A tree of nodes that know what names mean

Astroid's stated aim is to provide a common base representation of Python source code, and it is currently the library powering pylint's capabilities. The description in the package metadata calls it an abstract syntax tree for Python with inference support.

The mechanism is described concretely in the project documentation. Astroid provides a compatible representation which comes from the _ast module, and it rebuilds the tree generated by the builtin _ast module by recursively walking down the AST and building an extended ast. The new node classes have additional methods and attributes for different usages, and they include some support for static inference and local name scopes.

That last clause is the whole difference from the standard library. The builtin ast gives you a faithful syntax tree: a Name node, an Assign node, a FunctionDef. It does not tell you what a name refers to. Astroid's nodes carry scope information and can infer that a name resolves to a particular function, class or value in a particular scope, which is the prerequisite for every useful check. A linter that reports undefined-name, unused-import or no-member cannot do it from the builtin tree alone.

There is a third capability in the same description that is easy to miss: astroid can also build partial trees by inspecting living objects. So the representation is not only built from source text, it can also be built by asking an object what it is at runtime.

The topics list names the domain precisely, with inference-engine and parser alongside static-analysis and static-code-analysis. Astroid is the engine half of that stack.

Installing it, and the support policy is explicit about Python versions

The installation instructions are short, and there are two variants.

From a tarball, you extract it, change into the created directory and install:

bash
    pip install .

And for a development checkout, the editable form:

bash
    pip install -e .

The Python version story is stated in two places and they are not quite in step. The README says astroid 2.0 is currently available for Python 3 only, and that if you want Python 2 support you should use an older version of astroid, noting those versions are no longer supported. The package metadata is more current and more restrictive: requires-python is set to >=3.11.0, and the classifier list names Python 3.11, 3.12, 3.13 and 3.14 as supported versions, with Python 3 only as the language line.

So the practical floor is Python 3.11, and that is a real constraint for tooling that has to run on an older interpreter in CI.

The implementation is CPython first with PyPy also listed as a supported implementation, and the operating system is OS Independent, which is what you would expect of a pure analysis library that never executes the code it reads.

Support questions go to the [email protected] mailing list, and the documentation lives at astroid.readthedocs.io, with the project also linking the pylint documentation pages for the astroid documentation as the canonical URL.

The release machinery shows how a linter library is actually maintained

The packaging metadata is a good place to read the maintenance model, because it names the tools.

The build backend is setuptools with a requirement of setuptools>=77, and the project version is dynamic rather than hardcoded, which is the pattern that lets a release tool own it. The dev dependency group lists the three tools used when releasing: contributors-txt, tbump at about 6.11, and towncrier at 26.9 or newer.

Those three are the whole release story. tbump handles the version bump and the tag. towncrier builds the changelog from fragments. contributors-txt regenerates the contributor list, which explains the CONTRIBUTORS.txt file at the top of the repository and the fact that it is listed in the license-files alongside LICENSE.

There is a towncrier.toml at the top level and a tbump.toml, so the configuration for both is committed rather than living on a maintainer's laptop. There is a ChangeLog file as well, and a pylintrc, which tells you that astroid is linted with pylint itself, the sibling project.

The test story is tox and pytest, and the README is explicit that the tests are in the test subdirectory and that you can launch the whole suite with either:

bash
    tox
    pytest

The test dependency group explains what the suite needs beyond pytest itself: attrs, numpy for Python versions before 3.12, pyqt6, python-dateutil and regex. The numpy pin carries a comment explaining that a particular test data package declares its namespace through pkg_resources, so setuptools has to be pinned to a specific version. That level of detail in a dependency group is what a project looks like when its test suite genuinely runs the code paths it analyses.

A large codebase with an interface built for inference

The top-level entries describe a project with real infrastructure around it. There is the astroid/ package itself, a doc/ directory, a script/ directory, a tests/ directory, plus a .pre-commit-config.yaml, a .readthedocs.yaml, a codecov.yml, an AGENTS.md and a CONTRIBUTORS.txt.

The pre-commit configuration and the black badge in the readme are worth noting together. The project formats with black, runs pre-commit for that and for other checks, and reports coverage through codecov. Combined with pylint linting itself via the committed pylintrc, that is a project that treats its own tooling as part of the build rather than as an afterthought.

The scale is the other thing. An inference engine that can answer what a name refers to in any scope, with partial trees built from live objects as well as from source, is not a small library. The node classes carry additional methods and attributes for different usages, and the ones you will use in a checker are not the ones you would write yourself against the builtin ast.

That is the trade you are making. You give up the familiarity of the standard library's ast module, whose node classes you can look up in the documentation and whose behaviour you already know from writing tools, and you get an engine that answers questions the standard library cannot.

For a project whose entire purpose is to check other people's Python, that is a good trade. For a script that wants to find every function call in a file, it is a heavy one, and the builtin ast module plus a dozen lines of your own visitor would be enough.

Where astroid is the wrong tool

The first limit is the Python 3.11 floor, and it bites in a specific place. Analysis tools are often run in CI against a matrix of Python versions, and a library that requires 3.11 cannot be installed on the older interpreters in that matrix. There is no compatibility shim in the packaging, just requires-python.

The second is the size of the abstraction. The extended node classes carry scope information, inference and additional methods, which is what makes the library valuable and also what makes it a large surface to learn. A developer who knows the builtin ast can read a pylint plugin in an afternoon; a developer who does not know astroid will spend that time on the node API first.

The third is the coupling to a moving target. Astroid exists to model Python's own semantics, so every new syntax feature in the language is a change astroid has to track. The release line shows how often that happens, with v4.3.2 on 2026-09-25, v4.3.3 on 2026-09-30 and v4.3.4 on 2026-10-08, three releases in a fortnight. That pace is fine for a project that consumes astroid and keeps up, and awkward for one that pins a version and then finds a Python release has moved underneath it.

The fourth is the licence, and it deserves a direct mention rather than a paragraph of hedging. The package metadata records LGPL-2.1-OR-later, and the LICENSE file is listed among the license files. For a library that other programs import, the LGPL's requirements about what you do when you ship a modified version are the part your legal team will want to see. This is not a licence to copy a sentence about; it is a licence to read before you embed astroid in a product.

The fifth is that inference is not a solved problem and astroid's answers are its own. A checker built on it inherits its model of what Python means, including the cases where that model is a simplification. When a checker reports something surprising, the question of whether the inference or the check is wrong is a real debugging task, and the library's size makes that task slower than it would be with a simpler tree.

Editorial conclusion

astroid is worth using if you are writing a Python linter, a type checker or a code intelligence tool and you do not want to reimplement scope resolution and inference, because the inference engine is the hard part of static analysis and it is already written and tested against a real linter. It is the wrong choice for a one-off script that just needs to walk a syntax tree, because the builtin ast module is enough for that. Before you depend on it, check the three things the packaging metadata states: that Python 3.11 or later is required, so an older runtime is out; that the licence is LGPL-2.1-OR-later, which is a meaningful constraint if you intend to link it into a closed-source product; and that the release line moves fast, with v4.3.2, v4.3.3 and v4.3.4 published in the space of a fortnight in late September and October 2026, so pin a version rather than tracking the branch.

Frequently asked questions

What is astroid and what does it do?

Astroid provides a common base representation of Python source code, rebuilding the tree from the builtin _ast module into extended node classes with additional methods and attributes, support for static inference and local name scopes. It is the library currently powering pylint's capabilities, and it can also build partial trees by inspecting living objects.

How do I install astroid?

Extract the tarball, change into the created directory and run pip install ., or use pip install -e . for an editable installation. The package requires Python 3.11 or later, supports CPython and PyPy, and the operating system is listed as OS Independent.

How do I run the astroid test suite?

The tests are in the test subdirectory and the whole suite can be launched with either tox or pytest. The test dependency group adds attrs, numpy for Python versions below 3.12, pyqt6, python-dateutil and regex on top of pytest.

Official sources

  1. License: LGPL-2.1
  2. Project website
  3. pylint-dev/astroid on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pylint-dev-astroid.svg)](https://hysenlabs.com/projects/pylint-dev-astroid)

Was this useful?