Skip to content

Commit b7c93c5

Browse files
committed
fmt; fix #132
1 parent 2e5ce05 commit b7c93c5

6 files changed

Lines changed: 77 additions & 42 deletions

File tree

licensecheck/io/cli.py

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import argparse
66
from dataclasses import fields
7+
from enum import Enum
78
from pathlib import Path
89
from sys import exit as sysexit
910
from sys import stdin, stdout
@@ -20,6 +21,12 @@
2021
stdout.reconfigure(encoding="utf-8") # type: ignore[general-type-issues]
2122

2223

24+
class ExitCode(Enum):
25+
SUCCESS = 0
26+
INCOMPATIBLE_LICENSE = 1
27+
NO_PACKAGES = 3
28+
29+
2330
def cli() -> None: # pragma: no cover
2431
"""Cli entry point."""
2532
parser = argparse.ArgumentParser(description=__doc__, argument_default=argparse.SUPPRESS)
@@ -84,7 +91,7 @@ def cli() -> None: # pragma: no cover
8491
)
8592
parser.add_argument(
8693
"--skip-dependencies",
87-
help="set of packages/dependencies to skip (this sets the 'compatibility' to True)",
94+
help="set of packages/dependencies to skip resolving",
8895
nargs="+",
8996
)
9097
parser.add_argument(
@@ -109,9 +116,6 @@ def cli() -> None: # pragma: no cover
109116
)
110117
args = vars(parser.parse_args())
111118

112-
if args.get("format", "simple") not in fmt.FMT:
113-
args["format"] = "simple"
114-
115119
stdin_path = Path("__stdin__")
116120
if not args.get("requirements_paths"):
117121
if stdin.isatty():
@@ -139,12 +143,12 @@ def cli() -> None: # pragma: no cover
139143
ec = main(licensecheckConf)
140144
stdin_path.unlink(missing_ok=True)
141145

142-
sysexit(ec)
146+
sysexit(ec.value)
143147

144148

145-
def main(licensecheckConf: LC_Config) -> int:
149+
def main(licensecheckConf: LC_Config) -> ExitCode:
146150
"""Test entry point."""
147-
exitCode = 0
151+
exitCode = ExitCode.SUCCESS
148152

149153
# File
150154
requirements_paths = licensecheckConf.requirements_paths or {"__stdin__"}
@@ -185,23 +189,23 @@ def main(licensecheckConf: LC_Config) -> int:
185189
)
186190
raise ValueError(msg)
187191

188-
if licensecheckConf.format in fmt.FMT:
189-
print(
190-
fmt.fmt(
191-
licensecheckConf.format,
192-
this_license,
193-
sorted(depsWithLicenses),
194-
hide_output_parameters,
195-
show_only_failing=licensecheckConf.show_only_failing,
196-
),
197-
file=output_file,
198-
)
199-
else:
200-
exitCode = 2
192+
print(
193+
fmt.fmt(
194+
licensecheckConf.format,
195+
this_license,
196+
sorted(depsWithLicenses),
197+
hide_output_parameters,
198+
show_only_failing=licensecheckConf.show_only_failing,
199+
),
200+
file=output_file,
201+
)
201202

202203
# Exit code of 1 if args.zero
203-
if licensecheckConf.zero and incompatible:
204-
exitCode = 1
204+
if licensecheckConf.zero:
205+
if len(depsWithLicenses) == 0:
206+
exitCode = ExitCode.NO_PACKAGES
207+
if incompatible:
208+
exitCode = ExitCode.INCOMPATIBLE_LICENSE
205209

206210
# Cleanup + exit
207211
if licensecheckConf.file != "":

licensecheck/io/fmt.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
from __future__ import annotations
4141

4242
import csv
43-
from enum import StrEnum, auto
4443
import json
4544
import re
4645
from collections import OrderedDict
46+
from enum import StrEnum, auto
4747
from importlib.metadata import PackageNotFoundError, version
4848
from io import StringIO
4949
from pathlib import Path
@@ -335,6 +335,7 @@ class FMT(StrEnum):
335335
ansi = auto()
336336
simple = auto()
337337

