What is setup.py and how can it be configured or used for Python package development?
setup.py is a Python script that serves as the standard configuration file for defining package metadata, dependencies, and build instructions in Python package development. It enables developers to specify essential information about their package such as name, version, author details, and requirements, while providing commands for building and distributing packages to PyPI. The file works in conjunction with setuptools to automate the packaging process, making it easier to share and install Python code across different environments.
Contents
- Understanding setup.py
- Basic setup.py Configuration
- Advanced Configuration Options
- Project Structure Requirements
- Modern Alternatives to setup.py
- Building and Distributing Packages
- Best Practices and Migration
Understanding setup.py
setup.py is a fundamental component in Python package development that acts as the central configuration file for defining how a package should be built, what its metadata contains, and how it should be distributed. According to VPK Technologies, setup.py is “the standard way to define metadata about your package and its dependencies.”
The primary purpose of setup.py is to provide setuptools (the Python packaging library) with all the information needed to:
- Discover and package Python modules
- Define package dependencies
- Generate distribution archives
- Handle installation requirements
- Set up entry points for command-line tools
As explained in the Xebia guide, the setup.py file essentially serves as the “control center” for your Python package, orchestrating the entire packaging and distribution process.
Basic setup.py Configuration
A minimal setup.py file follows a standard structure using setuptools. Here’s the basic configuration template:
from setuptools import setup, find_packages
VERSION = '0.0.1'
DESCRIPTION = 'My first Python package'
LONG_DESCRIPTION = 'My first Python package with a slightly longer description'
setup(
name="verysimplemodule",
version=VERSION,
author="Your Name",
author_email="<youremail@email.com>",
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
packages=find_packages(),
install_requires=[]
)
Key Basic Parameters:
name: The package name, which must match the folder nameversion: Package version number (typically following semantic versioning)author: Author’s nameauthor_email: Author’s email addressdescription: Short description of the packagelong_description: Detailed descriptionpackages: Automatically discovers all packages usingfind_packages()install_requires: List of dependencies that need to be installed with the package
As shown in the freeCodeCamp tutorial, this basic configuration is sufficient for most simple Python packages you might build.
Advanced Configuration Options
For more comprehensive package management, setup.py supports numerous additional parameters:
setup(
name="my_package",
version="1.0.0",
author="Your Name",
author_email="email@example.com",
description="A comprehensive Python package",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/username/my_package",
packages=find_packages(),
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
python_requires=">=3.8",
install_requires=[
"requests>=2.25.1",
"numpy>=1.21.0",
"pandas>=1.3.0",
],
extras_require={
"dev": ["pytest>=6.0", "black", "flake8"],
"docs": ["sphinx", "sphinx-rtd-theme"],
},
entry_points={
"console_scripts": [
"my-package=my_package.cli:main",
],
},
include_package_data=True,
zip_safe=False,
)
Key Advanced Parameters:
classifiers: PyPI classifiers that help categorize your packagepython_requires: Minimum Python version requirementextras_require: Optional dependencies for different use casesentry_points: Defines command-line tools and pluginsinclude_package_data: Include non-Python files specified in MANIFEST.inurl: Project homepage or repository URLlong_description_content_type: Format of the long description
Project Structure Requirements
For setup.py to work correctly, your project must follow a specific directory structure. According to GeeksforGeeks, you need to:
- Create a package folder with an
__init__.pyfile inside it - Ensure proper organization of your Python modules
- Follow naming conventions that align with your setup.py configuration
The typical project structure looks like:
my_project/
├── setup.py
├── README.md
├── MANIFEST.in
├── my_package/
│ ├── __init__.py
│ ├── module1.py
│ ├── module2.py
│ └── subpackage/
│ ├── __init__.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ └── test_module1.py
└── docs/
└── source/
├── conf.py
└── index.rst
Key structural requirements:
- Package folder: Must contain
__init__.py(even if empty) - setup.py location: Should be in the project root directory
- README.md: Typically referenced in setup.py for long description
- MANIFEST.in: Specifies additional files to include in the distribution
Important: The
__init__.pyfile is what makes a directory a Python package. It can be empty or contain package initialization code, but it must be present forfind_packages()to discover your modules.
Modern Alternatives to setup.py
While setup.py has been the traditional standard, Python packaging is evolving toward more modern approaches. As noted in the Xebia updated guide, “the recommended way of using Setuptools has shifted in the direction of using the Pyproject.toml in favour of setup.py and setup.cfg.”
pyproject.toml
The modern alternative is pyproject.toml, which serves as “a single source of truth for project metadata” according to PyDevTools.
Here’s a minimal pyproject.toml example:
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mypkg"
description = "really awesome package."
keywords = ["random", "cool"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
]
requires-python = ">=3.7"
dynamic = ["version", "readme"]
[tool.setuptools.dynamic]
readme = {file = ["README.md"], content-type = "text/markdown"}
version = {attr = "mypkg.__version__"}
[project.optional-dependencies]
dev = ["pytest>=6.0", "black", "flake8"]
docs = ["sphinx", "sphinx-rtd-theme"]
Key Benefits of pyproject.toml:
- PEP compliance: Follows modern packaging standards (PEP-517, PEP-518, PEP-621)
- Single configuration: Consolidates metadata that was spread across multiple files
- Better tooling support: Native support in modern Python build tools
- Static analysis: Easier for tools to parse and validate configuration
When to Use setup.py vs pyproject.toml:
Note: According to Ian Hopkinson, as of May 2023, “project settings formerly in setup.cfg can now go in pyproject.toml, as per PEP-621.”
Building and Distributing Packages
Once your setup.py is configured, you can use it to build and distribute your Python package. The process involves several key commands:
Basic Build Commands
-
Build source distribution:
bashpython setup.py sdist
-
Build wheel distribution (recommended):
bashpython setup.py bdist_wheel
-
Build both formats:
bashpython setup.py sdist bdist_wheel
Upload to PyPI
To publish your package to the Python Package Index (PyPI):
python setup.py sdist upload -r pypi
However, the modern approach is to use twine for more secure uploads:
# First build your distributions
python setup.py sdist bdist_wheel
# Then upload with twine
twine upload dist/*
Installation Options
setup.py also enables different installation modes:
-
Standard installation:
bashpip install .
-
Editable installation (development mode):
bashpip install -e .
As mentioned in the Ian Hopkinson guide, editable installation means “changes in the code will be immediately reflected in the functionality of the package.”
-
Installation with extras:
bashpip install .[dev,docs]
Best Practice: Always use virtual environments when working with Python packages to avoid dependency conflicts. As recommended by Xebia, “It is common and recommended practice to use virtual environments for work in Python.”
Best Practices and Migration
When working with setup.py, several best practices should be followed to ensure maintainable and future-proof packaging:
Current Best Practices
- Use version control: Keep your setup.py in version control alongside your package code
- Automate builds: Use CI/CD pipelines to automatically build and test packages
- Document dependencies: Keep requirements.txt for development alongside setup.py
- Test thoroughly: Use tools like tox to test across multiple Python versions
- Follow semantic versioning: Use meaningful version numbers that reflect changes
Migration to Modern Standards
For projects currently using setup.py, consider migrating to pyproject.toml:
- Start simple: Begin with basic pyproject.toml configuration
- Gradual migration: Move configuration piece by piece
- Maintain compatibility: Keep setup.py during transition if needed
- Update tooling: Modernize your build and deployment pipeline
- Test thoroughly: Ensure all functionality works with the new configuration
Future Considerations
As Python packaging continues to evolve, consider these future trends:
- PEP 621: Standard metadata specification for pyproject.toml
- Build backends: Moving beyond setuptools for specialized build needs
- Dependency resolution: Improved dependency management tools
- Security enhancements: Better signing and verification mechanisms
According to PyDevTools, “Setuptools can be configured through pyproject.toml or the legacy setup.py file,” indicating that both approaches will remain supported for the foreseeable future.
Conclusion
setup.py remains a fundamental tool in Python package development, serving as the traditional configuration file that defines package metadata, dependencies, and build instructions. While newer alternatives like pyproject.toml are gaining prominence, understanding setup.py is still essential for working with existing Python packages and maintaining compatibility across different environments.
Key takeaways include:
- setup.py works with setuptools to automate packaging and distribution
- It uses parameters like name, version, author, and dependencies to define package metadata
- Project structure requirements include proper package organization with init.py files
- Modern alternatives like pyproject.toml offer improved configuration management
- Building and distributing packages involves commands like
python setup.py sdistandtwine upload - Virtual environments are recommended for all package development work
As Python packaging continues to evolve, developers should stay informed about new standards and best practices while maintaining the skills to work with both traditional and modern packaging approaches.
Sources
- A Practical Guide To Using Setup.py | Xebia
- How to Build Your Very First Python Package | freeCodeCamp
- What is setup.py in Python? | GeeksforGeeks
- Understanding setup.py, setup.cfg and pyproject.toml in Python | SomeBeans
- How to Create Python Package with setup.py | VPK Technologies
- A Practical Guide To Setuptools And Pyproject.toml | Xebia
- An Updated Guide To Setuptools And Pyproject.toml | Xebia
- setuptools – Python Developer Tooling Handbook
- Why Should I Choose pyproject.toml over requirements.txt? | PyDevTools
- Python minimal package with pyproject.toml | Scientific Computing