Skip to content

Commit ccc674b

Browse files
authored
Merge pull request #4 from ProperDocs/fix
Update CI, update projects, delete defunct projects
2 parents 4b7ac85 + 90cbfd9 commit ccc674b

File tree

3 files changed

+110
-57
lines changed

3 files changed

+110
-57
lines changed

check_projects.py

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,58 @@
44
import sys
55
import tempfile
66
import textwrap
7+
from collections.abc import Collection, Mapping, Sequence
8+
from concurrent.futures import Future
79
from pathlib import Path
10+
from typing import Any, Literal, Required, TypeAlias, TypedDict, cast
811

912
import yaml
1013

14+
EntrypointType: TypeAlias = Literal[
15+
"properdocs_theme", "mkdocs_theme", "properdocs_plugin", "mkdocs_plugin", "markdown_extension"
16+
]
1117

12-
def _get_as_list(mapping, key):
13-
names = mapping.get(key, ())
18+
19+
class Project(TypedDict, total=False):
20+
name: Required[str]
21+
category: Required[str]
22+
labels: Collection[str]
23+
properdocs_theme: str | Collection[str]
24+
mkdocs_theme: str | Collection[str]
25+
properdocs_plugin: str | Collection[str]
26+
mkdocs_plugin: str | Collection[str]
27+
markdown_extension: str | Collection[str]
28+
github_id: str
29+
pypi_id: str
30+
31+
32+
def _get_as_list(mapping: Project, key: EntrypointType) -> Collection[str]:
33+
names: str | Collection[str] = mapping.get(key, ())
1434
if isinstance(names, str):
1535
names = (names,)
1636
return names
1737

1838

