Neural Architecture Hub
Python Project Setup

Packaging for Distribution

Learn how to turn your Python project into a distributable package using pyproject.toml and modern build backends.

Packaging for Distribution

Once your code is organized and tested, the next step is packaging it so others can install it via pip. In 2026, we have moved away from legacy files like setup.py and setup.cfg in favor of the standardized pyproject.toml.

1. The Anatomy of pyproject.toml

The pyproject.toml file contains everything a build tool needs to know about your project. It is divided into sections (tables).

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my_project"
version = "0.1.0"
description = "A short description of my project"
readme = "README.md"
requires-python = ">=3.9"
license = {text = "MIT"}
authors = [
    {name = "Ravi", email = "ravi@example.com"},
]
dependencies = [
    "requests>=2.31.0",
    "pydantic>=2.0.0",
]

[project.urls]
Homepage = "[https://github.com/user/my_project](https://github.com/user/my_project)"
Documentation = "[https://user.github.io/my_project](https://user.github.io/my_project)"

[project.scripts]
my-cli = "my_project.main:app"

2. Choosing a Build Backend

The [build-system] section tells the installer which tool to use to package your code.

BackendBest For
HatchlingHigh-performance, feature-rich, and works great with the src layout.
FlitMinimalist; best for simple libraries that don't need complex build steps.
SetuptoolsThe legacy standard; use only if you have custom C extensions or complex requirements.
PDM/PoetryAll-in-one dependency managers that have their own backends.

3. Building the Distribution

To package your repo, you need to generate two files:

  1. Source Distribution (sdist): A .tar.gz archive containing your source code.
  2. Built Distribution (wheel): A .whl file that is pre-compiled and faster to install.

Using the build tool

The standard, backend-agnostic way to build is using the build package:

# Install the builder
python -m pip install build

# Run the build
python -m build

This will create a dist/ directory in your root:

dist/
├── my_project-0.1.0-py3-none-any.whl
└── my_project-0.1.0.tar.gz

4. Publishing to PyPI

To make your package available via pip install my_project, you must upload these artifacts to the Python Package Index (PyPI).

Step A: Create an Account

Register at PyPI.org and enable 2FA. Generate an API Token for secure uploads.

Step B: Upload with Twine

twine is the standard tool for securely uploading packages.

python -m pip install twine

# Upload to TestPyPI first (to check for errors)
python -m twine upload --repository testpypi dist/*

# Upload to the real PyPI
python -m twine upload dist/*

5. Automation with CI/CD

You shouldn't have to run these commands manually every time. Most modern projects use GitHub Actions to automate the release process whenever a new tag is pushed.

name: Publish to PyPI
on:
  release:
    types: [published]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
      - name: Install dependencies
        run: pip install build twine
      - name: Build and Publish
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: |
          python -m build
          twine upload dist/*

On this page