Skip to content

Commit e35e689

Browse files
Carreauhenryiii
andauthored
Add check that Deprecated Trove classifiers are not used. (#553)
* Add check that Deprecated Trove classifiers are not used. * fix: add to docs and narrower check Signed-off-by: Henry Schreiner <[email protected]> * fix: add to docs and narrower check Signed-off-by: Henry Schreiner <[email protected]> --------- Signed-off-by: Henry Schreiner <[email protected]> Co-authored-by: Henry Schreiner <[email protected]>
1 parent 9475432 commit e35e689

File tree

6 files changed

+93
-2
lines changed

6 files changed

+93
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ for family, grp in itertools.groupby(collected.checks.items(), key=lambda x: x[1
302302
- [`PP002`](https://learn.scientific-python.org/development/guides/packaging-simple#PP002): Has a proper build-system table
303303
- [`PP003`](https://learn.scientific-python.org/development/guides/packaging-classic#PP003): Does not list wheel as a build-dep
304304
- [`PP004`](https://learn.scientific-python.org/development/guides/packaging-simple#PP004): Does not upper cap Python requires
305+
- [`PP005`](https://learn.scientific-python.org/development/guides/packaging-simple#PP005): Using SPDX project.license should not use deprecated trove classifiers
305306
- [`PP301`](https://learn.scientific-python.org/development/guides/pytest#PP301): Has pytest in pyproject
306307
- [`PP302`](https://learn.scientific-python.org/development/guides/pytest#PP302): Sets a minimum pytest to at least 6
307308
- [`PP303`](https://learn.scientific-python.org/development/guides/pytest#PP303): Sets the test paths

docs/_includes/pyproject.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ You can read more about each field, and all allowed fields, in
4545
or [Whey](https://whey.readthedocs.io/en/latest/configuration.html). Note that
4646
"Homepage" is special, and replaces the old url setting.
4747

48+
### License
49+
50+
The license can be done one of two ways. The classic convention (shown above)
51+
uses one or more [Trove Classifiers][] to specify the license. The other way is
52+
to use the `license` field and an [SPDX identifier expression][spdx]:
53+
54+
```toml
55+
license = "BSD-3-Clause"
56+
```
57+
58+
You can also specify files to include with the `license-files` field.
59+
60+
You should not include the `License ::` classifiers if you use the `license`
61+
field {% rr PP007 %}. Some backends do not support this fully yet (notably
62+
Poetry and Setuptools).
63+
4864
### Extras
4965

5066
It is recommended to use extras instead of or in addition to making requirement
@@ -85,3 +101,5 @@ function, followed by a colon, then the function to call. If you use
85101
work to call the app (`__name__` will be `"__main__"` in that case).
86102

87103
[metadata]: https://packaging.python.org/en/latest/specifications/core-metadata/
104+
[trove classifiers]: https://pypi.org/classifiers/
105+
[spdx]: https://spdx.org/licenses

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ authors = [
1010
]
1111
description = "Review repos for compliance to the Scientific-Python development guidelines"
1212
requires-python = ">=3.10"
13+
license-expression = 'BSD-3-Clause'
1314
classifiers = [
1415
"Development Status :: 4 - Beta",
1516
"Environment :: Console",
1617
"Environment :: WebAssembly :: Emscripten",
1718
"Intended Audience :: Developers",
1819
"Intended Audience :: Science/Research",
19-
"License :: OSI Approved :: BSD License",
2020
"Operating System :: OS Independent",
2121
"Programming Language :: Python :: 3",
2222
"Programming Language :: Python :: 3.10",

src/sp_repo_review/checks/pyproject.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,29 @@ def check(pyproject: dict[str, Any], package: Traversable) -> bool | None:
9494
return None
9595

9696

97+
class PP005(PyProject):
98+
"Using SPDX project.license should not use deprecated trove classifiers"
99+
100+
requires = {"PY001"}
101+
url = mk_url("packaging-simple")
102+
103+
@staticmethod
104+
def check(pyproject: dict[str, Any]) -> bool | None:
105+
"""
106+
If you use SPDX identifiers in `project.license`, then all the `License ::`
107+
classifiers are deprecated.
108+
109+
See https://packaging.python.org/en/latest/specifications/core-metadata/#license-expression
110+
"""
111+
match pyproject:
112+
case {"project": {"license": str(), "classifiers": classifiers}}:
113+
return all(not c.startswith("License ::") for c in classifiers)
114+
case {"project": {"license": str()}}:
115+
return True
116+
case _:
117+
return None
118+
119+
97120
class PP301(PyProject):
98121
"Has pytest in pyproject"
99122

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
extend = "pyproject.toml"
2-
target-version = "3.9"
2+
target-version = "py39"

tests/test_pyproject.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,55 @@ def test_PP004_not_present(tmp_path: Path):
113113
assert compute_check("PP004", pyproject={}, package=tmp_path).result is None
114114

115115

116+
def test_PP005_no_license():
117+
toml = toml_loads("""
118+
[project]
119+
license.text = "MIT"
120+
classifiers = ["License :: OSI Approved :: MIT License"]
121+
""")
122+
123+
assert compute_check("PP005", pyproject=toml).result is None
124+
125+
126+
def test_PP005_pass():
127+
toml = toml_loads("""
128+
[project]
129+
license = "MIT"
130+
""")
131+
132+
assert compute_check("PP005", pyproject=toml).result
133+
134+
135+
def test_PP005_pass_empty_classifiers():
136+
toml = toml_loads("""
137+
[project]
138+
license = "MIT"
139+
classifiers = []
140+
""")
141+
142+
assert compute_check("PP005", pyproject=toml).result
143+
144+
145+
def test_PP005_pass_other_classifiers():
146+
toml = toml_loads("""
147+
[project]
148+
license = "MIT"
149+
classifiers = ["Something :: Else"]
150+
""")
151+
152+
assert compute_check("PP005", pyproject=toml).result
153+
154+
155+
def test_PP005_both():
156+
toml = toml_loads("""
157+
[project]
158+
license = "MIT"
159+
classifiers = ["License :: OSI Approved :: MIT License"]
160+
""")
161+
162+
assert not compute_check("PP005", pyproject=toml).result
163+
164+
116165
def test_PP302_okay_intstr():
117166
toml = toml_loads("""
118167
[tool.pytest.ini_options]

0 commit comments

Comments
 (0)