Skip to main content

Semantic versioning made easy for Python

Project description

🐊 Semmy

Semantic versioning made easy for Python.

Features

With semmy you can...

  • Parse semantic version domain objects from valid strings
  • Check if two versions are equal
  • Check if version is greater (newer) or lesser (older) than other version
  • Check if version is a pre-release
  • Bump (pre-)major, (pre-)minor, and (pre-)patch versions

Prerequisites

  • Python >=3.8 or later

Install

poetry add semmy

Alternatively, for older projects.

pip install semmy
pip freeze > requirements.txt

Usage

Below are the most common use cases. Please, check the unit tests for complete examples.

Importing

>>> from semmy import Semver

Initializing a raw object

Plain objects are easy to initialize given three semantic version components.

>>> Semver(1, 2, 3)
Version (1.2.3)

Keyword arguments are supported, too.

>>> Semver(major=1, minor=2, patch=3)
Version (1.2.3)

Versions may contain pre-release tag and build number.

>>> Semver(1, 0, 0, pre_release="rc-1")
Version (1.0.0-rc-1)

>>> Semver(1, 0, 0, build="6c231887917e472da7f299c934b20f29")
Version (1.0.0+6c231887917e472da7f299c934b20f29)

Initializing from string

You can pass a string and have it transformed to a valid object.

>>> Semver.from_string("1.0.0")
Version (1.0.0)

Exporting as tuple

Versions can be exported as integer tuples.

>>> Semver(1, 2, 3).as_tuple()
(1, 2, 3)

Validating input

I recommend using Semver.from_string() whenever possible as it includes a strict input validation.

For invalid inputs, instance of SemverException is raised, which should be caught.

>>> from semmy import Semver, SemverException
>>> try:
...     Semver.from_string("not-a-version")
... except SemverException as e:
...     print(e)
...
Version string not-a-version is not a valid semantic version

Comparing versions

Two versions are ordered by comparing their major, minor, and patch numbers respectively.

>>> Semver.from_string("1.2.3") == Semver(1, 2, 3)
True

>>> Semver.from_string("1.1.0") > Semver(1, 0, 0)
True

>>> Semver.from_string("0.9.0") < Semver(0, 9, 1)
True

You may also want to sort a list of versions where Python's tuple ordering is helpful.

>>> versions: list[Semver] = [
...     Semver(1, 2, 3),
...     Semver(2, 0, 0),
...     Semver(0, 1, 0),
... ]
>>>
>>> sorted(versions, key=lambda v: v.as_tuple(), reverse=True)
[Version (2.0.0), Version (1.2.3), Version (0.1.0)]

Bumping versions

Typically, you want to bump major version for breaking changes, minor version for new features, and patch version for new fixes. These are supported.

>>> Semver(0, 1, 0).bump_major()
Version (1.0.0)

>>> Semver(1, 0, 0).bump_minor()
Version (1.1.0)

>>> Semver(1, 1, 0).bump_patch()
Version (1.1.1)

Contributing

See here for instructions.

Release Setup

This project uses automated releases with Release Please and GitHub Actions.

Required GitHub Repository Secrets

Before the release workflow can function properly, you need to configure the following secrets in your GitHub repository:

PYPI_API_TOKEN

Purpose: Authenticate with PyPI for publishing packages

Setup Instructions:

  1. Go to PyPI Account Settings
  2. Navigate to the "API tokens" section
  3. Click "Add API token"
  4. Set the token name (e.g., "semmy-github-actions")
  5. Set the scope to "Entire account" or specific to the "semmy" project
  6. Copy the generated token (it starts with pypi-)
  7. Add it to your GitHub repository secrets as PYPI_API_TOKEN

Alternative: PyPI Trusted Publishing (Recommended)

Instead of using an API token, you can set up trusted publishing which is more secure:

  1. Go to your project on PyPI: https://pypi.org/manage/project/semmy/
  2. Navigate to "Publishing" → "Add a new pending publisher"
  3. Fill in the details:
    • Owner: nikoheikkila (your GitHub username)
    • Repository name: semmy
    • Workflow name: release.yml
    • Environment name: Leave empty (unless you use environments)
  4. Save the publisher

