ansys-pre-commit-hooks 0.2.9__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 ANSYS, Inc. and/or its affiliates.
3
+ Copyright (c) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ansys-pre-commit-hooks
3
- Version: 0.2.9
3
+ Version: 0.3.1
4
4
  Summary: A Python wrapper to create Ansys-tailored pre-commit hooks
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: "ANSYS, Inc." <pyansys.core@ansys.com>
@@ -13,19 +13,16 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Operating System :: OS Independent
16
- Requires-Dist: importlib-metadata==7.0.1
17
- Requires-Dist: reuse==2.1.0
18
- Requires-Dist: GitPython==3.1.41
19
- Requires-Dist: ansys-sphinx-theme==0.13.3 ; extra == "doc"
20
- Requires-Dist: numpydoc==1.6.0 ; extra == "doc"
21
- Requires-Dist: sphinx==7.2.6 ; extra == "doc"
22
- Requires-Dist: sphinx-autoapi==3.0.0 ; extra == "doc"
23
- Requires-Dist: sphinx-autodoc-typehints==2.0.0 ; extra == "doc"
16
+ Requires-Dist: importlib-metadata==7.1.0
17
+ Requires-Dist: reuse==3.0.2
18
+ Requires-Dist: GitPython==3.1.43
19
+ Requires-Dist: ansys-sphinx-theme[autoapi]==0.15.2 ; extra == "doc"
20
+ Requires-Dist: numpydoc==1.7.0 ; extra == "doc"
21
+ Requires-Dist: sphinx==7.3.7 ; extra == "doc"
22
+ Requires-Dist: sphinx-autodoc-typehints==2.1.0 ; extra == "doc"
24
23
  Requires-Dist: sphinx-copybutton==0.5.1 ; extra == "doc"
25
- Requires-Dist: pytest==8.0.0 ; extra == "tests"
26
- Requires-Dist: pytest-cov==4.0.0 ; extra == "tests"
27
- Requires-Dist: reuse==2.1.0 ; extra == "tests"
28
- Requires-Dist: GitPython==3.1.41 ; extra == "tests"
24
+ Requires-Dist: pytest==8.1.1 ; extra == "tests"
25
+ Requires-Dist: pytest-cov==5.0.0 ; extra == "tests"
29
26
  Project-URL: Documentation, https://pre-commit-hooks.docs.ansys.com
30
27
  Project-URL: Homepage, https://github.com/ansys/pre-commit-hooks
31
28
  Project-URL: Source, https://github.com/ansys/pre-commit-hooks
@@ -119,7 +116,7 @@ Set custom arguments
119
116
  .. code:: yaml
120
117
 
121
118
  - repo: https://github.com/ansys/pre-commit-hooks
122
- rev: v0.2.9
119
+ rev: v0.3.1
123
120
  hooks:
124
121
  - id: add-license-headers
125
122
  args: ["--custom_copyright", "custom copyright phrase", "--custom_template", "template_name", "--custom_license", "license_name", "--ignore_license_check", "--start_year", "2023"]
@@ -164,7 +161,7 @@ the hook should run on, add the necessary regex to the ``files`` line in your
164
161
  .. code:: yaml
165
162
 
166
163
  - repo: https://github.com/ansys/pre-commit-hooks
167
- rev: v0.2.9
164
+ rev: v0.3.1
168
165
  hooks:
169
166
  - id: add-license-headers
170
167
  files: '(src|examples|tests|newFolder)/.*\.(py|newExtension)|\.(proto|newExtension)'
@@ -177,7 +174,7 @@ In .pre-commit-config.yaml:
177
174
  .. code:: yaml
178
175
 
179
176
  - repo: https://github.com/ansys/pre-commit-hooks
180
- rev: v0.2.9
177
+ rev: v0.3.1
181
178
  hooks:
182
179
  - id: add-license-headers
183
180
  exclude: |
@@ -84,7 +84,7 @@ Set custom arguments
84
84
  .. code:: yaml
85
85
 
