Skip to main content

A Python CLI to inspect, validate, and manage license and copyright headers.

Project description

TopMark

PyPI version Documentation Status Downloads GitHub release

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 (line comments like #///, and block comments like /* … */). 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!");
/*
 * topmark:header:start
 *
 *   project   : TopMark
 *   file      : styles.css
 *   license   : MIT
 *   copyright : (c) 2025 Olivier Biot
 *
 * topmark:header:end
 */

body { margin: 0; }

✨ 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.toml or topmark.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).

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: Registry is not re-exported from topmark.api; import it from topmark.registry.

Version helper

from topmark import api
print(api.version())  # e.g. "1.2.3"

Stability

  • topmark.api and the Registry facade 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 at pre-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

TopMark supports layered configuration discovery with clear precedence and path semantics. Configuration can come from multiple sources and is merged in the following order:

  1. Built‑in defaults (topmark-default.toml)

  2. User config (~/.config/topmark/topmark.toml or ~/.topmark.toml)

  3. Project chain discovered upward from the discovery anchor: (first input path; its parent if it’s a file; otherwise CWD when no inputs)

    • pyproject.toml ([tool.topmark] table)
    • topmark.toml (tool‑specific file)
    • same‑directory precedence: pyproject.tomltopmark.toml
    • stops when root = true is found
  4. Explicit config files via --config (you can specify one or more --config files)

  5. CLI flags and options (highest precedence)

Each layer is merged into a single effective configuration, which can be inspected with topmark dump-config.

TopMark resolves paths relative to where they are defined:

  • Config‑declared globs are resolved relative to the config file’s directory.
  • CLI‑declared globs are resolved relative to the current working directory.
  • Path‑to‑file settings (e.g., exclude_from, files_from) are resolved relative to the declaring source (config dir or CWD for CLI).
  • relative_to affects only header metadata (e.g., file_relpath), not discovery.

For complete details and examples, see
Configuration: Discovery & Precedence.

Example (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 = true vertically aligns field names for readability.
  • File-type–specific behavior (shebang handling, XML prolog, blank-line policies) is driven by the internal FileTypeHeaderPolicy defaults.
  • Use topmark dump-config to see the effective merged configuration after all layers and overrides are applied.

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

LICENSE (MIT)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

topmark-0.9.0.tar.gz (167.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

topmark-0.9.0-py3-none-any.whl (213.6 kB view details)

Uploaded Python 3

File details

Details for the file topmark-0.9.0.tar.gz.

File metadata

  • Download URL: topmark-0.9.0.tar.gz
  • Upload date:
  • Size: 167.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for topmark-0.9.0.tar.gz
Algorithm Hash digest
SHA256 95b58bd4439f7c98b1bc5285eef6aa89623886ab96a2b5d7ef60465f41d6db88
MD5 635a88318efb52b1e31ff19e0f7aa34d
BLAKE2b-256 957b9b14e0b11e2e4d429e13505088f2df5b878603c91244fc3f15656d0b5452

See more details on using hashes here.

Provenance

The following attestation bundles were made for topmark-0.9.0.tar.gz:

Publisher: release.yml on shutterfreak/topmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topmark-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: topmark-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 213.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for topmark-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c571aa915e67efcdc237d2285679ad6e1babc71d0f53b6a034c33f197fcc6715
MD5 c7934cb335ab109d3c82638db3095eab
BLAKE2b-256 94baba745dbc24bac1f93c55d15258888ab9ac3948a8b50ccc2c4fb6555022a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for topmark-0.9.0-py3-none-any.whl:

Publisher: release.yml on shutterfreak/topmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page