The add_license_headers.py module#

Summary#

get_start_year_from_git

Return the year of the first (oldest) commit in the git repository.

set_lint_args

Add lint arguments to the parser for REUSE.

get_full_paths

Update file paths to be absolute paths with system separators.

update_license_file

Update the LICENSE file to match the license template, adjusting the year span for each repo.

link_assets

Link the default template and/or license from the assets folder to your git repo.

generate_license_file

Generate the license file from the assets/LICENSES/.txt template.

mkdirs_and_link

Make .reuse or LICENSES directory and create symbolic link to file.

non_recursive_file_check

Check if the committed file is missing its header.

set_variables

Set variables to run REUSE on the project.

update_header

Update the license header of the file.

add_header

Add the license header to the file.

check_same_content

Check if file before the hook ran is the same as after the hook ran.

apply_hook_changes

Add earlier hook changes to updated file with header.

get_content

Read a file and return its content.

update_year_range

Update the year in the copyright statement of a file.

get_years_from_file

Get the start and end years from the year range in the file.

cleanup

Unlink the default asset files, and remove directories if empty.

main

Add and update file headers with REUSE.

DEFAULT_TEMPLATE

Default template to use for license headers.

DEFAULT_COPYRIGHT

Default copyright line for license headers.

DEFAULT_LICENSE

Default license for headers.

DEFAULT_START_YEAR

Fallback start year used when git history is unavailable.

YEAR_REGEX

Year regex to match year or year range in files.

HEADER_PEEK_BYTES

Number of bytes read from the top of a file to check for an existing license header.

Description#

Module for running REUSE to add missing license headers to files.

A license header consists of the Ansys copyright statement and licensing information.

Module detail#

add_license_headers.get_start_year_from_git(git_repo) int#

Return the year of the first (oldest) commit in the git repository.

Uses git log --reverse to find the oldest commit and extracts its year. When the repository is a shallow clone (e.g. fetch-depth: 1 in CI/CD), attempts git fetch --unshallow to retrieve the full history before reading the first commit year. If unshallowing fails (no network access, no remote configured, etc.) the function continues with the limited history that is locally available. Falls back to DEFAULT_START_YEAR (the current year) when the repository has no commits yet.

Parameters:
git_repo: git.Repo

The git repository object.

Returns:
int

The four-digit year of the first commit, or the current year if the repository has no commits.

add_license_headers.set_lint_args(parser: argparse.ArgumentParser) argparse.Namespace#

Add lint arguments to the parser for REUSE.

Parameters:
parser: argparse.ArgumentParser

Parser without any lint arguments.

Returns:
argparse.Namespace

Parser namespace containing lint arguments.

add_license_headers.get_full_paths(file_list: list) list#

Update file paths to be absolute paths with system separators.

Parameters:
file_list: list

List containing committed files.

Returns:
list

List containing the full paths of committed files.

add_license_headers.update_license_file(repo_license_path: pathlib.Path, year_span: str, license: str = DEFAULT_LICENSE) int#

Update the LICENSE file to match the license template, adjusting the year span for each repo.

Parameters:
repo_license_path: Path

Path to the LICENSE file in the repository.

year_span: str

The user start year to the current year. If they are the same, default to the current year.

license: str

The license identifier to use. Defaults to DEFAULT_LICENSE (MIT).

Returns:
int

0 if the year in the LICENSE file was not updated. 1 if the year in the LICENSE file was updated.

Link the default template and/or license from the assets folder to your git repo.

Only creates symlinks or generates files if they don’t already exist or point to the wrong target, avoiding unnecessary filesystem churn.

Parameters:
assets: dict

Dictionary containing the asset folder information.

git_root: str

Full path of the repository’s root directory.

args: argparse.Namespace

Namespace of arguments with their values.

add_license_headers.generate_license_file(template_parent_dir: pathlib.Path, year_span: int | str, license_file_name: pathlib.Path, license: str = DEFAULT_LICENSE) None#

Generate the license file from the assets/LICENSES/.txt template.

Parameters:
template_parent_dir: Path

Path to the parent directory of the template file.

year_span: int

The user start year to the current year. If they are the same, default to the current year. For example, “2024” or “2023 - 2025”.

license_file_name: Path

Path to the license file in the repository to generate.

license: str

The license identifier. Defaults to DEFAULT_LICENSE (MIT).

Make .reuse or LICENSES directory and create symbolic link to file.

Skips symlink creation if destination already points to the correct source, avoiding unnecessary filesystem operations on every invocation.

Parameters:
asset_dir: str

Path of the asset directory required for REUSE (.reuse/templates or LICENSES).

hook_asset_dir: str

Full path of the hook’s asset directory.

repo_asset_dir: str

Full path of the git repository’s asset directory.

filename: str

Name of the file to be linked from the hook_asset_dir to the repo_asset_dir.

add_license_headers.non_recursive_file_check(changed_headers: int, obj: common.ClickObj, values: dict, args: argparse.Namespace) int#

Check if the committed file is missing its header.

Parameters:
changed_headers: int

0 if no headers were added or updated. 1 if headers were added or updated.

obj: common.ClickObj

