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

{{< callout type="warning" >}}
distutils was deprecated in Python 3.10 and removed in Python 3.12. Projects still importing from `distutils.core` must migrate to a modern [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md) configured through [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md).
{{< /callout >}}

## Original workflow

distutils handled package building, installation, and distribution through a `setup.py` script:

```python
from distutils.core import setup

setup(
    name="example",
    version="1.0",
    py_modules=["example"],
)
```

Running `python setup.py install` copied modules to the target system. Running `python setup.py sdist` produced a source distribution archive.

## Relationship to setuptools

[setuptools](https://pydevtools.com/handbook/reference/setuptools.md) 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.

## Pros

- Shipped in the Python standard library; no extra install required
- Defined the universal baseline every packaging tool extended for two decades
- Supported C extension compilation on all major platforms

## Cons

- No dependency resolution: could not declare or install transitive dependencies
- Poor extensibility: custom build steps required subclassing undocumented internals
- Brittle compiler handling: C extension flags were platform-dependent and hard to tune
- Removed in Python 3.12; unavailable on any modern Python

The limitations were felt most acutely in scientific computing. NumPy had to override nearly all of distutils to support Fortran, C++, and Cython, producing a parallel fork (`numpy.distutils`) that became a long-running maintenance burden. NumPy has since migrated to meson-python.

## Deprecation and Removal

[PEP 632](https://peps.python.org/pep-0632/) (distutils deprecation) 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` must migrate to a modern [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md) configured through [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md). Options include [setuptools](https://pydevtools.com/handbook/reference/setuptools.md), [hatchling](https://pydevtools.com/handbook/reference/hatch.md), meson-python, and [scikit-build-core](https://pydevtools.com/handbook/reference/scikit-build-core.md).
