Introduction
Setuptools is deprecating the legacy setup.py-only packaging format in favor of PEP 517/518 pyproject.toml-based builds. While existing setup.py files still work, they trigger warnings and future versions of pip will refuse to use them. Projects need to migrate to pyproject.toml for forward compatibility.
Symptoms
WARNING: Running setup.py install for package is deprecated. Use pip install with PEP 517 builds.DEPRECATION: package is being installed using the legacy 'setup.py install' methodUserWarning: setup.py install is deprecated. Use buildpip installoutput shows:Preparing metadata (setup.py) ... doneinstead ofPreparing metadata (pyproject.toml)
DEPRECATION: mypackage is being installed using the legacy
'setup.py install' method because it does not have a
'pyproject.toml' and the wheel package is not installed.Common Causes
- Project uses
setup.pywithsetup()call but nopyproject.toml pyproject.tomlexists but lacks[build-system]table- Using
python setup.py sdist bdist_wheelinstead ofpython -m build - Old project templates not updated for modern packaging
Step-by-Step Fix
- 1.Create minimal pyproject.toml:
- 2.```toml
- 3.[build-system]
- 4.requires = ["setuptools>=68.0", "wheel"]
- 5.build-backend = "setuptools.build_meta"
[project] name = "my-package" version = "1.0.0" description = "A useful Python package" readme = "README.md" requires-python = ">=3.10" license = {text = "MIT"} authors = [ {name = "Your Name", email = "you@example.com"}, ] dependencies = [ "requests>=2.28.0", "click>=8.0", ]
[project.optional-dependencies] dev = ["pytest>=7.0", "black>=23.0"]
[project.scripts] my-cli = "my_package.cli:main" ```
- 1.Migrate setup() arguments to pyproject.toml:
- 2.```python
- 3.# OLD: setup.py
- 4.from setuptools import setup, find_packages
setup( name="my-package", version="1.0.0", packages=find_packages(exclude=["tests"]), install_requires=["requests>=2.28.0", "click>=8.0"], python_requires=">=3.10", entry_points={ "console_scripts": ["my-cli=my_package.cli:main"], }, )
# NEW: Remove setup.py entirely or keep minimal: # setup.py (only if you need legacy compatibility) from setuptools import setup setup() # Reads from pyproject.toml ```
- 1.Migrate package data and include/exclude rules:
- 2.```toml
- 3.[tool.setuptools.packages.find]
- 4.where = ["src"]
- 5.exclude = ["tests*"]
[tool.setuptools.package-data] my_package = ["data/*.json", "templates/*.html"]
[tool.setuptools] include-package-data = true ```
- 1.Build using modern tools:
- 2.```bash
- 3.# Install build tool
- 4.pip install build
# Build wheel and source distribution python -m build
# Verify no deprecation warnings pip install --no-cache-dir dist/my_package-1.0.0-py3-none-any.whl ```
- 1.Migrate entry points and scripts:
- 2.```toml
- 3.[project.scripts]
- 4.my-cli = "my_package.cli:main"
[project.gui-scripts] my-gui = "my_package.gui:main"
[project.entry-points."myplugin.hooks"] hook_a = "my_package.plugins:hook_a" ```
Prevention
- Use
pip checkto verify packaging works without warnings - Adopt
hatchorpdmas modern build backends - Run
twine check dist/*before publishing - Use
check-manifestto verify all files are included - Set up CI to catch deprecation warnings early:
- ```bash
- python -W error::DeprecationWarning -m build
`