Python Semantic Versioning — Core Concepts
What Semantic Versioning Promises
Semantic Versioning (semver) assigns meaning to version numbers in the format MAJOR.MINOR.PATCH:
- MAJOR bumps signal incompatible API changes
- MINOR bumps add functionality in a backward-compatible way
- PATCH bumps fix bugs without changing the API
This is a social contract between library authors and consumers. When authors follow it, consumers can write dependency constraints like >=1.2,<2 with confidence that nothing will break until the next major release.
Python’s Version Scheme: PEP 440
Python does not enforce semver. Instead, PEP 440 defines a flexible version format that supports semver but also allows other schemes:
1.2.3 # standard release
1.2.3a1 # alpha pre-release
1.2.3b2 # beta pre-release
1.2.3rc1 # release candidate
1.2.3.post1 # post-release (metadata fix, no code change)
1.2.3.dev4 # development release
Most Python libraries that follow semver use the MAJOR.MINOR.PATCH subset, plus pre-release tags when needed.
When to Bump What
Patch (1.2.3 → 1.2.4)
- Fixed a bug in existing behavior
- Improved error messages
- Performance improvements with no API change
- Documentation-only changes (some teams skip the bump entirely)
Minor (1.2.3 → 1.3.0)
- Added a new function, class, or parameter
- Deprecated an existing feature (but did not remove it)
- Added a new optional dependency
Major (1.2.3 → 2.0.0)
- Removed a public function or class
- Changed a function signature in a breaking way
- Dropped support for a Python version
- Changed default behavior that existing code relies on
The 0.x Escape Hatch
Versions below 1.0.0 carry an implicit warning: “This API is unstable.” During 0.x development, even minor bumps can contain breaking changes. Many Python libraries (FastAPI was 0.x for years) use this to iterate quickly without semver’s strict promises.
The convention is: graduate to 1.0.0 when your public API is stable enough that breaking it would hurt real users.
Version Constraints in Practice
| Constraint | Meaning | Semver Trust Level |
|---|---|---|
>=1.2,<2 | Any 1.x from 1.2 up | High — trusts minor/patch |
~=1.2 | Same as above (PEP 440) | High |
>=1.2.3,<1.3 | Only 1.2.x patches | Medium — trusts patches only |
==1.2.3 | Exact pin | None — no trust, no flexibility |
For applications, exact pins in lock files provide reproducibility. For libraries, flexible constraints let consumers resolve their full dependency tree without conflicts.
Deprecation as a Bridge
Good semver practice never surprises users. Before removing a feature in a major release:
- Minor release — mark it deprecated with a
DeprecationWarning - Documentation — explain the replacement
- At least one minor cycle — give users time to migrate
- Major release — remove the deprecated code
Python’s warnings module makes this straightforward:
import warnings
def old_function():
warnings.warn("old_function is deprecated, use new_function instead", DeprecationWarning, stacklevel=2)
return new_function()
Common Misconception
“Semver means my code will never break on upgrade.” Semver is a promise, not a guarantee. Bugs in the implementation, undocumented behavior changes, and transitive dependency shifts can still cause breakage. Semver reduces risk; it does not eliminate it. Always run your test suite after upgrading.
Single Source of Truth for Version
Store your version in one place. The modern approach is pyproject.toml:
[project]
name = "my-package"
version = "1.3.0"
If you need runtime access, use importlib.metadata:
from importlib.metadata import version
__version__ = version("my-package")
Avoid duplicating the version string in __init__.py, setup.py, and pyproject.toml — they will inevitably drift.
The one thing to remember: Semver is a communication protocol between authors and users — follow it honestly, and your package becomes one that people trust to upgrade.
See Also
- Python Api Design Principles Design Python functions and classes that feel natural to use — like a well-labeled control panel.
- Python Code Documentation Sphinx Turn Python code comments into a beautiful documentation website automatically.
- Python Docstring Conventions Write helpful notes inside your Python functions so anyone can understand them without reading the code.
- Python Project Layout Conventions Organize Python project files like a tidy toolbox so every teammate finds what they need instantly.
- Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.