Skip to content

Commit cca6daf

Browse files
authored
add: ライセンス情報JSONをバリデーション (#1602)
1 parent 727e511 commit cca6daf

File tree

1 file changed

+47
-23
lines changed

1 file changed

+47
-23
lines changed

tools/generate_licenses.py

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
import subprocess
33
import sys
44
import urllib.request
5+
from dataclasses import dataclass
56
from pathlib import Path
67
from typing import Literal, assert_never
78

9+
from pydantic import TypeAdapter
10+
811

912
class LicenseError(Exception):
1013
# License違反があった場合、このエラーを出します。
@@ -44,9 +47,33 @@ def get_license_text(text_url: str) -> str:
4447

4548

4649
def generate_licenses() -> list[License]:
47-
# pip
50+
raw_licenses = acquire_licenses_of_pip_managed_libraries()
51+
licenses = update_licenses(raw_licenses)
52+
validate_license_compliance(licenses)
53+
add_licenses_manually(licenses)
54+
55+
return licenses
56+
57+
58+
@dataclass
59+
class PipLicense:
60+
"""`pip-license` により得られる依存ライブラリの情報"""
61+
62+
License: str
63+
Name: str
64+
URL: str
65+
Version: str
66+
LicenseText: str
67+
68+
69+
_pip_licenses_adapter = TypeAdapter(list[PipLicense])
70+
71+
72+
def acquire_licenses_of_pip_managed_libraries() -> list[PipLicense]:
73+
"""Pipで管理されている依存ライブラリのライセンス情報を取得する。"""
74+
# ライセンス一覧を取得する
4875
try:
49-
pip_licenses_output = subprocess.run(
76+
pip_licenses_json = subprocess.run(
5077
[
5178
sys.executable,
5279
"-m",
@@ -62,16 +89,13 @@ def generate_licenses() -> list[License]:
6289
).stdout.decode()
6390
except subprocess.CalledProcessError as e:
6491
raise Exception(f"command output:\n{e.stderr and e.stderr.decode()}") from e
65-
66-
licenses_json = json.loads(pip_licenses_output)
67-
licenses = generate_licenses_from_licenses_json(licenses_json)
68-
validate_license_compliance(licenses)
69-
add_licenses_manually(licenses)
70-
92+
# ライセンス情報の形式をチェックする
93+
licenses = _pip_licenses_adapter.validate_json(pip_licenses_json)
7194
return licenses
7295

7396

74-
def generate_licenses_from_licenses_json(licenses_json: dict) -> list[License]:
97+
def update_licenses(raw_licenses: list[PipLicense]) -> list[License]:
98+
"""pip から取得したライセンス情報を更新する。"""
7599
package_to_license_url = {
76100
"distlib": "https://bitbucket.org/pypa/distlib/raw/7d93712134b28401407da27382f2b6236c87623a/LICENSE.txt",
77101
"future": "https://raw.githubusercontent.com/PythonCharmers/python-future/master/LICENSE.txt",
@@ -85,37 +109,37 @@ def generate_licenses_from_licenses_json(licenses_json: dict) -> list[License]:
85109
"webencodings": "https://raw.githubusercontent.com/gsnedders/python-webencodings/fa2cb5d75ab41e63ace691bc0825d3432ba7d694/LICENSE",
86110
}
87111

88-
licenses = []
112+
updated_licenses = []
89113

90-
for license_json in licenses_json:
91-
package_name: str = license_json["Name"].lower()
114+
for raw_license in raw_licenses:
115+
package_name = raw_license.Name.lower()
92116

93-
if license_json["LicenseText"] == "UNKNOWN":
94-
if package_name == "core" and license_json["Version"] == "0.0.0":
117+
# ライセンス文が pip から取得できていない場合、pip 外から補う
118+
if raw_license.LicenseText == "UNKNOWN":
119+
if package_name == "core" and raw_license.Version == "0.0.0":
95120
continue
96121
if package_name not in package_to_license_url:
97122
# ライセンスがpypiに無い
98123
raise Exception(f"No License info provided for {package_name}")
99-
# ライセンス文を pip 外で取得されたもので上書きする
100124
text_url = package_to_license_url[package_name]
101-
license_json["LicenseText"] = get_license_text(text_url)
125+
raw_license.LicenseText = get_license_text(text_url)
102126

103127
# soxr
104128
if package_name == "soxr":
105129
text_url = "https://raw.githubusercontent.com/dofuuz/python-soxr/v0.3.6/LICENSE.txt"
106-
license_json["LicenseText"] = get_license_text(text_url)
130+
raw_license.LicenseText = get_license_text(text_url)
107131

108-
licenses.append(
132+
updated_licenses.append(
109133
License(
110-
package_name=license_json["Name"],
111-
package_version=license_json["Version"],
112-
license_name=license_json["License"],
113-
license_text=license_json["LicenseText"],
134+
package_name=raw_license.Name,
135+
package_version=raw_license.Version,
136+
license_name=raw_license.License,
137+
license_text=raw_license.LicenseText,
114138
license_text_type="raw",
115139
)
116140
)
117141

118-
return licenses
142+
return updated_licenses
119143

120144

121145
def validate_license_compliance(licenses: list[License]) -> None:

0 commit comments

Comments
 (0)