Contributing Guide
Thanks for your interest in contributing to Apathetic Python Logger — a minimal wrapper for the Python standard library logger.
This guide explains how to set up your environment, run checks, and safely contribute code.
Supported Python Versions
Apathetic Python Logger targets Python 3.10+.
That keeps compatibility with Ubuntu 22.04 (the baseline CI OS) while staying modern.
The library itself has no runtime dependencies — only dev tools use Poetry.
Setting Up the Environment
We use Poetry for dependency and task management.
1. Install Poetry
curl -sSL https://install.python-poetry.org | python3 -
poetry --version
If Poetry isn’t on your PATH, add it to your shell configuration (usually ~/.bashrc or ~/.zshrc):
export PATH="$HOME/.local/bin:$PATH"
2. Install Dependencies
poetry install --with dev
This creates an isolated virtual environment with Ruff, Mypy, pytest, and Poe tasks.
Development Commands
All key workflows are defined in [tool.poe.tasks] inside pyproject.toml.
| Command | Description |
|---|---|
poetry run poe check:fix |
Auto-fix issues, re-format, type-check, and re-test. |
poetry run poe check |
Run linting (ruff), type checks (mypy), and tests (pytest). |
poetry run poe fix |
Run all auto-fixers (ruff). |
poetry run poe build:script |
Bundle the project into a single portable script in dist/. |
poetry run poe build:zipapp |
Create a cross-platform zipapp (.pyz) with dependency support. |
poetry run poe release:version |
Check what version would be released (dry run). |
poetry run poe release:publish |
Publish a release (creates tag, GitHub release, etc.). |
poetry run poe release:changelog |
Generate changelog without releasing. |
Example workflow:
# Auto-fix & re-check
poetry run poe check:fix
Pre-commit Hook
Pre-commit is configured to run poe fix on each commit,
and poe check before every push.
This keeps your local commits tidy and ensures CI stays green.
Install the hook once:
poetry run pre-commit install --install-hooks
poetry run pre-commit install --hook-type pre-push
If any linter, type check, or test fails, the commit is blocked. It may have auto-fixed the problem, try committing again before troubleshooting.
Testing
Run the test suite directly:
poetry run poe test
Pytest will discover all files in tests/ automatically.
Testing on Python 3.10
The project supports Python 3.10+ and CI tests on both Python 3.10 and the latest 3.x.
To test locally on Python 3.10, you can either use a system-installed Python 3.10 or mise.
[!NOTE] mise setup is optional. You can develop and test on any Python 3.10+ version.
Thetest:py310task is only useful if you want to match CI’s Python 3.10 environment exactly.
Quick Check
First, run the setup check to see if Python 3.10 is available:
poetry run poe setup:python:check
This command will:
- Check for system Python 3.10
- Check for mise-managed Python 3.10
- Provide installation instructions if not found
- Verify everything is working
Option 1: System Python 3.10 (Simplest)
If you’re on Ubuntu/Debian and Python 3.10 is available in your repositories:
sudo apt install python3.10 python3.10-venv python3.10-dev
Then you can use poetry run poe env:py310 directly — no mise needed!
Option 2: mise (For Multiple Versions or Newer Systems)
If Python 3.10 isn’t available via your system package manager (e.g., Ubuntu 24.04), you can use mise:
1. Install mise (if not already installed):
curl https://mise.run | sh
2. Add to your shell configuration (~/.bashrc or ~/.zshrc):
eval "$(mise activate bash)"
3. Restart your shell or run source ~/.bashrc
4. Run the check command — it will guide you through the rest:
poetry run poe setup:python:check
The check command will:
- Verify mise is set up correctly
- Check if Python 3.10 is installed
- Provide exact commands for installing Python 3.10 via mise
- Verify everything is working
[!TIP] Run
poetry run poe setup:python:checkrepeatedly until it shows all checks passing. It provides interactive, step-by-step guidance.
[!NOTE] The
env:py310task automatically detects system Python 3.10 first, then falls back to mise if needed.
Using Python 3.10 for Testing
Once Python 3.10 is available, you can switch between Python versions:
# Switch to Python 3.10
poetry run poe env:py310
# Run tests on Python 3.10, then switch back
poetry run poe test:py310
# Switch back to latest Python 3.x
poetry run poe env:py3x
Previewing Documentation Locally
The documentation site is built with Jekyll and can be previewed locally before pushing changes.
Prerequisites
You’ll need Ruby 3.3 for Jekyll. The project supports both system Ruby and mise-managed Ruby.
Quick Check
First, run the setup check to see if Ruby 3.3 is available:
poetry run poe setup:ruby:check
This command will:
- Check for system Ruby 3.3
- Check for mise-managed Ruby 3.3
- Provide installation instructions if not found
- Verify everything is working
Option 1: System Ruby 3.3 (Simplest)
If you’re on Ubuntu/Debian and Ruby 3.3 is available in your repositories:
sudo apt install ruby3.3 ruby3.3-dev
Option 2: mise (For Multiple Versions or Newer Systems)
If Ruby 3.3 isn’t available via your system package manager, you can use mise:
1. Install mise (if not already installed):
curl https://mise.run | sh
2. Add to your shell configuration (~/.bashrc or ~/.zshrc):
eval "$(mise activate bash)"
3. Restart your shell or run source ~/.bashrc
4. Run the check command — it will guide you through the rest:
poetry run poe setup:ruby:check
The check command will:
- Verify mise is set up correctly
- Check if Ruby 3.3 is installed
- Provide exact commands for installing Ruby 3.3 via mise
- Verify everything is working
[!NOTE] If you’re using mise, Ruby 3.3 will be automatically activated when you enter the project directory (via
.tool-versions).
Building and Serving the Documentation
Once Ruby 3.3 is available:
1. Install Jekyll dependencies:
cd docs
bundle install
2. Start the Jekyll server:
bundle exec jekyll serve
3. Open your browser:
Navigate to http://localhost:4000/python-logging/
[!NOTE] The baseurl is
/python-logging, so make sure to include it in the local URL.
The server will automatically rebuild when you make changes to the documentation files.
Building and Publishing (for maintainers)
Apathetic Python Logger ships in three forms:
| Target | Command | Output |
|---|---|---|
| Single-file script | poetry run poe build:script |
Creates dist/apathetic_logging.py (human-readable, stitched source) |
| Zipapp | poetry run poe build:zipapp |
Creates dist/apathetic_logging.pyz (dependency-aware, importable) |
| PyPI package | poetry build && poetry publish |
Builds and uploads wheel & sdist |
Automated Release Process (Recommended)
Releases are automated using python-semantic-release. Simply use Conventional Commits in your commit messages, and releases happen automatically when you push to main.
Commit Message Format
Use conventional commit prefixes to trigger version bumps:
feat:→ Minor version bump (e.g.,0.1.0→0.2.0)fix:→ Patch version bump (e.g.,0.1.0→0.1.1)feat!:orBREAKING CHANGE:→ Major version bump (e.g.,0.1.0→1.0.0)
Examples:
git commit -m "feat: add new logging utility function"
git commit -m "fix: resolve issue with error handling"
git commit -m "feat!: change API signature for getLogger"
Automated Release Workflow
When you push commits to main:
- Semantic-release analyzes commits — Determines if a release is needed based on commit messages
- If a release is needed:
- Bumps version in
pyproject.toml - Updates
RELEASES.mdwith changelog from commits - Creates a git tag (e.g.,
v0.2.0) - Creates a GitHub release with notes from
RELEASES.md - Uploads Poetry build artifacts (wheel & sdist) to the release
- Uploads custom assets (
apathetic_logging.pyandapathetic_logging.pyz)
- Bumps version in
- Tag triggers PyPI publish — The publish workflow automatically publishes to PyPI
Testing Releases Locally
You can test what semantic-release would do without actually creating a release:
# Check what version would be released (dry run)
poetry run poe release:version
# Generate changelog without releasing
poetry run poe release:changelog
Release Tasks
| Command | Description |
|---|---|
poetry run poe release:version |
Check what version would be released (dry run) |
poetry run poe release:publish |
Actually publish a release (creates tag, GitHub release, etc.) |
poetry run poe release:changelog |
Generate changelog without releasing |
Manual Release Process (Fallback)
If you need to create a release manually (e.g., for hotfixes or special cases):
- Bump version in
pyproject.toml:# Edit pyproject.toml and update: version = "X.Y.Z" - Update RELEASES.md with the new version section:
# Add a new section at the top with version, date, and changes - Commit the changes:
git add pyproject.toml RELEASES.md git commit -m "chore: bump version to X.Y.Z" - Create and push the git tag:
git tag -a vX.Y.Z -m "Release vX.Y.Z - Description" git push origin main git push origin vX.Y.Z - Publishing happens automatically — The publish workflow will:
- Build the package
- Publish to PyPI (when tag is pushed)
- Upload custom assets to the GitHub release (if it exists)
Note: For testing, you can use the
testpypi_onlyoption in the publish workflow to publish to TestPyPI first.
Both distribution files are automatically attached to GitHub releases:
dist/apathetic_logging.py— single-file script (human-readable, stitched source)dist/apathetic_logging.pyz— zipapp format (dependency-aware, importable)
Integration with Apathetic Tools
When contributing, keep in mind that this library is designed to integrate strongly with:
- serger — the module stitching tool
- Other Apathetic Tools projects
Changes should maintain compatibility with the broader Apathetic Tools ecosystem and work seamlessly in both modular and single-file distributions.
Contribution Rules
- Follow PEP 8 (enforced via Ruff).
- Use Conventional Commits for commit messages — this enables automated releases.
- Keep the core library dependency-free — dev tooling lives only in
pyproject.toml’sdevgroup. - Run
poetry run poe checkbefore committing. - Open PRs against the
mainbranch. - Be kind: small tools should have small egos.
Getting Help
- 📘 Roadmap
- 🐛 Issue Tracker
- 💬 Discord
Thank you for helping keep Apathetic Python Logger minimal, dependency-free, and delightful.