19-
_kind_to_label = {
20-
"mkdocs_plugin": "plugin",
21-
"mkdocs_theme": "theme",
22-
"markdown_extension": "markdown",
39+
_kinds_to_label: Mapping[Collection[EntrypointType], str] = {
40+
("properdocs_plugin", "mkdocs_plugin"): "plugin",
41+
("properdocs_theme", "mkdocs_theme"): "theme",
42+
("markdown_extension",): "markdown",
2343
}
2444

25-
config = yaml.safe_load(Path("projects.yaml").read_text())
45+
config: Mapping[str, Any] = yaml.safe_load(Path("projects.yaml").read_text(encoding="utf-8"))
2646

27-
projects = config["projects"]
28-
all_labels = dict.fromkeys(label["label"] for label in config["labels"])
29-
all_categories = dict.fromkeys(category["category"] for category in config["categories"])
47+
projects: Sequence[Project] = config["projects"]
48+
all_labels: Collection[str] = dict.fromkeys(label["label"] for label in config["labels"])
49+
all_categories: Collection[str] = dict.fromkeys(category["category"] for category in config["categories"])
3050

3151

32-
def check_install_project(project, install_name, errors=None):
52+
def check_install_project(project: Project, install_name: str, errors: list[str] | None = None) -> list[str]:
3353
if errors is None:
3454
errors = []
3555

3656
with tempfile.TemporaryDirectory(prefix="best-of-mkdocs-") as directory:
3757
try:
38-
result = subprocess.run(
58+
subprocess.run(
3959
["pip", "install", "-U", "--ignore-requires-python", "--no-deps", "--target", directory, install_name],
4060
stdin=subprocess.DEVNULL,
4161
capture_output=True,
@@ -45,15 +65,17 @@ def check_install_project(project, install_name, errors=None):
4565
)
4666
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
4767
errors.append(f"Failed {e.cmd}:\n{e.stderr}")
48-
return
68+
return errors
4969

50-
entry_points = configparser.ConfigParser()
70+
entry_points_parser = configparser.ConfigParser()
5171
try:
52-
[entry_points_file] = Path(directory).glob(f"*.dist-info/entry_points.txt")
53-
entry_points.read_string(entry_points_file.read_text())
72+
[entry_points_file] = Path(directory).glob("*.dist-info/entry_points.txt")
73+
entry_points_parser.read_string(entry_points_file.read_text())
5474
except ValueError:
5575
pass
56-
entry_points = {sect: list(entry_points[sect]) for sect in entry_points.sections()}
76+
entry_points: dict[str, list[str]] = {
77+
sect: list(entry_points_parser[sect]) for sect in entry_points_parser.sections()
78+
}
5779

5880
for item in _get_as_list(project, "mkdocs_plugin"):
5981
if item not in entry_points.get("mkdocs.plugins", ()):
@@ -68,7 +90,7 @@ def check_install_project(project, install_name, errors=None):
6890
base_path = item.replace(".", "/")
6991
for pattern in base_path + ".py", base_path + "/__init__.py":
7092
path = Path(directory, pattern)
71-
if path.is_file() and "makeExtension" in path.read_text():
93+
if path.is_file() and "makeExtension" in path.read_text(encoding="utf-8"):
7294
break
7395
else:
7496
errors.append(
@@ -83,12 +105,12 @@ def check_install_project(project, install_name, errors=None):
83105
pool = concurrent.futures.ThreadPoolExecutor(4)
84106

85107
# Tracks shadowing: projects earlier in the list take precedence.
86-
available = {k: {} for k in _kind_to_label}
108+
available: dict[EntrypointType, dict[str, str]] = {k: {} for keys in _kinds_to_label for k in keys}
87109

88-
futures = []
110+
futures: list[tuple[str, Future[list[str]]]] = []
89111

90112
for project in projects:
91-
errors = []
113+
errors: list[str] = []
92114

93115
name = project.get("name")
94116
if not name:
@@ -104,30 +126,34 @@ def check_install_project(project, install_name, errors=None):
104126
if label not in all_labels:
105127
errors.append(f"Unknown label: {label!r} - should be one of: {', '.join(all_labels)}")
106128

107-
for kind, label in _kind_to_label.items():
108-
items = _get_as_list(project, kind)
109-
129+
for kinds, label in _kinds_to_label.items():
110130
if label == "plugin" and "theme" in labels and "plugin" not in labels:
111131
pass
112-
elif (label in labels) != bool(items):
113-
errors.append(f"'{label}' label should be present if and only if '{kind}:' is present")
114-
115-
for item in items:
116-
already_available = available[kind].get(item) or (
117-
kind == "mkdocs_plugin" and available[kind].get(item.split("/")[-1])
118-
)
119-
if already_available:
120-
if kind not in project.get("shadowed", ()):
121-
errors.append(
122-
f"{kind} '{item.split('/')[-1]}' is present in both project '{already_available}' and '{name}'.\n"
123-
f"If that is expected, the later of the two projects will be ignored, "
124-
f"and to indicate this, it should contain 'shadowed: [{kind}]'"
125-
)
126-
else:
127-
available[kind][item] = name
128-
129-
install_name = None
130-
if any(key in project for key in _kind_to_label):
132+
elif (label in labels) != any(bool(project.get(kind)) for kind in kinds):
133+
errors.append(f"'{label}' label should be present if and only if '{kinds}:' is present")
134+
135+
for kind in kinds:
136+
items = _get_as_list(project, kind)
137+
138+
for item in items:
139+
already_available: str | None = None
140+
for subkind in (kind, cast("EntrypointType", kind.replace("mkdocs", "properdocs"))):
141+
if already_available is None:
142+
already_available = available[subkind].get(item)
143+
if already_available is None and "plugin" in kind:
144+
already_available = available[subkind].get(item.split("/")[-1])
145+
146+
if already_available:
147+
if kind not in project.get("shadowed", ()):
148+
errors.append(
149+
f"{kind} '{item.split('/')[-1]}' is present in both project '{already_available}' and '{name}'.\n"
150+
f"If that is expected, the later of the two projects will be ignored, "
151+
f"and to indicate this, it should contain 'shadowed: [{kind}]'"
152+
)
153+
available[kind].setdefault(item, name)
154+
155+
install_name: str | None = None
156+
if any(key in project for keys in _kinds_to_label for key in keys):
131157
if "pypi_id" in project:
132158
install_name = project["pypi_id"]
133159
if "_" in install_name:
@@ -138,10 +164,11 @@ def check_install_project(project, install_name, errors=None):
138164
else:
139165
errors.append("Missing 'pypi_id:'")
140166

167+
fut: Future[list[str]]
141168
if install_name:
142169
fut = pool.submit(check_install_project, project, install_name, errors)
143170
else:
144-
fut = concurrent.futures.Future()
171+
fut = Future()
145172
fut.set_result(errors)
146173
futures.append((name, fut))
147174

projects.yaml

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ projects:
7676
category: theming
7777
- name: Material for MkDocs
7878
mkdocs_theme: material
79-
mkdocs_plugin: [material/blog, material/group, material/offline, material/search, material/social, material/tags]
79+
mkdocs_plugin: [material/blog, material/group, material/info, material/meta, material/offline, material/optimize, material/privacy, material/projects, material/search, material/social, material/tags, material/typeset]
8080
extra_dependencies:
8181
plugins.social: mkdocs-material[imaging]
82+
plugins.optimize: mkdocs-material[imaging]
8283
github_id: squidfunk/mkdocs-material
8384
pypi_id: mkdocs-material
8485
labels: [theme, plugin]
@@ -187,7 +188,7 @@ projects:
187188
labels: [theme]
188189
category: theming
189190
- name: Zettelkasten
190-
mkdocs_theme: zettelkasten-solarized-light
191+
mkdocs_theme: zettelkasten
191192
mkdocs_plugin: [zettelkasten]
192193
github_id: buvis/mkdocs-zettelkasten
193194
pypi_id: mkdocs-zettelkasten
@@ -1511,11 +1512,6 @@ projects:
15111512
pypi_id: mkdocs-categories-plugin
15121513
labels: [plugin]
15131514
category: nav-pages
1514-
- name: filename-title
1515-
mkdocs_plugin: filename_title
1516-
github_id: mipro98/mkdocs-filename-title-plugin
1517-
labels: [plugin]
1518-
category: nav-pages
15191515
- name: mkdocs-title-casing-plugin
15201516
mkdocs_plugin: title-casing
15211517
github_id: mattchristopher314/mkdocs-title-casing-plugin
@@ -1712,12 +1708,6 @@ projects:
17121708
pypi_id: mkdocs-print-site-plugin
17131709
labels: [plugin]
17141710
category: site-conversion
1715-
- name: mk2pdf-export
1716-
mkdocs_plugin: mk2pdf-export
1717-
github_id: HaoLiuHust/mkdocs-mk2pdf-plugin
1718-
pypi_id: mkdocs-mk2pdf-plugin
1719-
labels: [plugin]
1720-
category: site-conversion
17211711
- name: pdf-with-js
17221712
mkdocs_plugin: pdf-with-js
17231713
github_id: smaxtec/mkdocs-pdf-with-js-plugin

ruff.toml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
line-length = 120
2+
3+
[lint]
4+
preview = true
5+
select = [
6+
"YTT", "ASYNC", "FBT", "C4", "DTZ", "T10", "EXE", "FA", "ISC", "PIE", "RSE", "I", "E", "W", "F", "UP",
7+
"S201", "S202", "S303", "S304", "S305", "S306", "S506", "S602", "S604", "S605", "S612", "S701", "S704",
8+
"B002", "B003", "B004", "B005", "B007", "B008", "B009", "B010", "B011", "B012", "B013", "B014", "B015", "B016", "B017", "B018", "B019", "B020", "B021", "B022", "B023", "B025", "B026", "B029", "B030", "B031", "B032", "B033", "B034", "B035", "B039", "B043", "B901", "B905", "B909", "B911", "B912",
9+
"COM818",
10+
"LOG001", "LOG004", "LOG007", "LOG009", "LOG014", "LOG015",
11+
"G001", "G002", "G003", "G010", "G101", "G201", "G202",
12+
"PYI001", "PYI002", "PYI003", "PYI004", "PYI005", "PYI006", "PYI007", "PYI008", "PYI009", "PYI010", "PYI011", "PYI012", "PYI013", "PYI014", "PYI015", "PYI016", "PYI017", "PYI018", "PYI019", "PYI020", "PYI021", "PYI024", "PYI025", "PYI026", "PYI029", "PYI030", "PYI032", "PYI033", "PYI034", "PYI035", "PYI036", "PYI041", "PYI042", "PYI043", "PYI044", "PYI045", "PYI046", "PYI047", "PYI048", "PYI049", "PYI050", "PYI051", "PYI052", "PYI053", "PYI054", "PYI055", "PYI056", "PYI057", "PYI058", "PYI059", "PYI061", "PYI062", "PYI063", "PYI064", "PYI066",
13+
"PT001", "PT002", "PT003", "PT006", "PT007", "PT008", "PT009", "PT010", "PT013", "PT014", "PT015", "PT016", "PT018", "PT019", "PT020", "PT021", "PT022", "PT023", "PT024", "PT025", "PT026", "PT027", "PT029",
14+
"Q004",
15+
"RET502", "RET503", "RET504",
16+
"SIM101", "SIM103", "SIM105", "SIM107", "SIM109", "SIM110", "SIM113", "SIM114", "SIM118", "SIM201", "SIM202", "SIM208", "SIM210", "SIM211", "SIM212", "SIM220", "SIM221", "SIM222", "SIM223", "SIM300", "SIM401", "SIM905", "SIM910", "SIM911",
17+
"TD004", "TD005", "TD006", "TD007",
18+
"TC001", "TC002", "TC003", "TC004", "TC005", "TC006", "TC007", "TC008", "TC010",
19+
"PTH124", "PTH201", "PTH210",
20+
"FLY002",
21+
"N803", "N804", "N805", "N806", "N807", "N815", "N816", "N999",
22+
"PERF101", "PERF102", "PERF402", "PERF403",
23+
"PGH003", "PGH004", "PGH005",
24+
"PLC0105", "PLC0131", "PLC0132", "PLC0205", "PLC0206", "PLC0207", "PLC0208", "PLC0414", "PLC2401", "PLC2403", "PLC2701", "PLC2801", "PLC3002",
25+
"PLE0100", "PLE0101", "PLE0115", "PLE0116", "PLE0117", "PLE0118", "PLE0237", "PLE0241", "PLE0302", "PLE0303", "PLE0304", "PLE0305", "PLE0307", "PLE0308", "PLE0309", "PLE0604", "PLE0605", "PLE0643", "PLE0704", "PLE1132", "PLE1141", "PLE1142", "PLE1205", "PLE1206", "PLE1300", "PLE1307", "PLE1310", "PLE1507", "PLE1519", "PLE1520", "PLE1700", "PLE2502", "PLE2510", "PLE2512", "PLE2513", "PLE2514", "PLE2515", "PLE4703",
26+
"PLR0124", "PLR0133", "PLR0202", "PLR0203", "PLR0206", "PLR0402", "PLR1704", "PLR1708", "PLR1712", "PLR1716", "PLR1722", "PLR1733", "PLR1736", "PLR2044", "PLR6201", "PLR6301",
27+
"PLW0108", "PLW0120", "PLW0127", "PLW0128", "PLW0129", "PLW0131", "PLW0133", "PLW0177", "PLW0211", "PLW0244", "PLW0245", "PLW0406", "PLW0602", "PLW0603", "PLW0604", "PLW0642", "PLW0711", "PLW1501", "PLW1507", "PLW1508", "PLW1514", "PLW1641", "PLW2101", "PLW2901", "PLW3201",
28+
"FURB101", "FURB103", "FURB105", "FURB110", "FURB113", "FURB116", "FURB118", "FURB122", "FURB129", "FURB131", "FURB132", "FURB136", "FURB142", "FURB145", "FURB148", "FURB152", "FURB154", "FURB156", "FURB157", "FURB161", "FURB162", "FURB163", "FURB164", "FURB166", "FURB167", "FURB168", "FURB169", "FURB171", "FURB177", "FURB180", "FURB181", "FURB188", "FURB192",
29+
"RUF001", "RUF002", "RUF003", "RUF005", "RUF006", "RUF007", "RUF008", "RUF009", "RUF010", "RUF012", "RUF013", "RUF015", "RUF016", "RUF017", "RUF018", "RUF019", "RUF020", "RUF021", "RUF022", "RUF023", "RUF024", "RUF026", "RUF028", "RUF029", "RUF030", "RUF031", "RUF032", "RUF033", "RUF034", "RUF036", "RUF037", "RUF038", "RUF039", "RUF040", "RUF041", "RUF043", "RUF045", "RUF046", "RUF047", "RUF048", "RUF049", "RUF051", "RUF052", "RUF053", "RUF054", "RUF055", "RUF056", "RUF057", "RUF058", "RUF059", "RUF060", "RUF061", "RUF063", "RUF064", "RUF065", "RUF066", "RUF068", "RUF069", "RUF070", "RUF071", "RUF100", "RUF101", "RUF102", "RUF103", "RUF104", "RUF200",
30+
"TRY002", "TRY004", "TRY201", "TRY203", "TRY300", "TRY301", "TRY400", "TRY401",
31+
]
32+
ignore = ["E501", "E731"]
33+
[lint.flake8-comprehensions]
34+
allow-dict-calls-with-keyword-arguments = true
35+
[lint.flake8-type-checking]
36+
exempt-modules = ["typing", "collections.abc"]

0 commit comments

Comments
 (0)