Skip to content

Commit a89f9fc

Browse files
committed
fixes
1 parent e5dc3c3 commit a89f9fc

File tree

13 files changed

+260
-261
lines changed

13 files changed

+260
-261
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
All major and minor version changes will be documented in this file. Details of
44
patch-level version changes can be found in [commit messages](../../commits/master).
55

6+
## 2025.0.1 - 2025/03/16
7+
8+
- update the cli interface to remove some confusing functionality
9+
- refactor the library / code qa improvements
10+
- Allow for alias of classifier in setup.cfg, thanks https://github.com/ericwb: #106
11+
- Add support for SPDX license expression metadata after PEP 639: #107
12+
- Add use regex/glob pattern to ignore multiple packages, thanks https://github.com/JulianKimmig: #108
13+
- Prioritise ['project'] table over ['tool.poetry'] in pyproject.toml: #104
14+
- Add option to show only failing packages: #98
15+
616
## 2024.3 - 2024/08/26
717

818
- Use uv to parse dependencies before falling back to the native resolver

README.md

Lines changed: 183 additions & 224 deletions
Large diffs are not rendered by default.

documentation/reference/licensecheck/checker.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
## check
1212

13-
[Show source in checker.py:43](../../../licensecheck/checker.py#L43)
13+
[Show source in checker.py:47](../../../licensecheck/checker.py#L47)
1414

1515
#### Signature
1616

@@ -39,13 +39,16 @@ def check(
3939

4040
## resolve_requirements
4141

42-
[Show source in checker.py:17](../../../licensecheck/checker.py#L17)
42+
[Show source in checker.py:18](../../../licensecheck/checker.py#L18)
4343

4444
#### Signature
4545

4646
```python
4747
def resolve_requirements(
48-
requirements_paths: list[str], groups: list[str], skip_dependencies: list[ucstr]
48+
requirements_paths: list[str],
49+
groups: list[str],
50+
skip_dependencies: list[ucstr],
51+
index_url: str,
4952
) -> set[ucstr]: ...
5053
```
5154

documentation/reference/licensecheck/cli.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def cli() -> None: ...
2424

2525
## main
2626

27-
[Show source in cli.py:112](../../../licensecheck/cli.py#L112)
27+
[Show source in cli.py:117](../../../licensecheck/cli.py#L117)
2828

2929
Test entry point.
3030

@@ -35,5 +35,5 @@ Note: FHConfParser (Parses in the following order: `pyproject.toml`,
3535
#### Signature
3636

3737
```python
38-
def main(args: dict | argparse.Namespace) -> int: ...
38+
def main(args: dict) -> int: ...
3939
```

documentation/reference/licensecheck/packageinfo.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
## LocalPackageInfo
2424

25-
[Show source in packageinfo.py:75](../../../licensecheck/packageinfo.py#L75)
25+
[Show source in packageinfo.py:77](../../../licensecheck/packageinfo.py#L77)
2626

2727
Handles retrieval of package info from local installation.
2828

@@ -34,7 +34,7 @@ class LocalPackageInfo: ...
3434

3535
### LocalPackageInfo.get_info
3636

37-
[Show source in packageinfo.py:78](../../../licensecheck/packageinfo.py#L78)
37+
[Show source in packageinfo.py:80](../../../licensecheck/packageinfo.py#L80)
3838

3939
Retrieve package metadata from local installation.
4040

@@ -61,7 +61,7 @@ def get_info(package: ucstr) -> PackageInfo: ...
6161

6262
### LocalPackageInfo.get_size
6363

64-
[Show source in packageinfo.py:104](../../../licensecheck/packageinfo.py#L104)
64+
[Show source in packageinfo.py:106](../../../licensecheck/packageinfo.py#L106)
6565

6666
Retrieve installed package size.
6767

@@ -97,12 +97,12 @@ Manages retrieval of local and remote package information.
9797

9898
```python
9999
class PackageInfoManager:
100-
def __init__(self, pypi_api: str = "https://pypi.org/pypi/") -> None: ...
100+
def __init__(self, base_pypi_url: str = "https://pypi.org") -> None: ...
101101
```
102102

103103
### PackageInfoManager().getPackages
104104

105-
[Show source in packageinfo.py:34](../../../licensecheck/packageinfo.py#L34)
105+
[Show source in packageinfo.py:36](../../../licensecheck/packageinfo.py#L36)
106106

107107
Retrieve package information from local installation or PyPI.
108108

@@ -126,7 +126,7 @@ def getPackages(self, reqs: set[ucstr]) -> set[PackageInfo]: ...
126126

127127
### PackageInfoManager().get_package_info
128128

129-
[Show source in packageinfo.py:48](../../../licensecheck/packageinfo.py#L48)
129+
[Show source in packageinfo.py:50](../../../licensecheck/packageinfo.py#L50)
130130

131131
Retrieve package information, preferring local data.
132132

@@ -154,7 +154,7 @@ def get_package_info(self, package: ucstr) -> PackageInfo: ...
154154

155155
## ProjectMetadata
156156

157-
[Show source in packageinfo.py:192](../../../licensecheck/packageinfo.py#L192)
157+
[Show source in packageinfo.py:194](../../../licensecheck/packageinfo.py#L194)
158158

159159
Handles extraction of project metadata from configuration files.
160160

@@ -166,7 +166,7 @@ class ProjectMetadata: ...
166166

167167
### ProjectMetadata.get_license
168168

169-
[Show source in packageinfo.py:220](../../../licensecheck/packageinfo.py#L220)
169+
[Show source in packageinfo.py:222](../../../licensecheck/packageinfo.py#L222)
170170

171171
Extract license from project metadata.
172172

@@ -188,7 +188,7 @@ def get_license() -> ucstr: ...
188188

189189
### ProjectMetadata.get_metadata
190190

191-
[Show source in packageinfo.py:195](../../../licensecheck/packageinfo.py#L195)
191+
[Show source in packageinfo.py:197](../../../licensecheck/packageinfo.py#L197)
192192

193193
Extract project metadata from setup.cfg or pyproject.toml.
194194

@@ -208,7 +208,7 @@ def get_metadata() -> dict[str, Any]: ...
208208

209209
## RemotePackageInfo
210210

211-
[Show source in packageinfo.py:115](../../../licensecheck/packageinfo.py#L115)
211+
[Show source in packageinfo.py:117](../../../licensecheck/packageinfo.py#L117)
212212

213213
Handles retrieval of package info from PyPI.
214214

@@ -220,7 +220,7 @@ class RemotePackageInfo: ...
220220

221221
### RemotePackageInfo.get_info
222222

223-
[Show source in packageinfo.py:118](../../../licensecheck/packageinfo.py#L118)
223+
[Show source in packageinfo.py:120](../../../licensecheck/packageinfo.py#L120)
224224

225225
Retrieve package metadata from PyPI.
226226

@@ -248,7 +248,7 @@ def get_info(package: ucstr, pypi_api: str) -> PackageInfo: ...
248248

249249
### RemotePackageInfo.get_size
250250

251-
[Show source in packageinfo.py:148](../../../licensecheck/packageinfo.py#L148)
251+
[Show source in packageinfo.py:150](../../../licensecheck/packageinfo.py#L150)
252252

253253
Retrieve package size from PyPI metadata.
254254

@@ -270,7 +270,7 @@ def get_size(data: dict[str, Any]) -> int: ...
270270

271271
## from_classifiers
272272

273-
[Show source in packageinfo.py:173](../../../licensecheck/packageinfo.py#L173)
273+
[Show source in packageinfo.py:175](../../../licensecheck/packageinfo.py#L175)
274274

275275
Extract license from classifiers.
276276

@@ -295,7 +295,7 @@ def from_classifiers(classifiers: list[str] | None) -> ucstr: ...
295295

296296
## meta_get
297297

298-
[Show source in packageinfo.py:160](../../../licensecheck/packageinfo.py#L160)
298+
[Show source in packageinfo.py:162](../../../licensecheck/packageinfo.py#L162)
299299

300300
Retrieve metadata value safely.
301301

documentation/reference/licensecheck/resolvers/uv.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
```python
1717
def get_reqs(
18-
skipDependencies: list[ucstr], extras: list[str], requirementsPaths: list[str]
18+
skipDependencies: list[ucstr],
19+
extras: list[str],
20+
requirementsPaths: list[str],
21+
index_url: str = "https://pypi.org",
1922
) -> set[ucstr]: ...
2023
```
2124

licensecheck/checker.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pathlib import Path
77

88
import tomli
9+
from loguru import logger
910

1011
from licensecheck import license_matrix
1112
from licensecheck.packageinfo import PackageInfoManager
@@ -18,15 +19,18 @@ def resolve_requirements(
1819
requirements_paths: list[str],
1920
groups: list[str],
2021
skip_dependencies: list[ucstr],
22+
index_url: str,
2123
) -> set[ucstr]:
2224
try:
2325
return res_uv.get_reqs(
2426
skipDependencies=skip_dependencies,
2527
extras=groups,
2628
requirementsPaths=requirements_paths,
29+
index_url=index_url,
2730
)
2831

29-
except RuntimeError:
32+
except RuntimeError as e:
33+
logger.warning(e)
3034
pyproject = {}
3135
if "pyproject.toml" in requirements_paths:
3236
pyproject = tomli.loads(Path("pyproject.toml").read_text("utf-8"))
@@ -60,7 +64,12 @@ def check(
6064
only_licenses = only_licenses or []
6165
skip_dependencies = skip_dependencies or []
6266

63-
requirements = resolve_requirements(requirements_paths, groups, skip_dependencies)
67+
requirements = resolve_requirements(
68+
requirements_paths,
69+
groups,
70+
skip_dependencies,
71+
index_url=package_info_manager.pypi_search,
72+
)
6473

6574
ignoreLicensesType = license_matrix.licenseType(
6675
ucstr(JOINS.join(ignore_licenses)), ignore_licenses

licensecheck/cli.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def cli() -> None: # pragma: no cover
3434
parser.add_argument(
3535
"--requirements-paths",
3636
"-r",
37-
help="Filenames to read from (omit for stdin)",
37+
help="Filenames to read from (omit for stdin if piping, else pyproject.toml)",
3838
nargs="+",
3939
)
4040
parser.add_argument(
@@ -91,7 +91,7 @@ def cli() -> None: # pragma: no cover
9191
parser.add_argument(
9292
"--pypi-api",
9393
help="Specify a custom pypi api endpoint, for example if using a custom pypi server",
94-
default="https://pypi.org/pypi/",
94+
default="https://pypi.org",
9595
)
9696
parser.add_argument(
9797
"--zero",
@@ -100,16 +100,21 @@ def cli() -> None: # pragma: no cover
100100
action="store_true",
101101
)
102102
args = vars(parser.parse_args())
103+
103104
stdin_path = Path("__stdin__")
104-
if stdin:
105-
stdin_path.write_text("\n".join(stdin.readlines()), "utf-8")
105+
if not args.get("requirements_paths"):
106+
if stdin.isatty():
107+
args["requirements_paths"] = ["pyproject.toml"]
108+
else:
109+
stdin_path.write_text("\n".join(stdin.readlines()), encoding="utf-8")
110+
106111
ec = main(args)
107112
stdin_path.unlink(missing_ok=True)
108113

109114
sysexit(ec)
110115

111116

112-
def main(args: dict | argparse.Namespace) -> int:
117+
def main(args: dict) -> int:
113118
"""Test entry point.
114119
115120
Note: FHConfParser (Parses in the following order: `pyproject.toml`,
@@ -142,7 +147,7 @@ def main(args: dict | argparse.Namespace) -> int:
142147

143148
# Get my license
144149
this_license_text = (
145-
args["license"] if args.get("license") else packageinfo.getMyPackageLicense()
150+
args["license"] if args.get("license") else packageinfo.ProjectMetadata.get_license()
146151
)
147152
this_license = license_matrix.licenseType(this_license_text)[0]
148153

licensecheck/packageinfo.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@
2323
class PackageInfoManager:
2424
"""Manages retrieval of local and remote package information."""
2525

26-
def __init__(self, pypi_api: str = "https://pypi.org/pypi/") -> None:
26+
def __init__(self, base_pypi_url: str = "https://pypi.org") -> None:
2727
"""Manage retrieval of local and remote package information.
2828
2929
:param str pypi_api: url of pypi server. Typically the public instance, defaults
30-
to "https://pypi.org/pypi/"
30+
to "https://pypi.org"
3131
"""
32-
self.pypi_api = pypi_api
32+
self.base_pypi_url = base_pypi_url
33+
self.pypi_api = base_pypi_url + "/pypi/"
34+
self.pypi_search = base_pypi_url + "/simple/"
3335

3436
def getPackages(self, reqs: set[ucstr]) -> set[PackageInfo]:
3537
"""Retrieve package information from local installation or PyPI.

licensecheck/resolvers/native.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def resolveExtraReq(extraReq: str) -> ucstr | None:
110110
msg = "Could not find specification of requirements (pyproject.toml)."
111111
raise RuntimeError(msg) from error
112112
for extra in extras:
113-
reqLists.append(project["optional-dependencies"][extra])
113+
extra_info = project.get("optional-dependencies", {}).get(extra)
114+
reqLists.append(extra_info) if extra_info else ""
114115
for reqList in reqLists:
115116
for req in reqList:
116117
reqs.add(resolveReq(req))

licensecheck/resolvers/uv.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def get_reqs(
1616
skipDependencies: list[ucstr],
1717
extras: list[str],
1818
requirementsPaths: list[str],
19+
index_url: str = "https://pypi.org",
1920
) -> set[ucstr]:
2021
for idx, requirement in enumerate(requirementsPaths):
2122
if not Path(requirement).exists():
@@ -29,7 +30,9 @@ def get_reqs(
2930
requirementsPaths[idx] = destination_file.as_posix()
3031

3132
extras_cmd = [f"--extra {extra}" for extra in extras]
32-
command = f"uv pip compile {' '.join(requirementsPaths)} {' '.join(extras_cmd)}"
33+
command = (
34+
f"uv pip compile {' '.join(requirementsPaths)} {' '.join(extras_cmd)} --index {index_url}"
35+
)
3336

3437
result = subprocess.run(command, shell=True, capture_output=True, text=True, check=False)
3538

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "licensecheck"
3-
version = "2025"
3+
version = "2025.0.1"
44
description = "Output the licenses used by dependencies and check if these are compatible with the project license"
55
authors = [{ name = "FredHappyface" }]
66
requires-python = ">=3.9"

tests/platform_independent/test_checker.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from __future__ import annotations
2-
import pytest
2+
33
from unittest.mock import MagicMock
4-
from licensecheck.types import PackageInfo, ucstr, License
5-
from licensecheck.packageinfo import PackageInfoManager
4+
5+
import pytest
6+
67
from licensecheck.checker import check
8+
from licensecheck.packageinfo import PackageInfoManager
9+
from licensecheck.types import License, PackageInfo, ucstr
710

811

912
@pytest.fixture
@@ -37,6 +40,7 @@ def test_check(
3740
PackageInfo(name="PACKAGE_B", license=ucstr("GPL-3.0"), licenseCompat=False),
3841
}
3942
mock_package_info_manager.getPackages.return_value = mock_packages
43+
mock_package_info_manager.pypi_search = "https://pypi.org/simple"
4044

4145
incompatible, packages = check(
4246
requirements_paths=["requirements.txt"],

0 commit comments

Comments
 (0)