Codeskill

Learn to code, step by step

Packaging and publishing mindset

Packaging and publishing with a professional mindset. The intermediate tutorials showed you how to structure a module and pin dependencies. Here we look at what it takes to share code – on PyPI, inside a company, or as a reusable library in several of your own projects.

Library, application, or both

A library exposes functions and classes other code imports. An application runs as a service or CLI. Mixing the two in one package without thinking about it leads to awkward installs and surprise imports at startup. Decide early which way the code is meant to be consumed.

Modern layout with pyproject.toml

pyproject.toml is the single config file build tools read. Keep version, dependencies, and entry points in one place.

# pyproject.toml (structure shown as comments in a code block)
# [project]
# name = "codeskill-utils"
# version = "0.1.0"
# description = "Small helpers for Codeskill examples"
# readme = "README.md"
# requires-python = ">=3.10"
# dependencies = ["httpx>=0.27"]
#
# [project.optional-dependencies]
# dev = ["pytest>=8.0", "ruff>=0.4"]
#
# [project.scripts]
# cs-report = "codeskill_utils.cli:main"
#
# [build-system]
# requires = ["hatchling"]
# build-backend = "hatchling.build"

The src/ layout keeps import tests honest – you install the package to use it, rather than accidentally importing from the repo root.

codeskill_utils/
├── pyproject.toml
├── README.md
├── src/codeskill_utils/
│   ├── __init__.py
│   └── slugify.py
└── tests/
    └── test_slugify.py

Versioning and changelogs

Semantic versioning is a useful convention: bump the patch for fixes, minor for backwards-compatible features, major for breaking changes. A short CHANGELOG or GitHub release notes save future-you from archaeology. Even internal packages deserve a version string – “just use main” breaks the day someone needs to reproduce a build from six months ago.

Building and publishing to PyPI

Install build tooling in your virtual environment, build artefacts, upload with Twine. Use TestPyPI first unless you enjoy emailing strangers to yank a typo release.

# Terminal commands (run from project root):
# pip install build twine
# python -m build
# twine upload --repository testpypi dist/*
# twine upload dist/*   # real PyPI when ready

Store API tokens in environment variables or your CI secret store. Never commit credentials to the repo. Enable two-factor auth on your PyPI account – bot uploads are a real nuisance.

Private indexes and git installs

Companies often run a private package index or install directly from Git tags:

# requirements snippet examples:
# codeskill-utils==0.3.1
# codeskill-utils @ git+https://github.com/you/codeskill-utils@v0.3.1

Pin versions in applications. Libraries declare compatible ranges. That split is easy to forget and painful when you forget it.

Quality gates before you publish

  • README with install line and one working example
  • Tests that run in CI
  • License file if the code is public
  • requires-python set honestly
  • No secrets, no giant accidental data files in the sdist

Publishing is reversible in theory and annoying in practice. Treat the first public release as a contract – names, import paths, and behaviour people will depend on.

PreviousPerformance profiling generators