Skip to content

Commit 85523ec

Browse files
committed
Add support for licence-files option.
1 parent c9982f9 commit 85523ec

29 files changed

+382
-1
lines changed

pyproject_parser/parsers.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ class PEP621Parser(RequiredKeysConfigParser):
334334
"readme",
335335
"requires-python",
336336
"license",
337+
"license-files",
337338
"authors",
338339
"maintainers",
339340
"keywords",
@@ -678,6 +679,51 @@ def parse_license(config: Dict[str, TOML_TYPES]) -> License:
678679
else:
679680
raise BadConfigError("The 'project.license' table should contain one of 'text' or 'file'.")
680681

682+
# TODO: equivalent of PEP 621 direcrive for 639
683+
@_documentation_url("https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license-files")
684+
def parse_license_files(self, config: Dict[str, TOML_TYPES]) -> List[str]:
685+
"""
686+
Parse the ``license-files`` key, giving paths to the licence(s) for the project.
687+
688+
* **Format**: :toml:`Array` of :toml:`strings <string>`
689+
* **Core Metadata**: :core-meta:`License-Files`
690+
691+
.. versionadded:: 0.14.0
692+
693+
.. latex:vspace:: -5px
694+
695+
:bold-title:`Example:`
696+
697+
.. code-block:: TOML
698+
699+
[project]
700+
license-files = ["LICEN[CS]E*", "vendored/licenses/*.txt", "AUTHORS.md"]
701+
702+
.. latex:vspace:: -5px
703+
704+
:param config: The unparsed TOML config for the :pep621:`project table <table-name>`.
705+
"""
706+
707+
parsed_paths = set()
708+
key_path = [self.table_name, "license-files"]
709+
710+
license_files: List[str] = config["license-files"]
711+
self.assert_sequence_not_str(license_files, key_path)
712+
713+
for idx, pattern in enumerate(license_files):
714+
name = construct_path(key_path) + f"[{idx}]"
715+
self.assert_indexed_type(pattern, str, key_path, idx=idx)
716+
if pattern.startswith('/'):
717+
raise BadConfigError(f"{name!r}: pattern cannot start with '/'")
718+
if '\\' in pattern:
719+
raise BadConfigError(f"{name!r}: pattern cannot contain '\\'")
720+
if ".." in pattern:
721+
raise BadConfigError(f"{name!r}: pattern cannot contain '..'")
722+
723+
parsed_paths.add(pattern)
724+
725+
return natsorted(parsed_paths, alg=ns.GROUPLETTERS)
726+
681727
@staticmethod
682728
def _parse_authors(config: Dict[str, TOML_TYPES], key_name: str = "authors") -> List[Author]:
683729
all_authors: List[Author] = []

