Licenseheaders
licenseheaders is a Python 3 command-line tool designed to add or change license headers for all files of supported types in a given directory tree. It supports various predefined templates and allows for custom templates and variable substitutions. The current version is 0.8.8, and it appears to be actively maintained, with the last PyPI update on April 8, 2021, and GitHub issues still being addressed.
Common errors
-
Not a built-in template
cause The `licenseheaders` tool cannot locate its bundled license templates, often occurring in isolated environments like pre-commit hooks where the package's internal file structure is not correctly mapped.fixWhen specifying a template, use the full path to a custom template file (e.g., `licenseheaders -t /path/to/my_license.tmpl ...`) instead of relying on built-in template names. -
XML parsing error or corrupted XML files after processing (e.g., 'Error: Content is not allowed in prolog.')
cause XML files require a specific processing instruction (e.g., `<?xml version="1.0" encoding="UTF-8"?>`) to be the very first line. If `licenseheaders` inserts a comment *before* this instruction, it invalidates the XML structure.fixUse the `--exclude` option to prevent `licenseheaders` from processing XML files (e.g., `licenseheaders ... -x '**/*.xml'`). Manually add headers to XML files, ensuring the XML processing instruction remains the first line. -
Copyright years in headers are incorrectly extracted or updated, sometimes picking up arbitrary four-digit numbers (e.g., '1950 Main St' becomes part of a year range).
cause The regular expression used by some license header tools to identify and update copyright years might be too broad, inadvertently matching other four-digit numbers in the file content, leading to incorrect year ranges or garbled headers.fixReview the `--years` or `--current-year` arguments carefully. If using custom templates, ensure the year variable (`${YEARS}`) is clearly isolated from other numerical content. If the issue persists, consider manually inspecting and correcting affected files, or contributing a more specific regex to the project.
Warnings
- gotcha Template variables (e.g., ${varname}) are substituted from environment variables prefixed with `LICENSE_HEADERS_` (e.g., `LICENSE_HEADERS_VARNAME`) or from command-line options. Ensure consistent naming or explicit definition to avoid missing substitutions, which can lead to incomplete license headers.
- gotcha The tool relies on recognizing specific comment styles for different languages. If `--additional-extensions` is used, the specified language must have a recognized comment style, otherwise files might not be processed. Additionally, file extensions containing multiple dots (e.g., '.py.j2') are not currently supported.
- gotcha When integrated into pre-commit hooks or other isolated environments, `licenseheaders` may fail to find its bundled license templates, resulting in a 'Not a built-in template' error.
- gotcha The `--enc` command-line parameter for specifying file encoding might not correctly handle or apply the encoding when reading templates, potentially leading to issues with non-UTF-8 characters in headers or content.
Install
-
pip install licenseheaders
Imports
- main
from licenseheaders import main
Quickstart
import os
# Ensure licenseheaders is installed: pip install licenseheaders
# Create a dummy file for demonstration
with open("example.py", "w") as f:
f.write("def my_func():\n pass\n")
# Run licenseheaders from the command line to add an LGPLv3 license
# to a dummy Python file in the current directory, with a specific owner.
# This simulates running `licenseheaders -t lgpl3 -o "Your Name" -f example.py`
print("Adding LGPLv3 license to example.py...")
os.system('python -m licenseheaders -t lgpl3 -o "Your Name" -f example.py')
print("\nContent of example.py after adding license:")
with open("example.py", "r") as f:
print(f.read())
# Clean up
os.remove("example.py")