distutils: Python's Original Build System
distutils was a standard library module that provided the original mechanism for building and distributing Python packages. It defined the setup.py-based workflow that became the foundation of Python packaging for over two decades.
What It Did
distutils handled package building, installation, and distribution through a setup.py script:
from distutils.core import setup
setup(
name="example",
version="1.0",
py_modules=["example"],
)Running python setup.py install would copy modules into the correct location on the target system. Running python setup.py sdist would produce a source distribution archive.
Limitations
distutils worked for simple packages but struggled with anything beyond the basics:
- No dependency resolution. It could not declare or install package dependencies.
- Poor extensibility. Adding custom build steps required subclassing internal commands with minimal documentation.
- Opaque compiler handling. Configuring compiler flags for C extensions was brittle and platform-dependent.
These gaps were felt most acutely in scientific computing. NumPy had to override nearly all of distutils to support Fortran compilers, C++ compilation, Cython integration, and cross-platform build configurations. That fork, numpy.distutils, became a parallel maintenance burden for years.
Relationship to setuptools
setuptools was created as a direct extension of distutils, adding dependency declaration (install_requires), automatic package discovery, entry points, and egg/wheel distribution formats. For most of its history, setuptools monkey-patched distutils at import time to layer these features on top.
Deprecation and Removal
PEP 632 deprecated distutils in Python 3.10 and scheduled its removal. Python 3.12 completed that removal.
Projects that relied on from distutils.core import setup or distutils.core.Extension need to migrate to a modern build backend configured through pyproject.toml. Options include setuptools, hatchling, meson-python, and scikit-build-core.
Learn More
- PEP 632: Deprecate distutils module
- Python 3.11 distutils documentation (last version with distutils)
- Migrating from distutils