tests/test_cli.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
f"[project]\nname = 'spam'\nlicense = 'MIT AND (Apache-2.0 OR BSD-2-Clause)'\nversion = '2020.0.0'\n",
5252
id="PEP639"
5353
),
54+
pytest.param(
55+
f"[project]\nname = 'spam'\nlicense-files = ['LICEN[CS]E*', 'AUTHORS*']\nversion = '2020.0.0'\n",
56+
id="PEP639-FILES"
57+
),
5458
]
5559
)
5660
@pytest.mark.parametrize("show_diff", [True, False])
@@ -82,7 +86,7 @@ def test_reformat(
8286
with in_directory(tmp_pathplus):
8387
result = cli_runner.invoke(reformat, args=args, catch_exceptions=False)
8488

85-
assert result.exit_code == 0
89+
assert result.exit_code == 0, result.stdout
8690

8791
advanced_file_regression.check_file(tmp_pathplus / "pyproject.toml")
8892
assert result.stdout == "Reformatting 'pyproject.toml'\n"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reformatting 'pyproject.toml'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
name = "spam"
3+
version = "2020.0.0"
4+
license-files = [ "AUTHORS*", "LICEN[CS]E*",]
5+
dynamic = []
6+
7+
[tool]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Reformatting 'pyproject.toml'
2+
--- pyproject.toml (original)
3+
+++ pyproject.toml (reformatted)
4+
@@ -1,5 +1,8 @@
5+
[project]
6+
-name = 'spam'
7+
-license-files = ['LICEN[CS]E*', 'AUTHORS*']
8+
-version = '2020.0.0'
9+
+name = "spam"
10+
+version = "2020.0.0"
11+
+license-files = [ "AUTHORS*", "LICEN[CS]E*",]
12+
+dynamic = []
13+
14+
+[tool]
15+
+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
name = "spam"
3+
version = "2020.0.0"
4+
license-files = [ "AUTHORS*", "LICEN[CS]E*",]
5+
dynamic = []
6+
7+
[tool]

tests/test_config.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@
3939
id="pep639-and-or",
4040
),
4141
pytest.param(f"{MINIMAL_CONFIG}\nlicense = 'LicenseRef-My-Custom-License'\n", id="pep639-custom"),
42+
pytest.param(
43+
f"{MINIMAL_CONFIG}\nlicense-files = ['LICEN[CS]E*', 'AUTHORS*']\n", id="pep639-files-1"
44+
),
45+
pytest.param(
46+
f"{MINIMAL_CONFIG}\nlicense-files = ['licenses/LICENSE.MIT', 'licenses/LICENSE.CC0']\n",
47+
id="pep639-files-2"
48+
),
49+
pytest.param(
50+
f"{MINIMAL_CONFIG}\nlicense-files = ['LICENSE.txt', 'licenses/*']\n", id="pep639-files-3"
51+
),
52+
pytest.param(f"{MINIMAL_CONFIG}\nlicense-files = []\n", id="pep639-files-empty"),
4253
]
4354
)
4455
def test_pep621_class_valid_config(
@@ -422,6 +433,30 @@ def test_pep621_class_bad_config_license(
422433
r"'project.license-key' is not a valid SPDX Expression: \tUnknown license key\(s\): My-Custom-License",
423434
id="pep639-custom",
424435
),
436+
pytest.param(
437+
f"{MINIMAL_CONFIG}\nlicense-files = 'LICENSE'\n",
438+
TypeError,
439+
"Invalid type for 'project.license-files': expected <class 'collections.abc.Sequence'>, got <class 'str'>",
440+
id="pep639-files-string",
441+
),
442+
pytest.param(
443+
f"{MINIMAL_CONFIG}\nlicense-files = ['../LICENSE']\n",
444+
BadConfigError,
445+
r"'project.license-files\[0\]': pattern cannot contain '..'",
446+
id="pep639-files-1",
447+
),
448+
pytest.param(
449+
f"{MINIMAL_CONFIG}\nlicense-files = ['/home/user/project/LICENSE']\n",
450+
BadConfigError,
451+
r"'project.license-files\[0\]': pattern cannot start with '/'",
452+
id="pep639-files-2",
453+
),
454+
pytest.param(
455+
f"{MINIMAL_CONFIG}\nlicense-files = ['vendor\\LICENSE.MIT']\n",
456+
BadConfigError,
457+
r"'project.license-files\[0\]': pattern cannot contain '\\'",
458+
id="pep639-files-3",
459+
),
425460
]
426461
)
427462
def test_pep621_class_bad_config(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
dynamic: []
2+
license-files:
3+
- AUTHORS*
4+
- LICEN[CS]E*
5+
name: spam
6+
version: 2020.0.0
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
authors: []
2+
classifiers: []
3+
dependencies: []
4+
description: null
5+
dynamic: []
6+
entry-points: {}
7+
gui-scripts: {}
8+
keywords: []
9+
license: null
10+
license-files:
11+
- AUTHORS*
12+
- LICEN[CS]E*
13+
maintainers: []
14+
name: spam
15+
optional-dependencies: {}
16+
readme: null
17+
requires-python: null
18+
scripts: {}
19+
urls: {}
20+
version: 2020.0.0
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
dynamic: []
2+
license-files:
3+
- licenses/LICENSE.CC0
4+
- licenses/LICENSE.MIT
5+
name: spam
6+
version: 2020.0.0

0 commit comments

Comments
 (0)