A Python CLI to inspect, validate, and manage license and copyright headers.
Project description
TopMark
TopMark is a command-line tool to inspect, insert, validate, and manage file headers in diverse codebases.
It maintains consistent metadata across files by supporting multiple comment styles, configuration formats, and dry-run safety.
📚 Documentation
Full documentation is hosted on Read the Docs:
👉 https://topmark.readthedocs.io
This README provides an overview. See the docs for deeper topics (install, usage, API, CI/CD, etc.).
🧩 Features
- Detect, insert, and replace file headers across multiple file types
- Comment-aware (line and block styles)
- Configurable header fields and alignment
- Dry-run by default for safety
- Policy-based control over when headers may be inserted, updated, or added to empty files
- Layered configuration via:
pyproject.toml([tool.topmark])topmark.toml- CLI overrides and
--config
- Fine-grained include/exclude rules
- Selective application via file patterns or
stdin - Strict static typing (PEP 604 unions, Pyright)
- Works well with
pre-commit, CI, and Git hooks - Preserves newline style (LF/CRLF/CR) and BOM
- Idempotent: re-running on already-compliant files makes no changes
- Configurable comment alignment and raw/pretty formatting
🧱 Example headers
TopMark adapts headers to the comment syntax of each file type.
Bash / Shell
#!/bin/bash
# topmark:header:start
#
# project : TopMark
# file : script.sh
# license : MIT
# copyright : (c) 2025 Olivier Biot
#
# topmark:header:end
echo "Hello, World!"
XML
<?xml version="1.0" encoding="UTF-8"?>
<!--
topmark:header:start
project : TopMark
file : config.xml
license : MIT
copyright : (c) 2025 Olivier Biot
topmark:header:end
-->
<configuration>
<!-- XML content here -->
</configuration>
JavaScript
// topmark:header:start
//
// project : TopMark
// file : app.js
// license : MIT
// copyright : (c) 2025 Olivier Biot
//
// topmark:header:end
console.log("Hello, World!");
CSS
/*
* topmark:header:start
*
* project : TopMark
* file : styles.css
* license : MIT
* copyright : (c) 2025 Olivier Biot
*
* topmark:header:end
*/
body { margin: 0; }
⚙️ Installation
From PyPI
pip install topmark
From source (development setup)
git clone https://github.com/shutterfreak/topmark.git
cd topmark
make venv
make venv-sync-dev
Run checks to confirm setup:
make verify
make test
Verify CLI
topmark version
topmark --help
🚀 Usage
topmark [COMMAND] [OPTIONS] [PATHS]...
Subcommands
| Command | Description |
|---|---|
check |
Add or update TopMark headers |
strip |
Remove TopMark headers |
dump-config |
Show resolved configuration (merged TOML) |
filetypes |
List supported file types |
processors |
List header processors and mappings |
show-defaults |
Show built-in defaults without merging |
init-config |
Output a starter configuration |
version |
Print version (PEP 440 or SemVer) |
Examples
# Preview (dry-run)
topmark check src/
# Apply in place
topmark check --apply src/
# Remove headers (dry-run)
topmark strip src/
# Remove headers and apply changes
topmark strip --apply src/
# Show supported file types in Markdown format
topmark filetypes --output-format markdown --long
# List processors and associated file types
topmark processors --output-format markdown --long
TopMark preserves line endings, shebangs, BOMs, and indentation rules for each file type.
🧠 Configuration & Policy
TopMark supports layered configuration discovery and a flexible policy system controlling insert/update behavior.
Discovery order
- Built-in defaults (
topmark-default.toml) - User config (
~/.config/topmark/topmark.tomlor~/.topmark.toml) - Project config (nearest upward
pyproject.tomlortopmark.toml) - Explicit
--configfiles (merged in order) - CLI flags and options (highest precedence)
Example topmark.toml
[fields]
project = "TopMark"
license = "MIT"
copyright = "(c) 2025 Olivier Biot"
[header]
fields = ["file", "file_relpath", "project", "license", "copyright"]
[tool.topmark.policy]
add_only = false
update_only = false
allow_header_in_empty_files = false
[tool.topmark.policy_by_type."python"]
allow_header_in_empty_files = true
[formatting]
align_fields = true
raw_header = false
[files]
file_types = ["python", "markdown", "env"]
exclude_from = [".gitignore"]
relative_to = "."
Policy semantics
| Setting | Meaning |
|---|---|
add_only = true |
Only insert headers into files without one; skip updating existing ones |
update_only = true |
Only update existing headers; skip inserting new ones |
allow_header_in_empty_files |
Allow adding headers to empty files (useful for e.g. __init__.py) |
Per-type overrides under [tool.topmark.policy_by_type."filetype"] can adjust specific behavior.
These policy options apply equally to the CLI and the public API.
See
docs/configuration/discovery.mdfor more detail on config precedence and path semantics.
🪝 Pre-commit Integration
TopMark includes pre-commit hooks for automated header management.
| Hook ID | Purpose |
|---|---|
topmark-check |
Validate headers (non-destructive) |
topmark-apply |
Apply header updates (manual) |
Install hooks:
pre-commit install
pre-commit run --all-files
Manual header fix (safe interactive mode):
pre-commit run topmark-apply --hook-stage manual --all-files
🔒 Public API
The public API now an optional policy argument (global or per-type) that integrates with the same resolution mechanism used by the CLI.
Example
from pathlib import Path
from topmark import api
from topmark.api.public_types import Policy
# Dry-run header checks
result = api.check(
[Path("src")],
apply=True,
policy=Policy(add_only=True)
)
print(result.summary)
print(result.had_errors)
# Apply changes
applied = api.check([Path("src")], apply=True)
# Remove headers
api.strip([Path("src")], apply=True)
For programmatic discovery:
from topmark.registry import Registry
for ft, proc in Registry.bindings():
print(ft.name, bool(proc))
📦 Packaging & Versioning
TopMark follows Semantic Versioning (SemVer).
| Change Type | Version Impact |
|---|---|
fix: |
Patch |
feat: |
Minor |
feat!: / BREAKING CHANGE: |
Major |
Build and check distributions:
python -m build
python -m twine check dist/*
Upload:
python -m twine upload dist/*
Tags are released via CI/CD.
🧪 Development
To test across all supported Python versions:
make test # tox default envs
tox -m api-check # API stability across all Python versions
For faster iteration:
make pytest # run tests in current interpreter
make lint # static linting
make verify # formatting, linting, docs, links
📄 License
MIT License © 2025 Olivier Biot
See LICENSE
TopMark — consistent headers for consistent projects.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file topmark-0.11.1.tar.gz.
File metadata
- Download URL: topmark-0.11.1.tar.gz
- Upload date:
- Size: 233.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0f86240510363f73444336c4cb249e1c1ea57fc10d7c2f1edde3f0178ef3e66
|
|
| MD5 |
310d8d41a7f510b3d013d6942823ab0f
|
|
| BLAKE2b-256 |
c693bcd0125fdfb3a7b06666198ef0ca45da4c5c8ad1c3d6aaaa3828f30934a6
|
Provenance
The following attestation bundles were made for topmark-0.11.1.tar.gz:
Publisher:
release.yml on shutterfreak/topmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topmark-0.11.1.tar.gz -
Subject digest:
b0f86240510363f73444336c4cb249e1c1ea57fc10d7c2f1edde3f0178ef3e66 - Sigstore transparency entry: 833798123
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@9136a16785fef30d40863619ea52ee129a2a2fc6 -
Branch / Tag:
refs/tags/v0.11.1 - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9136a16785fef30d40863619ea52ee129a2a2fc6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file topmark-0.11.1-py3-none-any.whl.
File metadata
- Download URL: topmark-0.11.1-py3-none-any.whl
- Upload date:
- Size: 301.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbecbaeea679e9ca85e75cc691a51790f866b2785e1dc85867f9fab0be7a793d
|
|
| MD5 |
5ed31c239eff0447448235cfbb3f9869
|
|
| BLAKE2b-256 |
5ffab309f56e41cdbd309fce5423fe49b33c7db02331fc91fff3986b34396c4c
|
Provenance
The following attestation bundles were made for topmark-0.11.1-py3-none-any.whl:
Publisher:
release.yml on shutterfreak/topmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topmark-0.11.1-py3-none-any.whl -
Subject digest:
fbecbaeea679e9ca85e75cc691a51790f866b2785e1dc85867f9fab0be7a793d - Sigstore transparency entry: 833798125
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@9136a16785fef30d40863619ea52ee129a2a2fc6 -
Branch / Tag:
refs/tags/v0.11.1 - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9136a16785fef30d40863619ea52ee129a2a2fc6 -
Trigger Event:
push
-
Statement type: