DEV Community

Cover image for Python Packaging Best Practices: Build Professional, Reusable Components That Scale
Aarav Joshi
Aarav Joshi

Posted on

Python Packaging Best Practices: Build Professional, Reusable Components That Scale

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

Python Packaging Techniques for Reusable Components

Developing Python packages demands precision and scalability. I've found specific methods crucial for creating robust, shareable tools that stand the test of time. These approaches transform chaotic scripts into professional-grade libraries.

Isolating Code with the src Layout

Separating package code from project files prevents countless headaches. Early in my career, I struggled with accidental imports of test scripts and configuration files. The src structure eliminates this by physically isolating the package:

sound_processor/
├── src/
│   └── sound_processor/
│       ├── __init__.py
│       ├── filters.py
│       └── io.py
├── experiments/  # Local test scripts
├── pyproject.toml
└── requirements-dev.txt
Enter fullscreen mode Exit fullscreen mode

This layout ensures only packaged modules get installed. When users run import sound_processor, they access precisely what you intended—no stray development files. I enforce this in all projects after debugging missing module errors for hours due to path conflicts.

Centralizing Configuration via pyproject.toml

Replacing messy setup.py files with declarative metadata revolutionized my workflow. PEP 621 standardizes package definitions in a single human-readable file:

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

[project]
name = "geo_helpers"
version = "2.3.1"
authors = [{name = "Alex Rivers", email = "alex@geotools.io"}]
dependencies = [
    "shapely>=2.0",
    "geopandas>=0.13"
]
readme = "README.md"
license = {text = "MIT"}

[project.urls]
repository = "https://github.com/alexrivers/geo_helpers"
Enter fullscreen mode Exit fullscreen mode

All critical metadata lives here—dependencies, authorship, licensing. I appreciate how tools like pip and build consume this directly without fragile setup scripts.

Automating Versions with Git Tags

Manual version updates caused embarrassing mismatches in my early releases. setuptools-scm solved this by deriving versions directly from repository tags:

# pyproject.toml
[tool.setuptools_scm]
write_to = "src/geo_helpers/_version.py"
Enter fullscreen mode Exit fullscreen mode

Tagging with git tag v2.3.1 auto-generates a _version.py file. The package always reflects the repository state accurately. I've integrated this with CI pipelines to prevent version drift between code and distributions.

Building CLI Tools from Functions

Turning Python functions into command-line utilities expands a package's utility. I design CLI entry points like this:

# src/data_tools/clean.py
import click

@click.command()
@click.argument("input_file")
def sanitize(input_file):
    """Remove malformed records from CSV files"""
    # Processing logic here

# pyproject.toml
[project.scripts]
clean-csv = "data_tools.clean:sanitize"
Enter fullscreen mode Exit fullscreen mode

After installation, users run clean-csv raw_data.csv directly. I structure complex CLIs with multiple commands using click groups for discoverability.

Testing Across Python Versions

Tox eliminates "works on my machine" syndrome. My standard configuration tests against critical Python versions:

# tox.ini
[tox]
isolated_build = True
envlist = py39,py310,py311

[testenv]
extras = test
commands = pytest --cov=my_package --cov-report=term-missing
deps =
    pytest
    pytest-cov
    coverage
Enter fullscreen mode Exit fullscreen mode

Running tox spins up isolated environments for each interpreter. I combine this with pyenv to manage local interpreter versions. The coverage report highlights untested code paths before release.

Building Platform-Agnostic Wheels

Universal wheels ensure broad compatibility. Modern build tools handle this automatically:

python -m pip install build
python -m build --wheel
# Produces dist/data_tools-0.5.2-py3-none-any.whl
Enter fullscreen mode Exit fullscreen mode

I verify wheel contents with unzip -l dist/*.whl to confirm only intended files are included. Pure Python wheels work anywhere, while binary extensions require environment-specific builds.

Automating Documentation

Static documentation sites build credibility. MkDocs generates sleek sites from Markdown with minimal configuration:

# mkdocs.yml
site_name: Data Tools
nav:
  - "Home": "index.md"
  - "API Reference": "reference.md"
theme: readthedocs
Enter fullscreen mode Exit fullscreen mode

I automate deployment using GitHub Actions:

# .github/workflows/docs.yml
name: Deploy Docs
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install mkdocs-material
      - run: mkdocs gh-deploy --force
Enter fullscreen mode Exit fullscreen mode

Every push updates the public documentation. I include usage examples and troubleshooting guides based on user feedback.

Continuous Integration for Quality Control

CI pipelines catch errors before users do. This configuration runs tests and linters on every commit:

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: ["3.9", "3.10", "3.11"]
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python }}
      - run: pip install tox
      - run: tox -e py
Enter fullscreen mode Exit fullscreen mode

I extend this to enforce coding standards with black and flake8. Failed checks block merging, maintaining code quality across contributions.

These techniques form a cohesive system for professional Python development. The isolation, automation, and standardization they provide have saved me countless hours while increasing user trust in my packages. Start with the src layout and pyproject.toml, then gradually incorporate other elements as your project grows. Consistent application of these practices separates hobby scripts from production-grade Python libraries.

📘 Checkout my latest ebook for free on my channel!

Be sure to like, share, comment, and subscribe to the channel!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | Java Elite Dev | Golang Elite Dev | Python Elite Dev | JS Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)