Skip to content

Commit 0fb1a55

Browse files
Merge pull request #71 from tsillus/license-whitelist
Added option --only-licenses to allow whitelisting of licenses
2 parents f2d3c5f + e9f522d commit 0fb1a55

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,32 @@ See below for the output if you run `licensecheck` in this directory
139139
└────────────┴─────────────────────┴──────────────────────────────────────┘
140140
```
141141

142+
### Only allow a predefined set of licenses
143+
144+
```txt
145+
146+
>> licensecheck --only-licenses mit
147+
148+
list of packages
149+
┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
150+
┃ Compatible ┃ Package ┃ License(s) ┃
151+
┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
152+
│ ✖ │ idna │ BSD License │
153+
│ ✖ │ certifi │ Mozilla Public License 2.0 (MPL 2.0) │
154+
│ ✖ │ Pygments │ BSD License │
155+
│ ✖ │ commonmark │ BSD License │
156+
│ ✖ │ requirements-parser │ Apache Software License │
157+
│ ✔ │ fhconfparser │ MIT License │
158+
│ ✔ │ tomli │ MIT License │
159+
│ ✖ │ types-setuptools │ Apache Software License │
160+
│ ✔ │ attrs │ MIT License │
161+
│ ✔ │ charset-normalizer │ MIT License │
162+
│ ✔ │ rich │ MIT License │
163+
│ ✔ │ urllib3 │ MIT License │
164+
│ ✖ │ requests │ Apache Software License │
165+
└────────────┴─────────────────────┴──────────────────────────────────────┘
166+
```
167+
142168
### Custom requirements.txt in json format
143169

144170
Add optional path to requirements.txt as outlined in https://github.com/FHPythonUtils/LicenseCheck/issues/9#issuecomment-898878228. Eg. `licensecheck --using requirements:c:/path/to/reqs.txt;path/to/other/reqs.txt`
@@ -285,7 +311,8 @@ usage: __main__.py [-h] [--format FORMAT] [--file FILE] [--using USING]
285311
[--ignore-packages IGNORE_PACKAGES [IGNORE_PACKAGES ...]]
286312
[--fail-packages FAIL_PACKAGES [FAIL_PACKAGES ...]]
287313
[--ignore-licenses IGNORE_LICENSES [IGNORE_LICENSES ...]]
288-
[--fail-licenses FAIL_LICENSES [FAIL_LICENSES ...]] [--zero]
314+
[--fail-licenses FAIL_LICENSES [FAIL_LICENSES ...]]
315+
[--only_licenses ONLY_LICENSES [ONLY_LICENSES ...]] [--zero]
289316
290317
Output the licenses used by dependencies and check if these are compatible with the project license.
291318
@@ -304,6 +331,8 @@ options:
304331
a list of licenses to ignore (skipped, compat may still be False)
305332
--fail-licenses FAIL_LICENSES [FAIL_LICENSES ...]
306333
a list of licenses to fail (compat=False)
334+
--only-licenses ONLY_LICENSES [ONLY_LICENSES ...]
335+
a list of allowed licenses (any other license will fail)
307336
--skip-dependencies SKIP_DEPENDENCIES [SKIP_DEPENDENCIES ...]
308337
a list of dependencies to skip (compat=False)
309338
--zero, -0 Return non zero exit code if an incompatible license is found

licensecheck/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def cli() -> None:
6060
help="a list of licenses to fail (compat=False)",
6161
nargs="+",
6262
)
63+
parser.add_argument(
64+
"--only-licenses",
65+
help="a list of allowed licenses (any other license will fail)",
66+
nargs="+",
67+
)
6368
parser.add_argument(
6469
"--skip-dependencies",
6570
help="a list of packages to skip (compat=True)",
@@ -104,6 +109,7 @@ def cli() -> None:
104109
list(map(types.ucstr, simpleConf.get("fail_packages", []))),
105110
list(map(types.ucstr, simpleConf.get("ignore_licenses", []))),
106111
list(map(types.ucstr, simpleConf.get("fail_licenses", []))),
112+
list(map(types.ucstr, simpleConf.get("only_licenses", []))),
107113
list(map(types.ucstr, simpleConf.get("skip_dependencies", []))),
108114
)
109115

licensecheck/get_deps.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def getDepsWithLicenses(
176176
failPackages: list[ucstr],
177177
ignoreLicenses: list[ucstr],
178178
failLicenses: list[ucstr],
179+
onlyLicenses: list[ucstr],
179180
skipDependencies: list[ucstr],
180181
) -> tuple[License, set[PackageInfo]]:
181182
"""Get a set of dependencies with licenses and determine license compatibility.
@@ -188,6 +189,7 @@ def getDepsWithLicenses(
188189
ignoreLicenses (list[ucstr]): a list of licenses to ignore (skipped, compat may still be
189190
False)
190191
failLicenses (list[ucstr]): a list of licenses to fail (compat=False)
192+
onlyLicenses (list[ucstr]): a list of allowed licenses (any other license will fail)
191193
skipDependencies (list[ucstr]): a list of dependencies to skip (compat=False)
192194
193195
Returns:
@@ -206,6 +208,7 @@ def getDepsWithLicenses(
206208
ucstr(JOINS.join(ignoreLicenses)), ignoreLicenses
207209
)
208210
failLicensesType = license_matrix.licenseType(ucstr(JOINS.join(failLicenses)), ignoreLicenses)
211+
onlyLicensesType = license_matrix.licenseType(ucstr(JOINS.join(onlyLicenses)), ignoreLicenses)
209212

210213
# Check it is compatible with packages and add a note
211214
packages = packageinfo.getPackages(reqs)
@@ -224,5 +227,6 @@ def getDepsWithLicenses(
224227
license_matrix.licenseType(package.license, ignoreLicenses),
225228
ignoreLicensesType,
226229
failLicensesType,
230+
onlyLicensesType,
227231
)
228232
return myLice, packages

licensecheck/license_matrix.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ def depCompatWMyLice(
137137
depLice: list[L],
138138
ignoreLicenses: list[L] | None = None,
139139
failLicenses: list[L] | None = None,
140+
onlyLicenses: list[L] | None = None,
140141
) -> bool:
141142
"""Identify if the end user license is compatible with the dependency license(s).
142143
@@ -146,6 +147,7 @@ def depCompatWMyLice(
146147
depLice (list[L]): dependency license
147148
ignoreLicenses (list[L], optional): list of licenses to ignore. Defaults to None.
148149
failLicenses (list[L], optional): list of licenses to fail on. Defaults to None.
150+
onlyLicenses (list[L], optional): list of allowed licenses. Defaults to None.
149151
150152
Returns:
151153
-------
@@ -156,13 +158,15 @@ def depCompatWMyLice(
156158
# Protect against None
157159
failLicenses = failLicenses or []
158160
ignoreLicenses = ignoreLicenses or []
161+
onlyLicenses = onlyLicenses or []
159162

160163
return any(
161164
liceCompat(
162165
myLicense,
163166
lice,
164167
ignoreLicenses,
165168
failLicenses,
169+
onlyLicenses,
166170
)
167171
for lice in depLice
168172
)
@@ -173,19 +177,23 @@ def liceCompat(
173177
lice: L,
174178
ignoreLicenses: list[L],
175179
failLicenses: list[L],
180+
onlyLicenses: list[L],
176181
) -> bool:
177182
"""Identify if the end user license is compatible with the dependency license.
178183
179184
:param L myLicense: end user license
180185
:param L lice: dependency license
181186
:param list[L] ignoreLicenses: list of licenses to ignore. Defaults to None.
182187
:param list[L] failLicenses: list of licenses to fail on. Defaults to None.
188+
:param list[L] onlyLicenses: list of allowed licenses. Defaults to None.
183189
:return bool: True if compatible, otherwise False
184190
"""
185191
if lice in failLicenses:
186192
return False
187193
if lice in ignoreLicenses:
188194
return True
195+
if onlyLicenses and (lice not in onlyLicenses):
196+
return False
189197
licenses = list(L)
190198
row, col = licenses.index(myLicense) + 1, licenses.index(lice) + 1
191199

tests/test_license_matrix.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ def test_dualLicenseCompat() -> None:
5050
assert license_matrix.depCompatWMyLice(types.L.MIT, [types.L.GPL_2, types.L.MIT])
5151

5252

53+
def test_whitelistedLicenseCompat() -> None:
54+
assert license_matrix.depCompatWMyLice(types.L.MIT, [types.L.MIT], onlyLicenses=[types.L.MIT])
55+
assert license_matrix.depCompatWMyLice(types.L.MPL, [types.L.MIT], onlyLicenses=[types.L.MIT])
56+
assert not license_matrix.depCompatWMyLice(types.L.MIT, [types.L.MIT], onlyLicenses=[types.L.MPL])
57+
assert not license_matrix.depCompatWMyLice(types.L.MPL, [types.L.MIT], onlyLicenses=[types.L.MPL])
58+
59+
5360
def test_warningsForIgnoredLicense(caplog: LogCaptureFixture) -> None:
5461
zope = types.ucstr("ZOPE PUBLIC LICENSE")
5562
license_matrix.licenseLookup(zope, [])

0 commit comments

Comments
 (0)