86
86
  - repo: https://github.com/ansys/pre-commit-hooks
87
- rev: v0.2.9
87
+ rev: v0.3.1
88
88
  hooks:
89
89
  - id: add-license-headers
90
90
  args: ["--custom_copyright", "custom copyright phrase", "--custom_template", "template_name", "--custom_license", "license_name", "--ignore_license_check", "--start_year", "2023"]
@@ -129,7 +129,7 @@ the hook should run on, add the necessary regex to the ``files`` line in your
129
129
  .. code:: yaml
130
130
 
131
131
  - repo: https://github.com/ansys/pre-commit-hooks
132
- rev: v0.2.9
132
+ rev: v0.3.1
133
133
  hooks:
134
134
  - id: add-license-headers
135
135
  files: '(src|examples|tests|newFolder)/.*\.(py|newExtension)|\.(proto|newExtension)'
@@ -142,7 +142,7 @@ In .pre-commit-config.yaml:
142
142
  .. code:: yaml
143
143
 
144
144
  - repo: https://github.com/ansys/pre-commit-hooks
145
- rev: v0.2.9
145
+ rev: v0.3.1
146
146
  hooks:
147
147
  - id: add-license-headers
148
148
  exclude: |
@@ -5,7 +5,7 @@ build-backend = "flit_core.buildapi"
5
5
  [project]
6
6
  # Check https://flit.readthedocs.io/en/latest/pyproject_toml.html for all available sections
7
7
  name = "ansys-pre-commit-hooks"
8
- version = "0.2.9"
8
+ version = "0.3.1"
9
9
  description = "A Python wrapper to create Ansys-tailored pre-commit hooks"
10
10
  readme = "README.rst"
11
11
  requires-python = ">=3.9,<4"
@@ -27,24 +27,21 @@ classifiers = [
27
27
  "Operating System :: OS Independent",
28
28
  ]
29
29
  dependencies = [
30
- "importlib-metadata==7.0.1",
31
- "reuse==2.1.0",
32
- "GitPython==3.1.41",
30
+ "importlib-metadata==7.1.0",
31
+ "reuse==3.0.2",
32
+ "GitPython==3.1.43",
33
33
  ]
34
34
 
35
35
  [project.optional-dependencies]
36
36
  tests = [
37
- "pytest==8.0.0",
38
- "pytest-cov==4.0.0",
39
- "reuse==2.1.0",
40
- "GitPython==3.1.41",
37
+ "pytest==8.1.1",
38
+ "pytest-cov==5.0.0",
41
39
  ]
42
40
  doc = [
43
- "ansys-sphinx-theme==0.13.3",
44
- "numpydoc==1.6.0",
45
- "sphinx==7.2.6",
46
- "sphinx-autoapi==3.0.0",
47
- "sphinx-autodoc-typehints==2.0.0",
41
+ "ansys-sphinx-theme[autoapi]==0.15.2",
42
+ "numpydoc==1.7.0",
43
+ "sphinx==7.3.7",
44
+ "sphinx-autodoc-typehints==2.1.0",
48
45
  "sphinx-copybutton==0.5.1",
49
46
  ]
50
47
 
@@ -84,3 +81,38 @@ addopts = "--cov=ansys.pre_commit_hooks --cov-report term-missing -vv"
84
81
  testpaths = [
85
82
  "tests",
86
83
  ]
