Skip to content

Commit 392f230

Browse files
committed
remove fhconfparser and replace with configurator
1 parent 1056b96 commit 392f230

11 files changed

+128
-94
lines changed

README.md

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ the project license
3535
- [Configuration Example](#configuration-example)
3636
- [Example 1: pyproject.toml](#example-1-pyprojecttoml)
3737
- [Example 2: licensecheck.json](#example-2-licensecheckjson)
38-
- [Example 3: licensecheck.ini](#example-3-licensecheckini)
3938
- [Documentation](#documentation)
4039
- [Install With PIP](#install-with-pip)
4140
- [Language information](#language-information)
@@ -215,51 +214,63 @@ in the DOCS
215214

216215
## Configuration Example
217216

218-
Configuration files are parsed in the following order: `pyproject.toml`,
219-
`setup.cfg`, `licensecheck.toml`, `licensecheck.json`, `licensecheck.ini`,
220-
`~/licensecheck.toml`, `~/licensecheck.json`, `~/licensecheck.ini`
217+
Configuration files are parsed in the following order: `pyproject.toml`, `setup.cfg`,
218+
`licensecheck.toml`, `licensecheck.json`, `~/licensecheck.toml`, `~/licensecheck.json`,
221219

222220
- ⚠ All config files are parsed, however configuration defined in previous files takes precedent
223221

224-
Add optional path to requirements.txt as outlined in
225-
https://github.com/FHPythonUtils/LicenseCheck/issues/9#issuecomment-898878228
226-
for example: `licensecheck --using requirements:c:/path/to/reqs.txt;path/to/other/reqs.txt`
227222

228223
### Example 1: pyproject.toml
229224

230-
The following config is equivalent to `licensecheck -u 'requirements:requirements.txt;requirements_optional.txt' -f json`
231-
232225
```toml
226+
233227
[tool.licensecheck]
234-
using = "requirements:requirements.txt;requirements_optional.txt"
235-
format = "json"
228+
license = "mit" # Specify the project license explicitly
229+
format = "simple" # Output format (e.g., "json", "csv", etc.)
230+
requirements_paths = [] # List of filenames to read from
231+
groups = [] # List of selected groups
232+
extras = [] # List of selected extras
233+
file = "" # Output file (leave empty for stdout)
234+
ignore_packages = [] # Packages/dependencies to ignore
235+
fail_packages = [] # Packages/dependencies that cause failure
236+
ignore_licenses = [] # Licenses to ignore
237+
fail_licenses = [] # Licenses that cause failure
238+
only_licenses = [] # Allowed licenses (all others will fail)
239+
skip_dependencies = [] # Dependencies to skip (compatibility = True)
240+
hide_output_parameters = [] # Parameters to hide from output
241+
show_only_failing = false # Show only incompatible/failing packages
242+
pypi_api = "https://pypi.org" # Custom PyPI API endpoint
243+
zero = false # Return non-zero exit code for incompatible licenses (for CI/CD)
244+
236245
```
237246

238247
### Example 2: licensecheck.json
239248

240-
The following config is equivalent to `licensecheck -u 'requirements:requirements.txt;requirements_optional.txt' -f json`
241-
242249
```json
243250
{
244-
"tool": {
245-
"licensecheck": {
246-
"using": "requirements:requirements.txt;requirements_optional.txt",
247-
"format": "json"
248-
}
249-
}
251+
"tool": {
252+
"licensecheck": {
253+
"extras": [],
254+
"fail_licenses": [],
255+
"fail_packages": [],
256+
"file": "",
257+
"format": "simple",
258+
"groups": [],
259+
"hide_output_parameters": [],
260+
"ignore_licenses": [],
261+
"ignore_packages": [],
262+
"license": "mit",
263+
"only_licenses": [],
264+
"pypi_api": "https://pypi.org",
265+
"requirements_paths": [],
266+
"show_only_failing": false,
267+
"skip_dependencies": [],
268+
"zero": false
269+
}
270+
}
250271
}
251272
```
252273

253-
### Example 3: licensecheck.ini
254-
255-
The following config is equivalent to `licensecheck -u 'requirements:requirements.txt;requirements_optional.txt' -f json`
256-
257-
```ini
258-
[licensecheck]
259-
using = "requirements:requirements.txt;requirements_optional.txt"
260-
format = "json"
261-
```
262-
263274
## Documentation
264275

265276
A high-level overview of how the documentation is organized organized will help you know

licensecheck/cli.py

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from pathlib import Path
1010
from sys import exit as sysexit
1111
from sys import stdin, stdout
12-
13-
from fhconfparser import FHConfParser, SimpleConf
12+
from configurator import Config
13+
from configurator.node import ConfigNode
14+
from pathlib import Path
1415

1516
from licensecheck import checker, fmt, license_matrix, packageinfo, types
1617

@@ -129,26 +130,29 @@ def main(args: dict) -> int:
129130
"""
130131
exitCode = 0
131132

132-
configparser = FHConfParser()
133-
namespace = ["tool"]
134-
configparser.parseConfigList(
135-
[("pyproject.toml", "toml"), ("setup.cfg", "ini")]
136-
+ [
137-
(f"{directory}/licensecheck.{ext}", ext)
138-
for ext in ("toml", "json", "ini")
139-
for directory in [".", str(Path.home())]
140-
],
141-
namespace,
142-
namespace,
143-
)
144-
simpleConf = SimpleConf(configparser, "licensecheck", args)
133+
config: ConfigNode = Config()
134+
135+
config_files = [
136+
"~/licensecheck.json",
137+
"~/licensecheck.toml",
138+
"licensecheck.json",
139+
"licensecheck.toml",
140+
"setup.cfg",
141+
"pyproject.toml",
142+
]
143+
144+
for file in config_files:
145+
config += Config.from_path(file, optional=True)
146+
147+
scopedData: ConfigNode = config.get("tool", default={}).get("licensecheck", default=ConfigNode())
148+
scopedConfig = {**scopedData.data, **args}
145149

146150
# File
147-
requirements_paths = simpleConf.get("requirements_paths") or ["__stdin__"]
151+
requirements_paths = scopedConfig.get("requirements_paths") or ["__stdin__"]
148152
output_file = (
149153
stdout
150-
if simpleConf.get("file") is None
151-
else Path(simpleConf.get("file")).open("w", encoding="utf-8")
154+
if scopedConfig.get("file") in [None, ""]
155+
else Path(scopedConfig.get("file")).open("w", encoding="utf-8")
152156
)
153157

154158
# Get my license
@@ -158,14 +162,14 @@ def main(args: dict) -> int:
158162
this_license = license_matrix.licenseType(this_license_text)[0]
159163

160164
def getFromConfig(key: str) -> list[types.ucstr]:
161-
return list(map(types.ucstr, simpleConf.get(key, [])))
165+
return list(map(types.ucstr, scopedConfig.get(key, [])))
162166

163-
package_info_manager = packageinfo.PackageInfoManager(simpleConf.get("pypi_api"))
167+
package_info_manager = packageinfo.PackageInfoManager(scopedConfig.get("pypi_api"))
164168

165169
incompatible, depsWithLicenses = checker.check(
166170
requirements_paths=requirements_paths,
167-
groups=simpleConf.get("groups", []),
168-
extras=simpleConf.get("extras", []),
171+
groups=scopedConfig.get("groups", []),
172+
extras=scopedConfig.get("extras", []),
169173
this_license=this_license,
170174
package_info_manager=package_info_manager,
171175
ignore_packages=getFromConfig("ignore_packages"),
@@ -177,18 +181,20 @@ def getFromConfig(key: str) -> list[types.ucstr]:
177181
)
178182

179183
# Format the results
180-
hide_output_parameters = [types.ucstr(x) for x in simpleConf.get("hide_output_parameters", [])]
184+
hide_output_parameters = [
185+
types.ucstr(x) for x in scopedConfig.get("hide_output_parameters", [])
186+
]
181187
available_params = [param.name.upper() for param in fields(types.PackageInfo)]
182188
if not all(hop in available_params for hop in hide_output_parameters):
183189
msg = (
184190
f"Invalid parameter(s) in `hide_output_parameters`. "
185191
f"Valid parameters are: {', '.join(available_params)}"
186192
)
187193
raise ValueError(msg)
188-
if simpleConf.get("format", "simple") in fmt.formatMap:
194+
if scopedConfig.get("format", "simple") in fmt.formatMap:
189195
print(
190196
fmt.fmt(
191-
simpleConf.get("format", "simple"),
197+
scopedConfig.get("format", "simple"),
192198
this_license,
193199
sorted(depsWithLicenses),
194200
hide_output_parameters,
@@ -200,10 +206,10 @@ def getFromConfig(key: str) -> list[types.ucstr]:
200206
exitCode = 2
201207

202208
# Exit code of 1 if args.zero
203-
if simpleConf.get("zero", False) and incompatible:
209+
if scopedConfig.get("zero", False) and incompatible:
204210
exitCode = 1
205211

206212
# Cleanup + exit
207-
if simpleConf.get("file") is not None:
213+
if scopedConfig.get("file") not in [None, ""]:
208214
output_file.close()
209215
return exitCode

pyproject.toml

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ classifiers = [
2121
"Topic :: Utilities",
2222
]
2323
dependencies = [
24-
"appdirs>=1.4.4",
25-
"fhconfparser>=2024.1",
26-
"license-expression>=30.4.1",
27-
"loguru>=0.7.3",
28-
"markdown>=3.7",
29-
"packaging>=24.2",
30-
"requests>=2.32.3",
31-
"requests-cache>=1.2.1",
32-
"requirements-parser>=0.11.0",
33-
"rich>=13.9.4",
34-
"tomli>=2.2.1",
35-
"uv>=0.6.8",
24+
"appdirs>=1.4.4",
25+
"configurator>=3.2.0",
26+
"license-expression>=30.4.1",
27+
"loguru>=0.7.3",
28+
"markdown>=3.7",
29+
"packaging>=24.2",
30+
"requests>=2.32.3",
31+
"requests-cache>=1.2.1",
32+
"requirements-parser>=0.11.0",
33+
"rich>=13.9.4",
34+
"tomli>=2.2.1",
35+
"uv>=0.6.8",
3636
]
3737

3838
[project.urls]
@@ -45,13 +45,13 @@ licensecheck = "licensecheck:cli"
4545

4646
[dependency-groups]
4747
dev = [
48-
"coverage>=7.6.12",
49-
"handsdown>=2.1.0",
50-
"pyright>=1.1.396",
51-
"pytest>=8.3.5",
52-
"pytest-loguru>=0.4.0",
53-
"ruff>=0.11.0",
54-
"safety>=3.3.1",
48+
"coverage>=7.6.12",
49+
"handsdown>=2.1.0",
50+
"pyright>=1.1.396",
51+
"pytest>=8.3.5",
52+
"pytest-loguru>=0.4.0",
53+
"ruff>=0.11.0",
54+
"safety>=3.3.1",
5555
]
5656

5757
[tool.ruff]
@@ -62,13 +62,13 @@ target-version = "py38"
6262
[tool.ruff.lint]
6363
select = ["ALL"]
6464
ignore = [
65-
"COM812", # enforce trailing comma
66-
"D2", # pydocstyle formatting
65+
"COM812", # enforce trailing comma
66+
"D2", # pydocstyle formatting
6767
"ISC001",
68-
"N", # pep8 naming
68+
"N", # pep8 naming
6969
"PLR09", # pylint refactor too many
70-
"TCH", # type check blocks
71-
"W191" # ignore this to allow tabs
70+
"TCH", # type check blocks
71+
"W191", # ignore this to allow tabs
7272
]
7373
fixable = ["ALL"]
7474

@@ -88,15 +88,32 @@ venvPath = "."
8888
venv = ".venv"
8989

9090
[tool.licensecheck]
91+
license = "mit" # Specify the project license explicitly
92+
format = "simple" # Output format (e.g., "json", "csv", etc.)
93+
requirements_paths = [] # List of filenames to read from
94+
groups = [] # List of selected groups
95+
extras = [] # List of selected extras
96+
file = "" # Output file (leave empty for stdout)
97+
ignore_packages = [] # Packages/dependencies to ignore
98+
fail_packages = [] # Packages/dependencies that cause failure
99+
ignore_licenses = [] # Licenses to ignore
100+
fail_licenses = [] # Licenses that cause failure
101+
only_licenses = [] # Allowed licenses (all others will fail)
102+
skip_dependencies = [] # Dependencies to skip (compatibility = True)
103+
hide_output_parameters = [] # Parameters to hide from output
104+
show_only_failing = false # Show only incompatible/failing packages
105+
pypi_api = "https://pypi.org" # Custom PyPI API endpoint
106+
zero = false # Return non-zero exit code for incompatible licenses (for CI/CD)
107+
91108

92109
[tool.tox]
93110
legacy_tox_ini = """
94111
[tox]
95112
env_list =
96-
py311
113+
py313
114+
py312
97115
py310
98116
py39
99-
py38
100117
101118
[testenv]
102119
deps = pytest

tests/data/test_issue_112.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_issue_112_expected.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_main_tc1.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_main_tc1_expected.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_main_tc3.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_main_tc3_expected.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
│ ✔ │ certifi │ MOZILLA PUBLIC LICENSE 2.0 _MPL 2.0_ │
2121
│ ✔ │ charset-normalizer │ MIT LICENSE │
2222
│ ✔ │ colorama │ BSD LICENSE │
23-
│ ✔ │ fhconfparser │ MIT LICENSE │
23+
│ ✔ │ configurator │ MIT LICENSE │
2424
│ ✔ │ idna │ BSD LICENSE │
2525
│ ✔ │ license-expression │ APACHE-2.0 │
2626
│ ✔ │ loguru │ MIT LICENSE │

tests/data/test_main_tc4.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@
6363
"errorCode": 0
6464
},
6565
{
66-
"name": "fhconfparser",
67-
"homePage": "https://github.com/FHPythonUtils/FHConfParser",
68-
"author": "FredHappyface",
66+
"name": "configurator",
67+
"homePage": "https://github.com/Simplistix/configurator",
68+
"author": "Chris Withers",
6969
"license": "MIT LICENSE",
7070
"licenseCompat": true,
7171
"errorCode": 0

tests/data/test_main_tc4_expected.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@
6363
"errorCode": 0
6464
},
6565
{
66-
"name": "fhconfparser",
67-
"homePage": "https://github.com/FHPythonUtils/FHConfParser",
68-
"author": "FredHappyface",
66+
"name": "configurator",
67+
"homePage": "https://github.com/Simplistix/configurator",
68+
"author": "Chris Withers",
6969
"license": "MIT LICENSE",
7070
"licenseCompat": true,
7171
"errorCode": 0

0 commit comments

Comments
 (0)