A click object used in REUSE to annotate files.

values: dict

Dictionary containing the values of files, copyright, template, license, changed_headers, year, and git_repo.

args: argparse.Namespace

Namespace of arguments with their values.

Returns:
int

0 if all files contain headers and are up to date. 1 if REUSE changed all noncompliant files.

add_license_headers.set_variables(obj: common.ClickObj, values: dict, args: argparse.Namespace) tuple#

Set variables to run REUSE on the project.

Parameters:
obj: common.ClickObj

A click object used in REUSE to annotate files.

values: dict

Dictionary containing the values of files, copyright, template, license, changed_headers, year, and git_repo.

args: argparse.Namespace

Namespace of arguments with their values.

Returns:
tuple

Tuple containing the project, template, commented, license, files, copyright, and years.

add_license_headers.update_header(changed_headers: int, file: str, copyright: str, license: str, years: str, template: str, commented: bool, force_license: bool = False) int#

Update the license header of the file.

Parameters:
changed_headers: int

0 if no headers were added or updated. 1 if headers were added or updated.

file: str

The file whose header is being updated.

copyright: str

The copyright string of the header. For example, “Synopsys, Inc. and ANSYS, Inc. All rights reserved.”

license: str

The license of the header. For example, “MIT”.

years: str

The year span of the header. For example, “2024” or “2023 - 2025”.

template: str

The template to use for the header. For example, “ansys” for “ansys.jinja2”.

commented: bool

Whether the template is commented or not.

force_license: bool

When True, pass the full license list to add_header() so that a mismatched SPDX-License-Identifier (e.g. MIT when Apache-2.0 is requested) is fully replaced instead of being left unchanged. Defaults to False.

Returns:
int

0 if all files contain headers and are up to date. 1 if REUSE changed all noncompliant files.

add_license_headers.add_header(copyright: str, license: str, years: str, file: str, template: str, commented: bool, out: tempfile.NamedTemporaryFile | IO[str]) None#

Add the license header to the file.

Parameters:
copyright: str

The copyright line for the license header. For example, “Synopsys, Inc. and ANSYS, Inc. All rights reserved.”

license: str

The license for the license header. For example, “MIT”.

years: str

The year span in the license header. For example, “2024” or “2023 - 2025”.

file: str

The file path to add the license header to.

template: str

The template to use for the license header. For example, “ansys.jinja2”.

commented: bool

Whether the template is commented or not.

out: Union[NamedTemporaryFile, IO[str]]

Temporary file to capture the stdout of the add_header_to_file() function or sys.stdout.

add_license_headers.check_same_content(before_hook: str, after_hook: str) bool#

Check if file before the hook ran is the same as after the hook ran.

Parameters:
before_hook: str

Path to file before add-license-headers was run.

after_hook: str

Path to file after add-license-headers was run.

Returns:
bool

True if the files have the same content. False if the files have different content.

add_license_headers.apply_hook_changes(before_hook: str, after_hook: str) None#

Add earlier hook changes to updated file with header.

Parameters:
before_hook: str

Path to file before add-license-headers was run.

after_hook: str

Path to file after add-license-headers was run.

add_license_headers.get_content(file: str) str#

Read a file and return its content.

Parameters:
file: str

Path to the file to read.

Returns:
str

Content of the file.

add_license_headers.update_year_range(changed_headers: int, file: str, year_regex: str, user_start_year: str, current_year: str) int#

Update the year in the copyright statement of a file.

Parameters:
changed_headers: int

0 if no headers were added or updated. 1 if headers were added or updated.

file: str

The file to update the year in the header.

year_regex: str

The regex to match the year or year range in the file.

user_start_year: str

The start year provided by the user.

current_year: str

The current year.

Returns:
int

0 if the year is up to date. 1 if the year was updated.

add_license_headers.get_years_from_file(content: str, year_regex: str) tuple#

Get the start and end years from the year range in the file.

Parameters:
content: str

The content of the file.

year_regex: str

The regex to match the year or year range in the file.

add_license_headers.cleanup(assets: dict, os_git_root: str) None#

Unlink the default asset files, and remove directories if empty.

Parameters:
assets: dict

Dictionary containing assets information

os_git_root: str

Full path of the repository’s root directory.

add_license_headers.main()#

Add and update file headers with REUSE.

Returns:
int

0 if all files contain headers and are up to date. 1 if REUSE changed all noncompliant files.

add_license_headers.DEFAULT_TEMPLATE = 'ansys'#

Default template to use for license headers.

Default copyright line for license headers.

add_license_headers.DEFAULT_LICENSE = 'MIT'#

Default license for headers.

add_license_headers.DEFAULT_START_YEAR#

Fallback start year used when git history is unavailable.

add_license_headers.YEAR_REGEX = '(\\d{4}) - (\\d{4})|\\d{4}'#

Year regex to match year or year range in files.

add_license_headers.HEADER_PEEK_BYTES = 1024#

Number of bytes read from the top of a file to check for an existing license header.

License headers always appear at the very start of a file and are at most a few hundred bytes, so reading only this many bytes avoids loading the full file for every checked file.

add_license_headers.logger#