{"id":247,"library":"setuptools","title":"Setuptools","description":"Setuptools is Python's original and most established build backend for packaging, distributing, and installing Python packages, with full support for C/C++ extension modules, entry points, and PEP 517/660 editable installs. Current version is 82.0.1 (released Feb 2026). The project ships frequently — multiple major versions per month — and has a history of disruptive but well-warned breaking changes. Requires Python >=3.9 as of v75.4.0.","status":"active","version":"82.0.1","language":"python","source_language":"en","source_url":"https://github.com/pypa/setuptools","tags":["packaging","build-backend","distribution","pep517","pep660","c-extensions","pypa"],"install":[{"cmd":"pip install setuptools","lang":"bash","label":"Install latest"},{"cmd":"pip install \"setuptools>=61.0\"","lang":"bash","label":"Install with pyproject.toml support (minimum recommended)"}],"dependencies":[{"reason":"Recommended frontend for invoking setuptools as a build backend (python -m build); not required at runtime","package":"build","optional":true},{"reason":"Historically listed in build-system.requires but no longer needed — setuptools vendors what it needs","package":"wheel","optional":true},{"reason":"Drop-in replacement for the removed pkg_resources API on older Pythons (<3.10)","package":"importlib-metadata","optional":true}],"imports":[{"note":"Used inside setup.py for legacy configuration; pyproject.toml is now preferred over a standalone setup.py","symbol":"setup","correct":"from setuptools import setup"},{"note":"Discovers packages automatically; use find_namespace_packages() for PEP 420 namespace packages","symbol":"find_packages","correct":"from setuptools import find_packages"},{"note":"Use instead of find_packages() when working with PEP 420 implicit namespace packages","symbol":"find_namespace_packages","correct":"from setuptools import find_namespace_packages"},{"note":"distutils was removed from the stdlib in Python 3.12; always import Extension from setuptools","wrong":"from distutils.core import Extension","symbol":"Extension","correct":"from setuptools import Extension"},{"note":"pkg_resources was fully removed in setuptools 81.0.0 (Feb 2026); use importlib.metadata instead","wrong":"import pkg_resources; pkg_resources.get_distribution('pkg').version","symbol":"version (runtime metadata)","correct":"from importlib.metadata import version"},{"note":"pkg_resources removed in setuptools 81; importlib.metadata is the stdlib replacement","wrong":"import pkg_resources; pkg_resources.iter_entry_points('my.group')","symbol":"entry_points (runtime)","correct":"from importlib.metadata import entry_points; eps = entry_points(group='my.group')"},{"note":"Always declare this in pyproject.toml; pip assumes it as default only as a fallback for legacy projects","symbol":"build_meta (build backend)","correct":"build-backend = \"setuptools.build_meta\"  # in pyproject.toml [build-system]"}],"quickstart":{"code":"# pyproject.toml (place in your project root — no setup.py needed)\n# [build-system]\n# requires = [\"setuptools>=61\"]\n# build-backend = \"setuptools.build_meta\"\n#\n# [project]\n# name = \"mypackage\"\n# version = \"0.1.0\"\n# description = \"My package\"\n# requires-python = \">=3.9\"\n# license = \"MIT\"            # PEP 639 SPDX string (setuptools >= 77)\n# dependencies = [\"requests>=2.25\"]\n#\n# [project.scripts]\n# my-cli = \"mypackage.cli:main\"\n\n# --- Programmatic use (setup.py, still valid as config file) ---\nfrom setuptools import setup, find_packages\n\nsetup(\n    name=\"mypackage\",\n    version=\"0.1.0\",\n    packages=find_packages(where=\"src\"),\n    package_dir={\"\": \"src\"},\n    python_requires=\">=3.9\",\n    install_requires=[\"requests>=2.25\"],\n)\n\n# --- Runtime metadata (replaces pkg_resources) ---\nfrom importlib.metadata import version, entry_points\n\npkg_version = version(\"mypackage\")\neps = entry_points(group=\"console_scripts\")\n","lang":"python","description":"Minimal modern pyproject.toml-based package layout and programmatic setup.py usage. Run 'python -m build' from the project root to produce sdist + wheel in dist/."},"warnings":[{"fix":"Replace all pkg_resources usage with importlib.metadata (version, entry_points, etc.) and importlib.resources. For transitive dependencies you cannot control, pin 'setuptools<81' as a temporary workaround.","message":"pkg_resources was fully removed in setuptools 81.0.0 (released Feb 8 2026). Any code or dependency doing 'import pkg_resources' will raise ModuleNotFoundError on setuptools >= 81.","severity":"breaking","affected_versions":">=81.0.0"},{"fix":"Replace all hyphenated keys in setup.cfg with their underscore equivalents (e.g. 'description_file', 'long_description'). The v78.0.1 reversal was itself reverted; the enforcement stands in current releases.","message":"setup.cfg keys using hyphens (e.g. 'description-file', 'long-description') raise InvalidConfigError in setuptools >= 78. This was a deprecation since 2021 that became an error in v78.","severity":"breaking","affected_versions":">=78.0.0"},{"fix":"Use a plain SPDX expression string: 'license = \"MIT\"' in pyproject.toml [project]. If you still need to support Python 3.8 builds (max setuptools 75.3.x), keep the table form and suppress the warning temporarily.","message":"project.license as a TOML table (e.g. license = {text = 'MIT'}) is deprecated as of setuptools 77 in favour of a plain SPDX string (license = 'MIT'). The table form will eventually be rejected.","severity":"breaking","affected_versions":">=77.0.0"},{"fix":"Use 'pip install .' for installation, 'pip install -e .' for editable installs, 'python -m build' for building distributions, and a dedicated test runner (pytest) instead of 'setup.py test'.","message":"Running 'python setup.py install', 'python setup.py develop', 'python setup.py test', and other direct setup.py CLI invocations are deprecated and being removed incrementally. 'setup.py develop' now defers to pip internally.","severity":"deprecated","affected_versions":">=58.3.0"},{"fix":"If you must build on Python 3.8, pin 'setuptools<75.4' or use the 75.3.x maintenance branch. Otherwise upgrade to Python >=3.9.","message":"Python 3.8 support was dropped in setuptools 75.4.0. The last version supporting Python 3.8 is 75.3.x (actively maintained as a security-only branch).","severity":"breaking","affected_versions":">=75.4.0"},{"fix":"Use only 'requires = [\"setuptools\"]' in [build-system]. The build frontend (pip, build) handles wheel generation separately.","message":"Do NOT add 'wheel' to build-system.requires in pyproject.toml. This was historically recommended but is now unnecessary and actively discouraged by the official docs.","severity":"gotcha","affected_versions":">=61.0.0"},{"fix":"Pass '--config-settings editable_mode=compat' when running 'pip install -e .' to use a symlink/pth-file approach instead of the import hook.","message":"Static analysis tools (mypy, pyright, pylint) may not work correctly when setuptools uses an import-hook-based editable install (the default). This is a known limitation of the compat editable mode.","severity":"gotcha","affected_versions":">=64.0.0"}],"env_vars":null,"last_verified":"2026-05-12T12:19:18.761Z","next_check":"2026-06-25T00:00:00.000Z","problems":[{"fix":"Install the appropriate build tools for your operating system (e.g., `sudo apt-get install build-essential` on Debian/Ubuntu, `xcode-select --install` on macOS, Visual C++ build tools on Windows).","cause":"Setuptools requires a C/C++ compiler to build native extensions for some Python packages, which is missing from the system's PATH.","error":"error: command 'gcc' failed: No such file or directory"},{"fix":"Upgrade Python to version 3.9 or newer, or switch to a Python environment (e.g., virtualenv) that uses Python 3.9 or newer.","cause":"The version of setuptools being installed or used requires Python 3.9 or newer, but the current Python environment is older than 3.9.","error":"ERROR: Package 'setuptools' requires a different Python: 3.8.10 not in '>=3.9'"},{"fix":"Modify `install_requires` in `setup.cfg` (or `setup.py`) to be a list of strings (e.g., `install_requires = python_package_name >= X.Y.Z`) or a multi-line string format.","cause":"The `install_requires` field in `setup.cfg` or `setup.py` is incorrectly formatted, typically specified as a Python set instead of a list of strings or a multi-line string.","error":"error: The 'install_requires' parameter must be a string or list of strings (got set) in setup.cfg"},{"fix":"Update the `setup.py` script to import `setup` from `setuptools` (e.g., `from setuptools import setup`) and replace direct `distutils` imports with their `setuptools.distutils` equivalents.","cause":"The `distutils` package was removed from the Python standard library in Python 3.12+, causing older `setup.py` scripts or packages that directly import from it to fail.","error":"ModuleNotFoundError: No module named 'distutils.cmd'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.81,"mem_mb":15.7,"disk_size":"18.7M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.81,"mem_mb":15.7,"disk_size":"18.7M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":15.7,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.55,"mem_mb":15.7,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.02,"mem_mb":17.2,"disk_size":"20.9M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.03,"mem_mb":17.2,"disk_size":"20.9M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.8,"mem_mb":17.2,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.8,"mem_mb":17.2,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":17,"disk_size":"20.4M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.48,"mem_mb":17,"disk_size":"20.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":17,"disk_size":"21M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":17,"disk_size":"21M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":17.4,"disk_size":"20.0M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":17.4,"disk_size":"20.0M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":17.4,"disk_size":"20M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":17.4,"disk_size":"20M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.83,"mem_mb":15.3,"disk_size":"18.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.85,"mem_mb":15.3,"disk_size":"18.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.66,"mem_mb":15.4,"disk_size":"19M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.69,"mem_mb":15.4,"disk_size":"19M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}