What is setup.py?

Learn what is setup.py? with practical examples, diagrams, and best practices. Covers python, pypi, setup.py development techniques with visual explanations.

Understanding setup.py: The Heart of Python Package Distribution

Hero image for What is setup.py?

Explore setup.py, its role in Python packaging, how it defines metadata, dependencies, and entry points for your projects, and its evolution in the Python ecosystem.

In the world of Python, sharing your code with others or deploying it to production environments often involves packaging. At the core of traditional Python packaging lies setup.py, a script that serves as the build script for your project. It's the primary way to define how your Python package is built, distributed, and installed. While newer tools and standards like pyproject.toml are gaining prominence, understanding setup.py remains crucial for working with many existing Python projects and grasping the fundamentals of Python packaging.

What is setup.py?

setup.py is a Python script that lives in the root directory of your project. It uses the setuptools library (which extends the older distutils) to describe your project's metadata and how it should be packaged. When you run commands like python setup.py install or python setup.py sdist, this script is executed to perform the packaging operations.

flowchart TD
    A[Developer's Project] --> B{setup.py}
    B --> C[Metadata (Name, Version, Author)]
    B --> D[Dependencies (install_requires)]
    B --> E[Package Data (include_package_data)]
    B --> F[Entry Points (console_scripts)]
    B --> G[Build Commands (sdist, bdist_wheel)]
    G --> H[Distributable Package (e.g., .whl, .tar.gz)]
    H --> I[PyPI / Local Installation]

The role of setup.py in the Python packaging workflow.

The main function within setup.py is setup(), which takes various keyword arguments to define the package's characteristics. These arguments include essential information like the package name, version, author, description, and most importantly, its dependencies and the files it contains.

from setuptools import setup, find_packages

setup(
    name='my_awesome_package',
    version='0.1.0',
    author='Your Name',
    author_email='your.email@example.com',
    description='A short description of my awesome package.',
    long_description=open('README.md').read(),
    long_description_content_type='text/markdown',
    url='https://github.com/yourusername/my_awesome_package',
    packages=find_packages(),
    install_requires=[
        'requests>=2.25.1',
        'beautifulsoup4>=4.9.3',
    ],
    classifiers=[
        'Programming Language :: Python :: 3',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
    ],
    python_requires='>=3.7',
    entry_points={
        'console_scripts': [
            'my-cli-tool=my_awesome_package.cli:main',
        ],
    },
    include_package_data=True,
)

A typical setup.py file demonstrating common arguments.

Key Arguments and Their Purpose

The setup() function accepts numerous arguments, each serving a specific purpose in defining your package. Understanding these is key to creating a well-formed and easily distributable Python project.

  • name: The name of your package. This is how users will refer to it (e.g., pip install my_awesome_package).
  • version: The current version of your package (e.g., 0.1.0). Following semantic versioning is a good practice.
  • author, author_email: Contact information for the package author.
  • description, long_description, long_description_content_type: Short and long descriptions of your package, often read from README.md.
  • url: The project's homepage or repository URL.
  • packages: A list of Python packages (directories containing __init__.py files) to include. find_packages() is a convenient helper function from setuptools.
  • install_requires: A list of strings specifying the project's runtime dependencies. setuptools will ensure these are installed when your package is installed.
  • classifiers: A list of strings that categorize your project for PyPI, helping users find it.
  • python_requires: Specifies the Python versions your package is compatible with.
  • entry_points: Defines console scripts or GUI entry points, allowing users to run commands directly from your installed package.
  • include_package_data: If True, setuptools will look for a MANIFEST.in file to include non-Python files (like data files, templates, etc.) in your distribution.

Evolution and Alternatives: pyproject.toml

While setup.py has been the standard for a long time, the Python packaging landscape is evolving. The introduction of pyproject.toml (defined by PEP 518 and PEP 621) aims to centralize build system configuration and package metadata in a single, static file. Tools like Poetry and Flit leverage pyproject.toml extensively, and setuptools itself now supports defining metadata directly within pyproject.toml.

For new projects, especially those not requiring complex build logic, using pyproject.toml for metadata and relying on build backends like setuptools or hatch is often recommended. However, setup.py still offers flexibility for more intricate build processes, custom commands, or when dealing with older projects.

graph TD
    A[Project Configuration] --> B{Traditional setup.py}
    A --> C{Modern pyproject.toml}
    B --> D[Dynamic Metadata]
    B --> E[Custom Build Logic]
    C --> F[Static Metadata]
    C --> G[Build System Backend (e.g., setuptools, poetry)]
    D --> H[Flexibility]
    E --> H
    F --> I[Simplicity]
    G --> I

Comparison of setup.py and pyproject.toml approaches.

Common setup.py Commands

Here are some frequently used commands executed with setup.py:

1. Install in editable mode

This command installs your package in 'editable' or 'development' mode. Changes to your source code are immediately reflected without re-installation.

pip install -e .

2. Create a source distribution

This command creates a source distribution (sdist), typically a .tar.gz file, containing your source code and any data files specified in MANIFEST.in.

python setup.py sdist

3. Create a wheel distribution

This command creates a wheel distribution (.whl file), which is a pre-built distribution format that can be installed without needing to run setup.py during installation, making it faster and more reliable.

python setup.py bdist_wheel

4. Upload to PyPI

After creating distributions, you can upload them to PyPI (the Python Package Index) using twine.

twine upload dist/*