84
+
85
+ [tool.towncrier]
86
+ package = "ansys.pre_commit_hooks"
87
+ directory = "doc/changelog.d"
88
+ filename = "CHANGELOG.md"
89
+ start_string = "<!-- towncrier release notes start -->\n"
90
+ underlines = ["", "", ""]
91
+ template = "doc/changelog.d/changelog_template.jinja"
92
+ title_format = "## [{version}](https://github.com/ansys/pre-commit-hooks/releases/tag/v{version}) - {project_date}"
93
+ issue_format = "[#{issue}](https://github.com/ansys/pre-commit-hooks/pull/{issue})"
94
+
95
+ [[tool.towncrier.type]]
96
+ directory = "added"
97
+ name = "Added"
98
+ showcontent = true
99
+
100
+ [[tool.towncrier.type]]
101
+ directory = "changed"
102
+ name = "Changed"
103
+ showcontent = true
104
+
105
+ [[tool.towncrier.type]]
106
+ directory = "fixed"
107
+ name = "Fixed"
108
+ showcontent = true
109
+
110
+ [[tool.towncrier.type]]
111
+ directory = "dependencies"
112
+ name = "Dependencies"
113
+ showcontent = true
114
+
115
+ [[tool.towncrier.type]]
116
+ directory = "miscellaneous"
117
+ name = "Miscellaneous"
118
+ showcontent = true
@@ -38,7 +38,7 @@ import sys
38
38
  from tempfile import NamedTemporaryFile
39
39
 
40
40
  import git
41
- from reuse import _util, header, lint, project
41
+ from reuse import _annotate, _util, lint, project
42
42
 
43
43
  DEFAULT_TEMPLATE = "ansys"
44
44
  """Default template to use for license headers."""
@@ -86,7 +86,7 @@ def set_lint_args(parser: argparse.ArgumentParser) -> argparse.Namespace:
86
86
  help="Default license for headers.",
87
87
  default=DEFAULT_LICENSE,
88
88
  )
