Python
Setup.py
Programming
Software Development
Coding Tutorial

What is setup.py?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

setup.py is the traditional build script for Python packages. It uses the setuptools library to define package metadata (name, version, author), dependencies, entry points, and installation instructions. When you run pip install . or python setup.py install, this file tells the build system how to package and install your project.

Basic setup.py

python
1from setuptools import setup, find_packages
2
3setup(
4    name='my-package',
5    version='1.0.0',
6    author='Alice',
7    author_email='[email protected]',
8    description='A short description of the package',
9    long_description=open('README.md').read(),
10    long_description_content_type='text/markdown',
11    url='https://github.com/alice/my-package',
12    packages=find_packages(),
13    python_requires='>=3.8',
14    install_requires=[
15        'requests>=2.25.0',
16        'click>=8.0',
17    ],
18)

Key Fields

FieldPurposeExample
namePackage name on PyPI'my-package'
versionSemantic version'1.2.3'
packagesPython packages to includefind_packages()
install_requiresRuntime dependencies['requests>=2.25']
entry_pointsCLI commands{'console_scripts': [...]}
python_requiresMinimum Python version'>=3.8'
classifiersPyPI metadata tags['License :: OSI Approved :: MIT License']

Common Commands

bash
1# Install the package in development mode (editable)
2pip install -e .
3
4# Install the package
5pip install .
6
7# Build a distribution
8python setup.py sdist bdist_wheel
9
10# Upload to PyPI
11twine upload dist/*
12
13# Legacy commands (still work but pip is preferred)
14python setup.py install
15python setup.py develop

Entry Points (CLI Commands)

Define command-line tools that get installed with your package:

python
1setup(
2    name='my-cli',
3    # ...
4    entry_points={
5        'console_scripts': [
6            'my-command=my_package.cli:main',
7        ],
8    },
9)

After installation, my-command is available in the terminal and calls main() from my_package/cli.py.

Extra Dependencies

Define optional dependency groups:

python
1setup(
2    name='my-package',
3    install_requires=['requests'],
4    extras_require={
5        'dev': ['pytest', 'flake8', 'black'],
6        'docs': ['sphinx', 'sphinx-rtd-theme'],
7        'gpu': ['tensorflow-gpu'],
8    },
9)
bash
pip install .[dev]       # install with dev dependencies
pip install .[dev,docs]  # install with multiple extras

Package Data and Non-Python Files

Include data files like templates, configs, or static assets:

python
1setup(
2    name='my-package',
3    packages=find_packages(),
4    package_data={
5        'my_package': ['templates/*.html', 'data/*.json'],
6    },
7    include_package_data=True,
8)

Modern Alternative: pyproject.toml

setup.py is being replaced by pyproject.toml (PEP 621), which uses a declarative format:

toml
1[build-system]
2requires = ["setuptools>=68.0", "wheel"]
3build-backend = "setuptools.backends._legacy:_Backend"
4
5[project]
6name = "my-package"
7version = "1.0.0"
8description = "A short description"
9requires-python = ">=3.8"
10dependencies = [
11    "requests>=2.25.0",
12    "click>=8.0",
13]
14
15[project.scripts]
16my-command = "my_package.cli:main"
17
18[project.optional-dependencies]
19dev = ["pytest", "flake8"]

pyproject.toml is preferred for new projects because:

  • It is declarative (no executable code)
  • It supports multiple build backends (setuptools, flit, poetry, hatch)
  • It consolidates tool configuration ([tool.pytest], [tool.black], etc.)

setup.py vs setup.cfg vs pyproject.toml

Featuresetup.pysetup.cfgpyproject.toml
FormatPython scriptINI-styleTOML
Dynamic logicYesLimitedNo
Build backendssetuptools onlysetuptools onlyAny
Recommended for new projectsNoNoYes
PyPI uploadYesYesYes

Common Pitfalls

  • Missing MANIFEST.in: When building source distributions (sdist), non-Python files are excluded unless listed in MANIFEST.in or specified via package_data.
  • Version sync: Keeping the version in setup.py in sync with __version__ in your package is error-prone. Use setuptools-scm or single-source the version from your package.
  • find_packages scope: find_packages() includes all Python packages it finds, including test directories. Use find_packages(exclude=['tests', 'tests.*']) to exclude them.
  • install_requires vs requirements.txt: install_requires in setup.py lists abstract dependencies (what your package needs). requirements.txt lists pinned versions (what to install in a specific environment). They serve different purposes.
  • Executable setup.py: Because setup.py is executable Python, it can contain arbitrary code that runs during installation. This is a security concern — prefer declarative pyproject.toml for new projects.

Summary

  • setup.py is the traditional Python package build script using setuptools
  • It defines package metadata, dependencies, entry points, and installation behavior
  • Use pip install -e . for development installation (editable mode)
  • For new projects, prefer pyproject.toml (PEP 621) as the declarative alternative
  • Use find_packages() to automatically discover packages, excluding tests

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.