Contributor guidelines
Developer prerequisites
pre-commit
Refer to pre-commit for installation instructions.
TL;DR:
curl -LsSf https://astral.sh/uv/install.sh | sh # Install uv
uv tool install pre-commit # Install pre-commit
pre-commit install # Install hooks
Installing pre-commit ensures all contributions adhere to the project’s code quality standards.
Code standards
ruff and doc8 are triggered automatically by pre-commit.
To run checks manually:
make doc8
make ruff
Import conventions
Import statements belong at module level. Avoid placing imports inside functions or methods unless absolutely necessary:
Acceptable exceptions:
Breaking circular dependencies
Optional runtime dependencies (e.g., CLI-only imports)
Heavy imports that are rarely used
Why this matters:
Improves code readability
Makes dependencies explicit and discoverable
Enables static analysis tools to work correctly
Follows Python community best practices (PEP 8)
When in doubt, place imports at the top of the file.
Virtual environment
make create-venv
Installation
make install
Testing
Note
Python 3.15 is being tested on GitHub CI, but not inside a local Docker image.
Docker-based testing (recommended)
All tests run inside Docker for platform independence and consistency:
make test # full matrix (Python 3.10-3.14)
make test-env ENV=py312 # single Python version
make shell # interactive shell in test container
make shell-env ENV=py312 # interactive shell for specific Python
Local testing (alternative)
For faster iteration during development, you can run tests locally with uv:
make install # one-time setup
uv run pytest # run all tests
uv run pytest path/to/test_something.py # run specific test
Important: If you encounter tooling errors with local testing, fall back to Docker-based testing which is the canonical environment.
GitHub Actions
In any case, GitHub Actions runs the full matrix automatically on every push. Tests run on Python 3.10–3.15 (all non-EOL versions). See the versions manifest for the full list of available Python versions.
Adding new normalisation rules
For a new alias or family override for an existing license:
Add an entry to
src/licence_normaliser/data/aliases/aliases.json.Optionally, add an
aliasesarray to define additional lookup variants (e.g. hyphen vs space forms) that resolve to the same target:{ "cc by-nc": { "version_key": "cc-by-nc", "name_key": "cc-by-nc", "family_key": "cc", "aliases": ["cc-by-nc", "cc by nc", "cc-by nc"] } }
Add a test in
src/licence_normaliser/tests/test_aliases.pyortest_alias_expansion.py.No Python changes needed.
For a new prose pattern (regex matching free-text descriptions):
Add an entry to
src/licence_normaliser/data/prose/prose_patterns.json.Add a test in
src/licence_normaliser/tests/test_prose.py.No Python changes needed.
For a new URL mapping:
Add an entry to
src/licence_normaliser/data/urls/url_map.jsonorsrc/licence_normaliser/data/publishers/publishers.json.Add a test in
src/licence_normaliser/tests/test_publisher.py.No Python changes needed.
For a brand-new license key (SPDX, OpenDefinition, OSI, CC, or ScanCode):
The upstream data source must be updated first (
licence-normaliser update-data --forcefor SPDX/OpenDefinition, or edit the upstream source for OSI/CC/ScanCode).The parser will pick it up automatically on the next import.
Add an alias in
aliases.jsonif needed.Add family override in
aliases.jsonif needed.Add tests.
For a new parser (new upstream data source):
Create
src/licence_normaliser/parsers/my_parser.pyimplementingBasePlugin.Register it in
src/licence_normaliser/parsers/__init__.py.Set
is_registry_entry = Falseif the parser only contributes aliases/URLs/patterns (not new license keys).Add tests.
Releases
Build the package for releasing:
make package-build
Test the built package:
make check-package-build
Make a test release (test.pypi.org):
make test-release
Release (pypi.org):
make release
Adding tests
Every new normalisation rule must have a corresponding test.
Tests should cover both successful normalisation and edge cases.
Pull requests
Open a pull request to the dev branch only. Never directly to main.
Note
Create pull requests to the dev branch only!
Examples of welcome contributions:
Fixing documentation typos or improving explanations.
Adding test cases for new edge cases.
Extending support for additional license formats.
Improving error messages.
General checklist
Does your change require documentation updates (
README.rst,AGENTS.md,ARCHITECTURE.rst,CONTRIBUTING.rst)?Does your change require new tests?
Does your change add any external dependencies? If so, reconsider:
licence-normalisershould have minimal dependencies.
When fixing bugs
Add a regression test that reproduces the bug before your fix.
When adding a new feature
Update
README.rst,AGENTS.md, andARCHITECTURE.rstif applicable.Add appropriate tests.
Questions
Ask on GitHub discussions.
Issues
Report bugs or request features on GitHub issues.