If you use trusted publishing, you can remove the UV_PUBLISH_TOKEN environment variable from the workflow.

How the Release Process Works

1. Release Please Phase

When you push commits to the main branch:

  1. Release Please analyzes conventional commit messages since the last release
  2. If release-worthy changes are found, it creates/updates a "Release PR"
  3. The Release PR contains:
    • Updated version in pyproject.toml
    • Updated CHANGELOG.md
    • Any other version-related files

2. Release Creation Phase

When you merge the Release PR:

  1. Release Please creates a GitHub Release and Git tag
  2. The workflow triggers the Publish job
  3. The publish job:
    • Runs tests to ensure quality
    • Builds the package with uv build
    • Publishes to PyPI with uv publish
    • Creates a workflow summary

Conventional Commit Types

The workflow recognizes these conventional commit types:

Type Description Release Impact Changelog Section
feat New feature Minor version bump ✨ Features
fix Bug fix Patch version bump 🐛 Bug Fixes
perf Performance improvement Patch version bump ⚡ Performance Improvements
revert Revert previous change Patch version bump ⏪ Reverts
docs Documentation changes Patch version bump 📚 Documentation
style Code style changes Patch version bump 🎨 Styles
refactor Code refactoring Patch version bump ♻️ Code Refactoring
test Test changes Patch version bump ✅ Tests
build Build system changes Patch version bump 👷 Build System
ci CI configuration changes Patch version bump 💚 Continuous Integration
chore Maintenance tasks No release (Hidden from changelog)

Breaking Changes

To trigger a major version bump, use:

  • feat!: or fix!: (with exclamation mark)
  • Include BREAKING CHANGE: in the commit message body

Example Commits

# Patch release (1.0.0 → 1.0.1)
git commit -m "fix: resolve null pointer exception in parser"

# Minor release (1.0.0 → 1.1.0) 
git commit -m "feat: add support for YAML configuration files"

# Major release (1.0.0 → 2.0.0)
git commit -m "feat!: remove deprecated API methods"

# Or with body:
git commit -m "feat: new API design

BREAKING CHANGE: The old API methods have been removed."

Manual Release

If you need to create a release manually:

# Create a commit that bumps the version
git commit -m "chore(release): 1.2.3" --allow-empty

# Push to main
git push origin main

Troubleshooting

Release PR not created

  • Ensure your commits follow conventional commit format
  • Check that you have release-worthy commit types (not just chore)
  • Verify the workflow has proper permissions

PyPI publish fails

  • Verify PYPI_API_TOKEN is correctly set
  • Ensure the package name isn't already taken by another user
  • Check that the version doesn't already exist on PyPI

Tests fail during release

  • All tests must pass before publishing
  • Fix the failing tests and push the fix to main
  • The workflow will retry on the next push

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

semmy-2.1.0.tar.gz (43.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

semmy-2.1.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file semmy-2.1.0.tar.gz.

File metadata

  • Download URL: semmy-2.1.0.tar.gz
  • Upload date:
  • Size: 43.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for semmy-2.1.0.tar.gz
Algorithm Hash digest
SHA256 60cb6ba1f08b5c027b32d9933edfc8d5d293072da734434ba6938e422905dabd
MD5 e16842db24fc9a085e7ae99576e11bfb
BLAKE2b-256 ebfdc3342c8f2049a858b5c33622f33ffb1eb6b120e5dcef58a81b9d886b3ed2

See more details on using hashes here.

File details

Details for the file semmy-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: semmy-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for semmy-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f35aa292d358f4c589f60bf19211bdeef04d70ea5c9df1c1c4a3d2b0816e4399
MD5 6b1998c24f1de6082a503cd515456a95
BLAKE2b-256 422b25ca688950fac7dcceaf6526e8f9d5e1f63ccc342a7966b68378f1ae5418

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page