Source code for pre_commit_hooks.license_headers

# ================================== LICENSE ===================================
# MIT License
#
# Copyright (c) 2023 - 2025 Andrey Rybakov (rybakov.ad@icloud.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# ================================ END LICENSE =================================
from argparse import ArgumentParser
from datetime import datetime


[docs] def ensure_license( filenames, license_template, verbose=False, ): r""" Insert license text at the top of the file. Every line at the beginning of the file, which is empty (consists only of spaces and a newline character at the end) or starts with a hash symbol ("#") is removed. Parameters ---------- filenames : list of str List of file to which the license is added. license_template : list of str Path to the file with the template of the license. """ license_start = f"# {' LICENSE ':=^78}\n" license_end = f"# {' END LICENSE ':=^78}\n" # Read license text from the template with open(license_template, "r") as f: license_text = f.read() # Update placeholders with the data def get_data(placeholder_name): if placeholder_name == "current-year": return str(datetime.now().year) raise ValueError(f'Placeholder "{placeholder_name}" is not supported.') license_text = license_text.split("{{") tmp_text = [] if len(license_text) >= 1: tmp_text.append(license_text[0]) for i in range(1, len(license_text)): text_portion = license_text[i].split("}}") if len(text_portion) == 1: raise ValueError( "data placeholder must be enclosed in the double figure " 'parenthesis, for example: "{{data-placeholder}}". Did not find closing ' f'"}}" for the opening "{{" number {i}.' ) if len(text_portion) != 2: raise ValueError( f'Expected only one closing "}}", found {len(text_portion) - 1}.' ) tmp_text.append(get_data(text_portion[0])) tmp_text.append(text_portion[1]) # Add comment symbols at the beginning tmp_text = "".join(tmp_text).split("\n") for i in range(len(tmp_text)): if len(tmp_text[i]) == 0: tmp_text[i] = "#" else: tmp_text[i] = "# " + tmp_text[i] license_text = "\n".join(tmp_text) + "\n" # Insert license text into the files for file in filenames: with open(file, "r") as f: lines = f.readlines() try: license_start_index = lines.index(license_start) except ValueError: license_start_index = None try: license_end_index = lines.index(license_end) except ValueError: license_end_index = None if license_start_index is None and license_end_index is None: lines = [license_start, license_text, license_end] + lines elif license_start_index is not None and license_end_index is not None: lines = ( lines[: license_start_index + 1] + [license_text] + lines[license_end_index:] ) else: raise ValueError( "License end and start are inconsistent. " f"Start index: {license_start_index}, end index: {license_end_index}. " f"File {file}" ) with open(file, "w", encoding="utf-8") as f: f.writelines(lines) if verbose: print(f"Add license to the file {file}")
def main(): parser = ArgumentParser() parser.add_argument( "filenames", nargs="*", help="Files to which the license text is added.", ) parser.add_argument( "-lt", "--license-template", default="LICENSE", help="Path to the template file of the license", ) parser.add_argument( "-v", "--verbose", default=False, action="store_true", help="Whether to indicate which files are updated.", ) args = parser.parse_args() ensure_license(**vars(args)) if __name__ == "__main__": main()