ADR-008: Packaging and Distribution¶
Status¶
Accepted Date: 2026-02-14
Context¶
cosalette is a reusable Python framework consumed by 8+ independent IoT-to-MQTT bridge projects, each in its own repository. The framework needs a packaging and distribution strategy that supports clean dependency management across multiple repos, works in CI/CD pipelines (GitHub Actions) and Docker builds, and follows modern Python packaging standards.
The project is open source (MIT license). The author wants to learn the PyPI publication workflow and is willing to maintain the package, though the primary audience is personal projects.
Decision¶
Use PyPI publication with the package name cosalette, hatchling as the build
backend, setuptools-scm for version management, src layout, and a py.typed
marker (PEP 561) for type stub support, because this is the cleanest, most standard
distribution mechanism for Python packages.
Package structure¶
cosalette/
├── pyproject.toml
├── src/
│ └── cosalette/
│ ├── __init__.py
│ ├── py.typed # PEP 561 marker
│ ├── _version.py # Generated by setuptools-scm
│ └── ...
Build configuration¶
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/cosalette"]
[tool.setuptools_scm]
version_scheme = "guess-next-dev"
write_to = "src/cosalette/_version.py"
fallback_version = "0.0.0"
Versioning strategy¶
- cosalette uses independent semver versioning
- Consumer projects pin with compatible ranges:
cosalette>=0.5,<1.0 - Deprecation cycles can be short (one minor version) since all consumers are maintained by the same author
Multi-repo layout¶
github.com/ff-fab/
├── cosalette/ # Framework repository
├── velux2mqtt/ # Depends on cosalette
├── gas2mqtt/ # Depends on cosalette
├── wiz2mqtt/ # Depends on cosalette
└── ... # 5 more project repos
Decision Drivers¶
pip install cosalettemust work everywhere (CI, Docker, devcontainers)- Proper version resolution (pip/uv can resolve conflicts)
- Independent semver for framework and projects
- PEP 561 type stub support for type-checker compatibility
- Modern Python packaging standards (PEP 517/518/621)
- Professional practice and learning opportunity for PyPI publishing
Considered Options¶
Option 1: Poetry¶
Use Poetry for project management and build backend.
- Advantages: All-in-one tool (dependency management + build + publish). Lock file for reproducible installs. Large community.
- Disadvantages: Poetry's custom dependency resolver can conflict with pip/uv.
Non-standard lock file format. The project already uses hatchling — switching adds
no value. Poetry's
pyproject.tomlextensions are not PEP 621 compliant.
Option 2: Flit¶
Use Flit for simple, minimal packaging.
- Advantages: Extremely simple for pure-Python packages. Minimal configuration.
- Disadvantages: Does not support dynamic version management (setuptools-scm). Limited build customisation. Less flexibility for future needs (C extensions, data files).
Option 3: setuptools (legacy)¶
Use traditional setuptools with setup.py or setup.cfg.
- Advantages: Most widely used build backend. Maximum compatibility.
- Disadvantages:
setup.pyis legacy;setup.cfgis being superseded bypyproject.toml. Verbose configuration compared to hatchling. Does not support PEP 621 natively in older versions.
Option 4: hatchling with PyPI publication (chosen)¶
Use hatchling as the PEP 517 build backend with PyPI as the distribution channel.
- Advantages: Modern PEP 517/518/621 compliant. Clean
pyproject.tomlconfiguration. Works with setuptools-scm for git-tag-based versioning.pip install cosaletteworks everywhere without git access. Hashes and integrity checks. Professional practice even for personal projects. - Disadvantages: Requires PyPI account setup and release automation. Public package on PyPI (acceptable for open source project).
Decision Matrix¶
| Criterion | Poetry | Flit | setuptools (Legacy) | hatchling + PyPI |
|---|---|---|---|---|
| PEP compliance | 3 | 4 | 3 | 5 |
| Version management | 4 | 2 | 3 | 5 |
| Install simplicity | 4 | 5 | 3 | 5 |
| Build flexibility | 3 | 2 | 5 | 4 |
| Community adoption | 5 | 3 | 4 | 4 |
Scale: 1 (poor) to 5 (excellent)
Consequences¶
Positive¶
pip install cosaletteworks in any environment — CI, Docker, devcontainers, bare metal- Version resolution by pip/uv handles dependency conflicts automatically
py.typedmarker enables type-checking consumers to verify against cosalette's type annotations- setuptools-scm eliminates manual version management — git tags drive version numbers
- src layout prevents accidental imports of the development source
Negative¶
- PyPI publication requires release automation (GitHub Actions workflow) and account management
- The package is public on PyPI — though this is acceptable for an open-source project
- setuptools-scm requires git tags to be managed carefully — missing tags produce dev versions
2026-02-14