Thank you for your interest in contributing to errortools — a toolset for working with Python exceptions, warnings, and logging. We welcome bug reports, documentation improvements, feature requests, refactors, performance work, and code submissions from the community.
Something needs to change or be refactored? Contact email errortools.docs@proton.me
Before you start, please skim these three documents — they are the source of truth that this guide points at:
| Document | Why read it |
|---|---|
PHILOSOPHY.md |
The why — the values, tradeoffs, and opinions that shape every design decision. |
.agents/AGENTS_PREVIEW.md |
The project snapshot: layout, public API map, conventions, anti-patterns. |
.agents/AGENTS_CHECK_LIST.md |
The pre-completion verification gate (style, typing, tests, CLI, docs, CI, version, anti-patterns). |
.agents/skills/ |
Reusable, task-shaped playbooks (e.g. add a public symbol, bump version, write tests). |
- Code of conduct
- Project at a glance
- Getting started
- Reporting issues
- Submitting changes
- Style and quality bar
- Pull request guidelines
- Code review process
- Release and versioning
- For AI coding agents
- Where to get help
We are committed to a welcoming and inclusive environment. Please be respectful
to all contributors and community members. The full expectations, examples of
unacceptable behaviour, and reporting process are in
.github/CODE_OF_CONDUCT.md.
| Item | Value |
|---|---|
| Package name | errortools |
| License | MIT (see LICENSE.txt) |
| Python support | >=3.8; type-checked against 3.13; 3.14 wheels shipped |
| Runtime dependencies | Exactly two: namebyauthor, typing_extensions |
| Code style | Google docstrings; black (line-length 120); flake8; mypy |
| Layout | Two-package: errortools/ (thin public re-export) → _errortools/ (real implementation) |
| CLI | python -m errortools … and logger … (console script from [project.scripts]) |
| Test runner | pytest with coverage on testing/ |
| Optional C extension | errortools_speedbelt._speedup / ._ignore_speed — pure-Python fallback is always present |
For a deeper orientation, see
.agents/AGENTS_PREVIEW.md §1 and §2.
- Python 3.8 or newer (the project is tested on 3.8 through 3.14).
- Git.
- A GitHub account.
# 1. Fork and clone
git clone https://github.com/more-abc/errortools.git
cd errortools
# 2. Create and activate a virtualenv
python -m venv .venv
# Linux / macOS:
source .venv/bin/activate
# Windows (cmd.exe):
.venv\Scripts\activate.bat
# Windows (PowerShell):
.venv\Scripts\Activate.ps1
# 3. Install in editable mode with dev extras
pip install -e .[dev]
# 4. (Optional) Install the extra lint tools referenced in CI
pip install pytest pytest-cov black flake8 mypy autoflake autopep8 pyflakes flake8-comprehensions flake8-bugbearTip. The CI workflows under
.github/workflows/are the source of truth for exactly which commands must pass. The list at.agents/AGENTS_CHECK_LIST.md§16 mirrors them and is the most reliable copy-pasteable checklist.
Blank issues are disabled (see .github/ISSUE_TEMPLATE/config.yml). Please
pick the template that matches what you want to report:
| Template | Use it for |
|---|---|
.github/ISSUE_TEMPLATE/bug_report.md |
A reproducible bug in errortools. |
.github/ISSUE_TEMPLATE/feature_request.md |
A new capability, public symbol, or CLI flag. |
.github/ISSUE_TEMPLATE/refactor.md |
A code-structure, readability, or maintainability improvement. |
.github/ISSUE_TEMPLATE/performance.md |
A slowness, memory, or allocation regression. |
.github/ISSUE_TEMPLATE/docs.md |
Missing, wrong, or unclear documentation. |
.github/ISSUE_TEMPLATE/add_label.md |
A proposal to add or update a label taxonomy. |
For everything else, start a thread in GitHub Discussions.
- Python version, OS, and
errortoolsversion (python -m errortools --version). - Minimal steps to reproduce (ideally a self-contained script).
- Expected vs. actual behaviour.
- Full traceback and any logs.
Do not file public issues for security vulnerabilities. Follow
.github/SECURITY.md and contact
errortools-security@proton.me privately, or open a GitHub Security
Advisory.
Branches follow the convention type/<name>, where type is one of:
feature/<name> new user-visible functionality
fix/<name> bug fix
refactor/<name> code structure / readability
docs/<name> documentation only
perf/<name> performance improvement
Example:
git checkout -b feature/exception-collector-benchmark- Read
PHILOSOPHY.mdand.agents/AGENTS_PREVIEW.mdbefore you start. - Place logic in
_errortools/. The publicerrortools/package is a re-export shim — do not add logic there except in__init__.pyand the three lazy submodule accessors (future.py,logging.py,partial.py). - Match the existing module style (Google docstrings, type hints,
from __future__ import annotations, no PEP 604 union syntax in runtime code — the project supports Python 3.8). - Keep changes atomic; one logical change per commit.
- Write commit messages in the imperative mood (
Add …,Fix …,Refactor …). - Never commit secrets.
pypi_token.txtand similar credentials are local-only.
Tests live under testing/ and follow the project's pytest discovery
rules (test_*.py files, Test* classes, test_* functions). The rule
of thumb is one concept per file — mirror the source path:
| Source | Test file |
|---|---|
_errortools/ignore.py |
testing/test_ignore.py |
_errortools/raises.py |
testing/test_raises.py |
_errortools/future.py |
testing/submodules/test_future.py |
_errortools/decorator/* |
testing/test_decorator.py |
_errortools/classes/* |
testing/classes/test_*.py |
_errortools/logging/* |
testing/logging/test_*.py |
_errortools/version.py |
testing/meta/test_version.py + testing/doctest/test_version.py |
_errortools/plugins.py |
testing/test_plugins.py |
_errortools/descriptor/* |
testing/test_descriptor.py |
_errortools/errno.py |
testing/test_errno.py |
_errortools/typing.py |
testing/test_typing.py |
BaseGroup / GroupErrors |
testing/test_groups.py |
| data-driven helpers | testing/test_data_driven.py |
Tests must be deterministic, fast, and isolated: no network, no real
time.sleep / asyncio.sleep, no reliance on wall-clock. If you add a
doctest, it is collected by pytest --doctest-modules in CI. See
.agents/skills/write-tests.md for
the full playbook.
If your PR fixes a bug, the workflow is:
- Before the fix, add a self-contained reproducer under
reproduce/sandbox/reproduce_issue_<N>.py(where<N>is the GitHub issue number). Seereproduce/sandbox/README.mdfor the naming convention. - Promote the reproducer body into the matching test under
testing/<area>/test_<file>.py. - Mark both items in the PR template.
This guarantees the bug is reproducible from a fresh clone before the fix lands, and that the regression is locked in afterwards.
For any user-visible change (new public symbol, behaviour change, bug fix, performance improvement, deprecation), add a one-line newsfragment:
reproduce/changelog/<PR>.<type>.md
where <PR> is the GitHub PR number and <type> is one of:
bug feature performance
refactor deprecation docs
Example: reproduce/changelog/123.performance.md
<!-- 123.performance.md -->
[#123](https://github.com/more-abc/errortools/issues/123) Avoid re-allocating `Record.extras` in `BaseLogger.info` hot path.On release, newsfragments are folded into ChangeLog.md and the file is
moved to reproduce/used_changelog/. See
reproduce/changelog/README.md.
When you change public behaviour, update:
- The docstring of the affected symbol (Google style, with an
Example:block where reasonable). - A one-line entry under
docs/api_reference/(or the closest user-guide page). - A runnable example under
docs/examples/if the change is non-trivial. - A
versionadded/versionchanged/deprecated/versionremoveddirective as appropriate. ChangeLog.md(under## [Unreleased]for in-flight work, or under a dated block on release).
Before pushing, every command below must exit 0:
# Static analysis and formatting
black .
flake8
flake8 --doctests
python -m pyflakes _errortools/
mypy _errortools/
flake8 --max-complexity 8 --select C901 _errortools/
# Autoflake / autopep8 must be no-ops after running once
autoflake --remove-all-unused-imports --remove-unused-variables \
--ignore-init-module-imports -r -i .
autopep8 . --recursive --in-place --pep8-passes 2000
# Tests + doctests + coverage
pytest # with coverage on _errortools
pytest --doctest-modules --no-cov # mirrors CI run-tests.yml
# CLI smoke tests
python -m errortools --help
python -m errortools -v
python -m errortools -i
python -m errortools --run-tests
python -m _errortools --debug
python -m _errortools --check
logger emit "smoke test" --level info
logger emit "warn" --level warning --output stderr
# Docs build
cd docs && sphinx-build -b html . _build/htmlIf you must skip a step, state the reason in the PR description.
git add <files>
git commit -m "Add <thing> in _errortools/<file>.py"
git push origin <type>/<branch-name>Open a pull request against main and fill in
.github/PULL_REQUEST_TEMPLATE.md. It has
six sections:
- Description — link the relevant
.agents/skills/<name>.mdyou followed. - Related Issues — use
Closes #NorRelates to #N. - Type of Change — tick exactly one.
- Scope — mark
Public API change,Behaviour change, orInternal. - Newsfragment — required for user-visible changes.
- Reproducer / Sandbox — required for bug fixes.
This is the short version. The canonical list is
.agents/AGENTS_CHECK_LIST.md.
- Never silently delete a public name. The deprecation pipeline
(
_DEPRECATED_NAMESinerrortools/__init__.py) is the only blessed way to retire a symbol — see.agents/skills/deprecate-public-name.md. - New parameters are always keyword-only with sensible defaults.
- New behaviour is opt-in: do not change defaults without a deprecation path.
- Line length 120 (
pyproject.toml [tool.black],.editorconfig). - Black's
target-versionis["py313"], but the runtime floor is Python 3.8 — useUnion[X, Y], notX | Y. - Google-style docstrings; doctest-friendly
Example:blocks render in Sphinx. - New files start with
from __future__ import annotations.
mypy _errortools/exits 0 with the project's existing flags (warn_return_any,warn_unused_configs,warn_unused_ignores,python_version = "3.13").- Reuse the existing aliases in
_errortools/typing.py(ExceptionType,WarningType,PureBaseExceptionType,BaseErrorCodesType,AnyErrorCode,TracebackType,FrameType). - Add
# type: ignore[reason]only with a short justification comment; prefer fixing the type.
- Tests are deterministic, fast, isolated. No network, no real
sleep. - The default pytest run includes
--cov=_errortools; do not disable coverage locally unless debugging. pytest --doctest-modules --no-covmirrors CI and must be green.
python -m errortools --help,-v,-i,-c,-a,-e,-l,-uall exit 0.logger emit --level info|debug|warning|error|critical --output stdout|stderr "msg"emits a single log line and exits 0.logger shelllaunches an interactive REPL with the documented pre-imported names (info,debug,error,warning,critical,trace,success,exception,catch,logger,Level,LEVELS,BaseLogger,Record,StreamSink,FileSink,CallableSink,Logger,Handler,Filter,Formatter).- If you add a CLI flag, update both
.github/workflows/cli-test.ymlanddocs/cli_tools/index.mdin the same commit.
- Sphinx docs live under
docs/and are built on Read the Docs from.readthedocs.yaml. - New public symbols need a corresponding entry under
docs/api_reference/(or the appropriate subfolder). - Non-trivial additions need a runnable example under
docs/examples/. - Use
versionadded,versionchanged,deprecated,versionremoveddirectives where appropriate.
- New classes in
_errortools/future.py(or other hot paths) use__slots__; no per-instance__dict__. - The optional
_speedup.cextension has a pure-Python fallback in every module that uses a C helper — never break the fallback. - Performance-sensitive code should be mirrored by a benchmark under
testing/benchmark/.
Before submitting, ensure every applicable box is ticked:
- Branch name follows
feature/<name>/fix/<name>/refactor/<name>/docs/<name>/perf/<name>. - Commits are atomic and use the imperative mood
(
Add …,Fix …,Refactor …). - New logic lives in
_errortools/; nothing was added undererrortools/except re-exports in__init__.py. - New public symbols are added to
__all__alphabetically in the appropriate bucket (functions/classes/type hints/plugins/metadata/submodules). - No backward-incompatible change to the public API.
- Tests added or updated in the matching
testing/<area>/file. -
reproduce/sandbox/reproduce_issue_<N>.pyadded for bug fixes. -
reproduce/changelog/<PR>.<type>.mdadded for user-visible changes. - Docs updated: docstring,
docs/api_reference/,docs/examples/as needed. -
ChangeLog.mdupdated under## [Unreleased]. -
black .,flake8,flake8 --doctests,pyflakes,mypy _errortools/,autoflake …,autopep8 …,pytest,pytest --doctest-modules --no-cov, CLI smoke tests, andsphinx-buildall exit 0. - PR description follows
.github/PULL_REQUEST_TEMPLATE.md. - Linked issues use
Closes #orRelates to #. - Reviewers requested per
.github/CODEOWNERS.
- Automated CI runs on every PR via
.github/workflows/:run-tests.yml—pytest --doctest-modules --no-covon Python 3.13 (Linux).pep8-check.yml—black .,autopep8,flake8,flake8 --doctests,pyflakes _errortools/.type-check.yml—mypy _errortools/.code-complexity.yml—flake8 --max-complexity 8 --select C901 _errortools/.autoflake-check.yml—autoflake --remove-all-unused-imports --remove-unused-variables ….cli-test.yml— every CLI flag exercised end-to-end.docs.yml—sphinx-build -b html . _build/html.- Plus the auto-merge / lock / label helpers
(
auto-awaiting-merge.yml,auto-comment.yml,auto-delete-branch.yml,auto-label.yml,block-merge-if-label.yml,lock-threads.yml).
- A maintainer reviews your code against the checklist above and
the project's
PHILOSOPHY.md. - You address any requested changes by pushing follow-up commits (do not force-push during review unless asked).
- Once approved, the PR is merged by a maintainer with write access. The auto-merge helper will handle the squash / rebase.
errortools follows Semantic Versioning and ships
from the main branch.
- Patch (
X.Y.Z+1) — backward-compatible bug fixes. - Minor (
X.Y+1.0) — backward-compatible features, new public symbols, new optional parameters, new deprecations. - Major (
X+1.0.0) — allowed to break the public API; the deprecation pipeline in_DEPRECATED_NAMESis the runway.
When you ship a user-visible change, the version bump is the maintainer's job — but the inputs come from you:
- Make sure
ChangeLog.mdhas an## [Unreleased]bullet (or newsfragment) describing the change. - If you deprecated or removed a public name, the ChangeLog bullet names the version that retires it.
- For a
minorormajorbump, adocs/whatsnew/<X>_<Y>.mdentry is added (linked fromdocs/whatsnew/index.md).
The version itself lives in two places that must stay in sync:
pyproject.toml→[project] version = "X.Y.Z"._errortools/version.py→__version__: Final[str] = "X.Y.Z".
The full playbook is
.agents/skills/bump-version.md.
This project ships a dedicated agent-oriented knowledge base under
.agents/. If you are an AI coding agent
(Cline, Cursor, Copilot, Claude Code, or similar), read it before doing
anything:
.agents/AGENTS_PREVIEW.md— project snapshot, public API map, conventions, anti-patterns..agents/AGENTS_CHECK_LIST.md— the pre-completion gate (the one you must tick every box of)..agents/skills/— task-shaped playbooks (add a public API, write tests, bump version, etc.).
Human contributors are welcome to skim the same documents — they reflect the project's actual conventions.
- First read
README.mdand https://errortools.readthedocs.io. - Then check
PHILOSOPHY.mdfor the values behind a decision. - Then open a GitHub Discussion for questions and ideas.
- For bugs / features, file an issue using the issue templates.
- For security, follow
.github/SECURITY.mdprivately — do not open a public issue. - For support, see
.github/SUPPORT.md. - By email:
- Documentation / general inquiries: errortools.docs@proton.me
- Security reports: errortools-security@proton.me
- General support: errortools-support@proton.me
Thank you for contributing! 🎉