89
- # Get custom license
89
+ # Get the start year
90
90
  parser.add_argument(
91
91
  "--start_year",
92
92
  type=str,
@@ -200,12 +200,6 @@ def list_noncompliant_files(args: argparse.Namespace, proj: project.Project) ->
200
200
  missing_licensing_info = set(lint_json["non_compliant"]["missing_licensing_info"])
201
201
  missing_headers = missing_headers.union(missing_licensing_info)
202
202
 
203
- if lint_json["non_compliant"]["missing_licenses"]:
204
- missing_licenses = set(
205
- lint_json["non_compliant"]["missing_licenses"][args.custom_license]
206
- )
207
- missing_headers = missing_headers.union(missing_licenses)
208
-
209
203
  # Remove temporary file
210
204
  os.remove(filename)
211
205
 
@@ -244,9 +238,9 @@ def set_header_args(
244
238
  # Provide values for license header arguments
245
239
  args = parser.parse_args([file_path])
246
240
  if start_year == current_year:
247
- args.year = [str(current_year)]
241
+ args.year = [current_year]
248
242
  else:
249
- args.year = [start_year, str(current_year)]
243
+ args.year = [int(start_year), current_year]
250
244
  args.copyright_style = "string-c"
251
245
  args.copyright = [copyright]
252
246
  args.merge_copyrights = True
@@ -296,48 +290,41 @@ def check_exists(
296
290
  copyright = values["copyright"]
297
291
  template = values["template"]
298
292
 
299
- if i < len(files):
293
+ for file in files:
294
+ args = set_header_args(parser, start_year, current_year, file, copyright, template)
300
295
  # If the committed file is in missing_headers
301
- if (files[i] in missing_headers) or (os.path.getsize(files[i]) == 0):
296
+ if (file in missing_headers) or (os.path.getsize(file) == 0):
302
297
  changed_headers = 1
303
298
  # Run REUSE on the file
304
- args = set_header_args(parser, start_year, current_year, files[i], copyright, template)
305
299
  if not args.ignore_license_check:
306
300
  args.license = [values["license"]]
307
- header.run(args, proj)
308
301
 
309
- # Check if the next file is in missing_headers
310
- return check_exists(changed_headers, parser, values, proj, missing_headers, i + 1)
302
+ _annotate.run(args, proj)
311
303
  else:
312
- # Save current copy of files[i]
304
+ # Save current copy of file
313
305
  before_hook = NamedTemporaryFile(mode="w", delete=False).name
314
- shutil.copyfile(files[i], before_hook)
306
+ shutil.copyfile(file, before_hook)
315
307
 
316
308
  # Update the header
317
309
  # tmp captures the stdout of the header.run() function
318
310
  with NamedTemporaryFile(mode="w", delete=True) as tmp:
319
- args = set_header_args(
320
- parser, start_year, current_year, files[i], copyright, template
321
- )
322
- header.run(args, proj, tmp)
311
+ _annotate.run(args, proj, tmp)
323
312
 
324
313
  # Check if the file before add-license-headers was run is the same as the one
325
314
  # after add-license-headers was run. If not, apply the syntax changes
326
315
  # from other hooks before add-license-headers was run to the file
327
- if check_same_content(before_hook, files[i]) == False:
328
- add_hook_changes(before_hook, files[i])
316
+ if check_same_content(before_hook, file) == False:
317
+ add_hook_changes(before_hook, file)
329
318
 
330
319
  # Check if the file content before add-license-headers was run has been changed
331
320
  # Assuming the syntax was fixed in the above if statement, this check is
332
321
  # solely for the file's content
333
- if check_same_content(before_hook, files[i]) == False:
322
+ if check_same_content(before_hook, file) == False:
334
323
  changed_headers = 1
335
- print(f"Successfully changed header of {files[i]}")
324
+ print(f"Successfully changed header of {file}")
336
325
 
337
326
  os.remove(before_hook)
338
327
 
339
- return check_exists(changed_headers, parser, values, proj, missing_headers, i + 1)
340
-
341
328
  return changed_headers
342
329
 
343
330
 
@@ -447,6 +434,99 @@ def get_full_paths(file_list: list) -> list:
447
434
  return full_path_files
448
435
 
449
436
 
437
+ def update_license_file(arg_dict):
438
+ """
439
+ Update the LICENSE file to match MIT.txt, adjusting the year span to each repository.
440
+
441
+ Parameters
442
+ ----------
443
+ arg_dict: dict
444
+ Dictionary containing the committed files, custom copyright, template, license,
445
+ changed_headers, start & end year, and git_repo
446
+ """
447
+ # Get location of LICENSE file in the repository the hook runs on
448
+ git_root = arg_dict["git_repo"].git.rev_parse("--show-toplevel")
449
+ repo_license_loc = os.path.join(git_root, "LICENSE").replace(os.sep, "/")
450
+ save_repo_license = shutil.copyfile(repo_license_loc, f"{repo_license_loc}_save")
451
+
452
+ # Get the location of MIT.txt in the hook's assets folder
453
+ hook_loc = pathlib.Path(__file__).parent.resolve()
454
+ hook_license_file = os.path.join(hook_loc, "assets", "LICENSES", f"{DEFAULT_LICENSE}.txt")
455
+
456
+ # Copy MIT.txt from the assets folder to the LICENSE file in the repository
457
+ if os.path.isfile(repo_license_loc) and (arg_dict["license"] == DEFAULT_LICENSE):
458
+ shutil.copyfile(hook_license_file, repo_license_loc)
459
+
460
+ # Whether or not the year in LICENSE was updated
461
+ # 0 is unchanged, 1 is changed
462
+ changed = 0
463
+
464
+ # Check if custom_license is MIT
465
+ if os.path.isfile(repo_license_loc) and (arg_dict["license"] == DEFAULT_LICENSE):
466
+ if "3.9" in python_version():
467
+ file = fileinput.input(repo_license_loc, inplace=True)
468
+ else:
469
+ file = fileinput.input(repo_license_loc, inplace=True, encoding="utf8")
470
+
471
+ copyright = arg_dict["copyright"]
472
+ start_year = str(arg_dict["start_year"])
473
+ current_year = str(arg_dict["current_year"])
474
+
475
+ for line in file:
476
+ if copyright in line:
477
+ # Copyright line: "Copyright (c) 2023 - 2024 ANSYS, Inc. and/or its affiliates."
478
+ # Get the index of the closing parenthesis of the copyright line
479
+ paren_index = line.index(")") + 2
480
+ # Get the index of the start of the copyright statement
481
+ cpright_index = line.index(copyright) - 1
482
+ # Create the year string to be replaced in the copyright line
483
+ # For example, "2024", or "2023 - 2024"
484
+ year_range = (
485
+ f"{start_year} - {current_year}"
486
+ if (start_year != current_year)
487
+ else current_year
488
+ )
489
+
490
+ # If the start and end year are different
491
+ if start_year != current_year:
492
+ if "-" in line:
493
+ # Get the index of the dash in the year range of the LICENSE file
494
+ dash_index = line.index("-") - 1
495
+ # Get the start year of the existing copyright line in the LICENSE file
496
+ existing_start_year = line[paren_index:dash_index]
497
+ # If the start year argument and the existing start year are different,
498
+ # replace the existing start year with the new one.
499
+ # For example, the existing start year is 2023, but the start_year
500
+ # argument is 2022.
501
+ if start_year != existing_start_year:
502
+ line = line.replace(existing_start_year, start_year)
503
+ else:
504
+ # Replace the existing copyright years with the new year_range
505
+ line = line.replace(line[paren_index:cpright_index], year_range)
506
+ print(line.rstrip())
507
+ else:
508
+ if "-" in line:
509
+ # If there is a year range in the existing LICENSE file, but the
510
+ # start_year and current_year are the same, remove the year range
511
+ # and replace it with the current year
512
+ line = line.replace(line[paren_index:cpright_index], current_year)
513
+ print(line.rstrip())
514
+ else:
515
+ print(line.rstrip())
516
+
517
+ fileinput.close()
518
+
519
+ # If the year changed, print a message that the LICENSE file was changed
520
+ if not check_same_content(save_repo_license, repo_license_loc):
521
+ changed = 1
522
+ print(f"Successfully updated year in {repo_license_loc}")
523
+
524
+ # Remove the temporary file
525
+ os.remove(save_repo_license)
526
+
527
+ return changed
528
+
529
+
450
530
  def cleanup(assets: dict, os_git_root: str) -> None:
451
531
  """
452
532
  Unlink the default asset files, and remove directories if empty.
@@ -516,6 +596,9 @@ def find_files_missing_header() -> int:
516
596
  "git_repo": git_repo,
517
597
  }
518
598
 
599
+ # Update the year in the copyright line of the LICENSE file
600
+ license_return_code = update_license_file(values)
601
+
519
602
  # Run REUSE on root of the repository
520
603
  git_root = values["git_repo"].git.rev_parse("--show-toplevel")
521
604
 
@@ -538,7 +621,8 @@ def find_files_missing_header() -> int:
538
621
  # year, style, copyright-style, template, exclude-year, merge-copyrights, single-line,
539
622
  # multi-line, explicit-license, force-dot-license, recursive, no-replace,
540
623
  # skip-unrecognized, and skip-existing
541
- header.add_arguments(parser)
624
+ # header.add_arguments(parser)
625
+ _annotate.add_arguments(parser)
542
626
 
543
627
  # Link the default template and/or license from the assets folder to your git repo.
544
628
  link_assets(assets, os_git_root, args)
@@ -551,14 +635,14 @@ def find_files_missing_header() -> int:
551
635
 
552
636
  # Add or update headers of required files.
553
637
  # Return 1 if files were added or updated, and return 0 if no files were altered.
554
- return_code = check_exists(changed_headers, parser, values, proj, missing_headers, 0)
638
+ file_return_code = check_exists(changed_headers, parser, values, proj, missing_headers, 0)
555
639
 
556
640
  # Unlink default files & remove .reuse and LICENSES folders if empty
557
641
  cleanup(assets, os_git_root)
558
642
 
559
- # Returns 1 if REUSE changes noncompliant files
643
+ # Returns 1 if REUSE changes noncompliant files or the year was updated in LICENSE
560
644
  # Returns 0 if all files are compliant
561
- return return_code
645
+ return 1 if (license_return_code or file_return_code) == 1 else 0
562
646
 
563
647
 
564
648
  def main():