338+
338339
formatMap = {
339340
FMT.json: raw,
340341
FMT.markdown: markdown,

licensecheck/models/config.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from __future__ import annotations
22

33
from dataclasses import field
4+
from typing import Any, Literal
5+
6+
from pydantic import field_validator
47

5-
from licensecheck.models.defaultonnone import DefaultOnNoneModel
68
from licensecheck.io.fmt import FMT
9+
from licensecheck.models.defaultonnone import DefaultOnNoneModel
10+
711

812
class LC_Config(DefaultOnNoneModel):
913
"""LC_Config type."""
@@ -25,3 +29,10 @@ class LC_Config(DefaultOnNoneModel):
2529
only_licenses: set[str] = field(default_factory=set)
2630
skip_dependencies: set[str] = field(default_factory=set)
2731
hide_output_parameters: set[str] = field(default_factory=set)
32+
33+
@field_validator("format", mode="before")
34+
@classmethod
35+
def normalize_format(cls, value: Any) -> Any | Literal[FMT.simple]:
36+
if value not in FMT:
37+
return FMT.simple
38+
return value

licensecheck/packageinforesolver.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
from boolean.boolean import Expression
65
import configparser
76
import contextlib
87
import re
@@ -16,6 +15,7 @@
1615
import license_expression
1716
import requests
1817
import tomli
18+
from boolean.boolean import Expression
1919
from depgather.parse import gather
2020
from license_expression import Licensing
2121
from packaging.requirements import Requirement
@@ -115,15 +115,14 @@ def normalize_license(lice: str) -> str:
115115
licensing = Licensing()
116116
parsed = None
117117
with contextlib.suppress(license_expression.ExpressionParseError):
118-
parsed = licensing.parse(
119-
re.sub(r"[^a-zA-Z0-9_.:\- ]", "_", lice.splitlines()[0])
120-
)
118+
parsed = licensing.parse(re.sub(r"[^a-zA-Z0-9_.:\- ]", "_", lice.splitlines()[0]))
121119
if parsed is None:
122120
return lice
123121

124122
tokens: list[Expression] = sorted(parsed.literals)
125123
return str(JOINS.join(getattr(x, "key", str(x)) for x in tokens))
126124

125+
127126
class LocalPackageInfo:
128127
"""Handles retrieval of package info from local installation."""
129128

tests/io/test_cli_main.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import pytest
55

6-
from licensecheck.io.cli import main
6+
from licensecheck.io.cli import ExitCode, main
77
from licensecheck.models.config import LC_Config
88

99

@@ -29,6 +29,28 @@ def config() -> LC_Config:
2929
)
3030

3131

32+
@pytest.fixture
33+
def config_invalid_fmt() -> LC_Config:
34+
return LC_Config(
35+
requirements_paths={"requirements.txt"},
36+
file=None,
37+
license="MIT",
38+
pypi_api=None,
39+
groups=set(),
40+
extras=set(),
41+
ignore_packages=set(),
42+
fail_packages=set(),
43+
ignore_licenses=set(),
44+
fail_licenses=set(),
45+
only_licenses=set(),
46+
skip_dependencies=set(),
47+
hide_output_parameters=set(),
48+
format="invalid_format",
49+
show_only_failing=False,
50+
zero=False,
51+
)
52+
53+
3254
def test_main_success(
3355
config: LC_Config,
3456
monkeypatch,
@@ -48,14 +70,13 @@ def test_main_success(
4870
lambda *_args, **_kwargs: "output",
4971
)
5072

51-
assert main(config) == 0
73+
assert main(config) == ExitCode.SUCCESS
5274

5375

5476
def test_main_invalid_format(
55-
config: LC_Config,
77+
config_invalid_fmt: LC_Config,
5678
monkeypatch,
5779
) -> None:
58-
config.format = "does-not-exist"
5980

6081
monkeypatch.setattr(
6182
"licensecheck.io.cli.checker.check",
@@ -67,16 +88,16 @@ def test_main_invalid_format(
6788
{},
6889
)
6990

70-
assert main(config) == 2
91+
assert main(config_invalid_fmt) == ExitCode.SUCCESS
7192

7293

7394
@pytest.mark.parametrize(
7495
("zero", "incompatible", "expected"),
7596
[
76-
(False, False, 0),
77-
(False, True, 0),
78-
(True, False, 0),
79-
(True, True, 1),
97+
(False, False, ExitCode.SUCCESS),
98+
(False, True, ExitCode.SUCCESS),
99+
(True, False, ExitCode.NO_PACKAGES),
100+
(True, True, ExitCode.INCOMPATIBLE_LICENSE),
80101
],
81102
)
82103
def test_main_exit_code_zero_mode(
@@ -155,7 +176,7 @@ def test_main_valid_hidden_parameters(
155176
lambda *_args, **_kwargs: "",
156177
)
157178

158-
assert main(config) == 0
179+
assert main(config) == ExitCode.SUCCESS
159180

160181

161182
def test_main_passes_args_to_checker(
@@ -214,5 +235,5 @@ def test_main_closes_output_file(
214235
lambda *_args, **_kwargs: "hello",
215236
)
216237

217-
assert main(config) == 0
238+
assert main(config) == ExitCode.SUCCESS
218239
assert output.read_text() == "hello\n"

tests/models/test_config.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import tomli
12

23
from licensecheck.io.fmt import FMT
34
from licensecheck.models.config import LC_Config
4-
import tomli
5+
56

67
def test_no_config() -> None:
78
LC_Config.model_validate({})
89

910

10-
1111
def test_basic_config() -> None:
1212
raw_conf = tomli.loads("""
1313
@@ -36,7 +36,6 @@ def test_basic_config() -> None:
3636
assert conf.pypi_api == "https://pypi.org"
3737

3838

39-
4039
def test_basic_config2() -> None:
4140
raw_conf = tomli.loads("""
4241

0 commit comments

Comments
 (0)