A Python CLI to inspect, validate, and manage license and copyright headers.
Project description
TopMark
TopMark is a command-line tool to inspect, validate, and manage file headers in diverse codebases. It helps maintain consistent header metadata across projects by supporting per-file-type header formats, customizable fields, inclusion/exclusion rules, and dry-run safety.
📚 Documentation
Full documentation is available on Read the Docs: https://topmark.readthedocs.io
This README is the canonical, complete introduction for GitHub/PyPI. The docs site provides a concise landing page and deep links into topics (install, usage, CI, API, etc.).
📝 Example headers
TopMark inserts headers that are tailored to the comment style and conventions of each file type. Here are examples of how TopMark headers appear in different file formats:
#!/bin/bash
# topmark:header:start
#
# project : TopMark
# file : script.sh
# license : MIT
# copyright : (c) 2025 Olivier Biot
# topmark:header:end
echo "Hello, World!"
<?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>
// topmark:header:start
//
// project : TopMark
// file : app.js
// license : MIT
// copyright : (c) 2025 Olivier Biot
//
// topmark:header:end
console.log("Hello, World!");
✨ Features
- File header detection, insertion, and replacement
- Supports multiple file types (Python, Makefile, Markdown,
.env, ...) - Configurable comment styles and header fields
- Inclusion and exclusion logic (via CLI, globs, stdin, or config)
- Dry-run by default; safe for CI/CD integration
- Configuration via
pyproject.tomlortopmark.toml - Shell completion for enum-based options
- Colorized CLI output (via
yachalk) - Python ≥3.10
- Integrated pre-commit hooks for automated checks
- Formatting and linting support via Makefile targets
- CI-friendly design for safe automated use
- Strict static typing with mypy and Pyright, using PEP 604 union syntax
- Google-style docstrings without redundant type declarations
- Full header removal (
topmark strip) - Preserves original newline style (LF/CRLF/CR) and BOM
- Idempotent updates (re-running does not change already-correct files)
- Structured diagnostics with severity levels (
info,warning,error) and aggregate counts
🚀 Installation
git clone https://github.com/shutterfreak/topmark.git
cd topmark
make setup # creates virtualenv, installs dependencies and tools
Or install into an existing virtualenv:
pip install -e .
Or install the latest release from PyPI:
pip install topmark
⚙️ Usage
Note: In dry-run mode, TopMark shows summaries ending with
- previewed. When run with--apply, summaries end with terminal statuses such as- inserted,- replaced, or- removed.
topmark [SUBCOMMAND] [OPTIONS] [PATHS]...
The check and strip commands performs a dry‑run by default
and will only apply changes when --apply is provided.
Logging verbosity is controlled globally:
CLI verbosity has two layers:
- Program output (user-facing):
-v,--verbose: Show more detail, including per-line diagnostics in summaries.-q,--quiet: Suppress most output (overrides-v).
- Internal logging (developer/machine):
- Also mapped by
-v/-q, controls log level (DEBUG/INFO/WARNING/ERROR).
- Also mapped by
All other options are specific to individual subcommands.
Subcommands
| Command | Description |
|---|---|
check |
Add / Update TopMark headers in files |
dump-config |
Show the resolved configuration in TOML format |
filetypes |
List supported file types and their comment styles |
processors |
List registered header processors and file types |
strip |
Remove TopMark headers from files (destructive) |
version |
Print TopMark version |
show-defaults |
Show default config (without merging) |
init-config |
Output a starter configuration file |
Examples
# Check Python files in the src/ directory
topmark check --file-type python src/
# Use exclusion patterns, and compute relative paths from src
topmark check --file-type python --exclude .venv --relative-to src src/
# Add one verbosity level to topmark, use exclusion patterns from .gitignore
topmark -v check --file-type python --exclude-from .gitignore src/
# Read a list of files from STDIN, generate summary
find . -name "*.py" | topmark check --file-type python --files-from - --summary
# Process all files that are either staged, or untracked but not ignored in a Git repo (needs dedulication with `sort -u`)
git ls-files -c -o --exclude-standard | sort -u | topmark check --files-from - --apply
# Read a single file's *content* from STDIN and render the resultng unified diff
cat README.md | topmark check - --stdin-filename README.md --diff
# Read a single file's *content* from STDIN and print the updated content to stdout
cat README.md | topmark check - --stdin-filename README.md --apply
# Dump the merged configuration (after loading all applicable config layers)
topmark dump-config --file-type python --exclude .venv --exclude-from .gitignore
# Display the default configuration without any merging
topmark show-defaults
# Output a starter configuration to stdout
topmark init-config
# Output TopMark version (PEP 440) in JSON format
topmark version --format json
# Output TopMark version (SemVer) to stdout
topmark version --semver
# Apply changes to files in-place
topmark check --apply src/
# Remove headers from files (dry-run)
topmark strip src/
# Remove headers from files and apply changes
topmark strip --apply src/
# CI-friendly summary: only show issues; ignore unsupported types
topmark check --skip-compliant --skip-unsupported src/
# Apply fixes, don't report unsupported files; default output is terse (pre-commit friendly)
topmark check --apply --skip-unsupported
# Show supported file types in MarkDown format, providing detailed output:
topmark filetypes --format markdown --long
# Show registered header processors (brief)
topmark processors
# Detailed Markdown listing of processors and their file types
topmark processors --format markdown --long
🔌 Public API (stable)
TopMark exposes a small, stable Python API for integrations. Import from topmark.api for core
operations, and use the registry facade for read-only discovery.
Quickstart
from pathlib import Path
from topmark import api
# Check (dry-run by default)
result = api.check([Path("src")])
print(result.summary) # {"unchanged": N, "error": M, ...}
print(result.had_errors) # True/False
# Apply changes explicitly
applied = api.check([Path("src")], apply=True)
# Remove headers
stripped = api.strip([Path("src")], apply=False)
Registry facade (read-only)
from topmark.registry import Registry
fts = Registry.filetypes() # Mapping[str, FileType]
procs = Registry.processors() # Mapping[str, HeaderProcessor]
for b in Registry.bindings(): # (filetype, optional processor)
print(b.filetype.name, bool(b.processor))
Note:
Registryis not re-exported fromtopmark.api; import it fromtopmark.registry.
Version helper
from topmark import api
print(api.version()) # e.g. "1.2.3"
Stability
topmark.apiand theRegistryfacade are covered by semantic versioning.- Low-level registries (
FileTypeRegistry,HeaderProcessorRegistry) remain available for plugins/tests but are advanced and may change between minor versions.
Adding & updating headers
Use the topmark check command to insert or update headers. It’s dry‑run by default; add
--apply to write changes. Placement follows file‑type policy (shebang/encoding for Python, XML
declaration for XML/HTML, etc.). Newline style and BOM are preserved; runs are idempotent.
Quick examples
# Preview (exit code 2 when changes are pending)
topmark check src/
# Apply in place
topmark check --apply src/
For full details, options, examples, and exit codes, see the dedicated guide: Adding & updating headers with
topmark
Removing headers with strip
Use topmark strip to remove the entire TopMark header block. The command is dry-run by
default; add --apply to write changes. It preserves newline style and BOM, and keeps XML
declarations and Markdown code fences intact.
Quick examples
# Preview (exit code 2 when removals are pending)
topmark strip src/
# Apply in place
topmark strip --apply src/
For full details, options, examples, and exit codes, see the dedicated guide: Removing headers with
topmark strip
Dumping the merged configuration
Use topmark dump-config to print the effective configuration (defaults → discovered config →
--config files → CLI flags) as TOML. This command is file‑agnostic: positional paths and
--files-from are ignored; filter flags (--include/--exclude, --include-from/--exclude-from)
are honored.
# Dump merged configuration
topmark dump-config
# Include/exclude filters still apply
topmark dump-config --exclude .venv --exclude-from .gitignore
# Read patterns from STDIN
printf "*.py\n" | topmark dump-config --include-from -
For details and notes, see: Dumping the merged configuration with
dump-config
Listing supported file types
Use topmark filetypes to see the identifiers you can pass to --file-type and the associated
comment styles TopMark will use when rendering headers.
# Show available file type identifiers
topmark filetypes
# Then restrict processing to one or more types
topmark check --file-type python src/
topmark check --file-type markdown --file-type env docs/ config/
For details, see: Listing supported file types with
filetypes
📐 Header placement rules
TopMark is comment-aware and places the header block according to the file type and its policy.
The complete header placement rules are documented in the usage guide:
🧩 Supported file types
See the full list and resolver behavior in the dedicated guide:
🪝 Pre-commit integration
TopMark ships with pre-commit hooks to validate or update file headers.
topmark-check— runs automatically atpre-commit/pre-push, fails if headers need changes.topmark-apply— manual only; applies fixes and may modify files.
For configuration examples, hook policies, and troubleshooting, see the dedicated guide:
🛠 Configuration
You can specify one or more --config files, or rely on local fallback resolution:
topmark.tomlin the working directorypyproject.tomlusing the[tool.topmark]table
TopMark reads configuration from one or more TOML files. Configuration is merged from:
- Built-in defaults
- Local project config (if not disabled via
--no-config) - Additional files via
--config - CLI overrides
Example configuration snippet (topmark.toml):
[fields]
project = "TopMark"
license = "MIT"
copyright = "(c) 2025 Olivier Biot"
[header]
fields = [ "file", "file_relpath", "project", "license", "copyright",]
[formatting]
align_fields = true
raw_header = false
[files]
file_types = [ "python", "markdown", "env" ]
include = []
include_from = []
exclude = []
exclude_from = [ ".gitignore" ]
relative_to = "."
Notes
formatting.align_fields = truevertically aligns the field names within the rendered header lines for readability.- File-type specific behavior (shebang handling, XML prolog, blank line policies) is driven by internal FileTypeHeaderPolicy defaults and can be extended to new types.
The EnumParam class enables shell completion for enum-based CLI options.
🧪 Development Setup
For development setup and contribution guidelines, see CONTRIBUTING.md.
To verify compatibility across supported Python versions (3.10–3.13), use tox to run tests and
type checks in each environment.
📄 License
MIT License © 2025 Olivier Biot
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.7.0.tar.gz.
File metadata
- Download URL: topmark-0.7.0.tar.gz
- Upload date:
- Size: 129.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc971f78941c8d969c0e06633b27445a6a5e2dce03fff2920873e1eedbd918e7
|
|
| MD5 |
44889c9d851ed25fa2bdeb7f6494b878
|
|
| BLAKE2b-256 |
805d2d2620910fcc21b82edb25dc3410d011d7af4cec41d8c3de6a91c0bfe00d
|
Provenance
The following attestation bundles were made for topmark-0.7.0.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.7.0.tar.gz -
Subject digest:
fc971f78941c8d969c0e06633b27445a6a5e2dce03fff2920873e1eedbd918e7 - Sigstore transparency entry: 550821944
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@43371cdd0c3edf38e1667f2b65c758692e3a6b8a -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@43371cdd0c3edf38e1667f2b65c758692e3a6b8a -
Trigger Event:
push
-
Statement type:
File details
Details for the file topmark-0.7.0-py3-none-any.whl.
File metadata
- Download URL: topmark-0.7.0-py3-none-any.whl
- Upload date:
- Size: 162.5 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 |
719038fda55fef4fa73446fbb4ec8cd7354858b107e9cbada8fcb442feb6bfb3
|
|
| MD5 |
026fe1f3f4bb1a1ab612cfccdd3e197e
|
|
| BLAKE2b-256 |
9e48fdcafb8b469b6c23aa6448ff2678d7d2d84c2c7d1cd5fcab4432ef982f88
|
Provenance
The following attestation bundles were made for topmark-0.7.0-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.7.0-py3-none-any.whl -
Subject digest:
719038fda55fef4fa73446fbb4ec8cd7354858b107e9cbada8fcb442feb6bfb3 - Sigstore transparency entry: 550821975
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@43371cdd0c3edf38e1667f2b65c758692e3a6b8a -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@43371cdd0c3edf38e1667f2b65c758692e3a6b8a -
Trigger Event:
push
-
Statement type: