Skip to content

Commit d690b2d

Browse files
authored
[update_lib] todo subcommand (#6823)
* [update_lib] todo * better CI comment
1 parent 22974cf commit d690b2d

File tree

6 files changed

+287
-37
lines changed

6 files changed

+287
-37
lines changed

.github/workflows/lib-deps-check.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ jobs:
2828
run: |
2929
git fetch origin ${{ github.event.pull_request.head.sha }}
3030
31+
- name: Checkout PR Lib files
32+
run: |
33+
# Checkout only Lib/ directory from PR head for accurate comparison
34+
git checkout ${{ github.event.pull_request.head.sha }} -- Lib/
35+
3136
- name: Checkout CPython
3237
run: |
3338
git clone --depth 1 --branch v3.14.2 https://github.com/python/cpython.git cpython
@@ -104,7 +109,7 @@ jobs:
104109
</details>
105110
106111
**Legend:**
107-
- `[+]` path exists, `[-]` path missing
112+
- `[+]` path exists in CPython
108113
- `[x]` up-to-date, `[ ]` outdated
109114
- `native:` Rust/C extension modules
110115

scripts/update_lib/__main__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def main(argv: list[str] | None = None) -> int:
5454
help="Show dependency information for a module",
5555
add_help=False,
5656
)
57+
subparsers.add_parser(
58+
"todo",
59+
help="Show prioritized list of modules to update",
60+
add_help=False,
61+
)
5762

5863
args, remaining = parser.parse_known_args(argv)
5964

@@ -87,6 +92,11 @@ def main(argv: list[str] | None = None) -> int:
8792

8893
return show_deps_main(remaining)
8994

95+
if args.command == "todo":
96+
from update_lib.show_todo import main as show_todo_main
97+
98+
return show_todo_main(remaining)
99+
90100
return 0
91101

92102

scripts/update_lib/deps.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Test dependencies (auto-detected from 'from test import ...')
88
"""
99

10+
import functools
1011
import pathlib
1112

1213
from update_lib.io_utils import read_python_files, safe_parse_ast, safe_read_text
@@ -145,15 +146,18 @@
145146
}
146147

147148

148-
def get_lib_paths(name: str, cpython_prefix: str = "cpython") -> list[pathlib.Path]:
149+
@functools.cache
150+
def get_lib_paths(
151+
name: str, cpython_prefix: str = "cpython"
152+
) -> tuple[pathlib.Path, ...]:
149153
"""Get all library paths for a module.
150154
151155
Args:
152156
name: Module name (e.g., "datetime", "libregrtest")
153157
cpython_prefix: CPython directory prefix
154158
155159
Returns:
156-
List of paths to copy
160+
Tuple of paths to copy
157161
"""
158162
dep_info = DEPENDENCIES.get(name, {})
159163

@@ -168,43 +172,49 @@ def get_lib_paths(name: str, cpython_prefix: str = "cpython") -> list[pathlib.Pa
168172
for dep in dep_info.get("hard_deps", []):
169173
paths.append(construct_lib_path(cpython_prefix, dep))
170174

171-
return paths
175+
return tuple(paths)
172176

173177

174-
def get_test_paths(name: str, cpython_prefix: str = "cpython") -> list[pathlib.Path]:
178+
@functools.cache
179+
def get_test_paths(
180+
name: str, cpython_prefix: str = "cpython"
181+
) -> tuple[pathlib.Path, ...]:
175182
"""Get all test paths for a module.
176183
177184
Args:
178185
name: Module name (e.g., "datetime", "libregrtest")
179186
cpython_prefix: CPython directory prefix
180187
181188
Returns:
182-
List of test paths
189+
Tuple of test paths
183190
"""
184191
if name in DEPENDENCIES and "test" in DEPENDENCIES[name]:
185-
return [
192+
return tuple(
186193
construct_lib_path(cpython_prefix, p) for p in DEPENDENCIES[name]["test"]
187-
]
194+
)
188195

189196
# Default: try directory first, then file
190-
return [resolve_module_path(f"test/test_{name}", cpython_prefix, prefer="dir")]
197+
return (resolve_module_path(f"test/test_{name}", cpython_prefix, prefer="dir"),)
191198

192199

193-
def get_data_paths(name: str, cpython_prefix: str = "cpython") -> list[pathlib.Path]:
200+
@functools.cache
201+
def get_data_paths(
202+
name: str, cpython_prefix: str = "cpython"
203+
) -> tuple[pathlib.Path, ...]:
194204
"""Get additional data paths for a module.
195205
196206
Args:
197207
name: Module name
198208
cpython_prefix: CPython directory prefix
199209
200210
Returns:
201-
List of data paths (may be empty)
211+
Tuple of data paths (may be empty)
202212
"""
203213
if name in DEPENDENCIES and "data" in DEPENDENCIES[name]:
204-
return [
214+
return tuple(
205215
construct_lib_path(cpython_prefix, p) for p in DEPENDENCIES[name]["data"]
206-
]
207-
return []
216+
)
217+
return ()
208218

209219

210220
def parse_test_imports(content: str) -> set[str]:
@@ -272,15 +282,16 @@ def parse_lib_imports(content: str) -> set[str]:
272282
return imports
273283

274284

275-
def get_all_imports(name: str, cpython_prefix: str = "cpython") -> set[str]:
285+
@functools.cache
286+
def get_all_imports(name: str, cpython_prefix: str = "cpython") -> frozenset[str]:
276287
"""Get all imports from a library file.
277288
278289
Args:
279290
name: Module name
280291
cpython_prefix: CPython directory prefix
281292
282293
Returns:
283-
Set of all imported module names
294+
Frozenset of all imported module names
284295
"""
285296
all_imports = set()
286297
for lib_path in get_lib_paths(name, cpython_prefix):
@@ -290,18 +301,19 @@ def get_all_imports(name: str, cpython_prefix: str = "cpython") -> set[str]:
290301

291302
# Remove self
292303
all_imports.discard(name)
293-
return all_imports
304+
return frozenset(all_imports)
294305

295306

296-
def get_soft_deps(name: str, cpython_prefix: str = "cpython") -> set[str]:
307+
@functools.cache
308+
def get_soft_deps(name: str, cpython_prefix: str = "cpython") -> frozenset[str]:
297309
"""Get soft dependencies by parsing imports from library file.
298310
299311
Args:
300312
name: Module name
301313
cpython_prefix: CPython directory prefix
302314
303315
Returns:
304-
Set of imported stdlib module names (those that exist in cpython/Lib/)
316+
Frozenset of imported stdlib module names (those that exist in cpython/Lib/)
305317
"""
306318
all_imports = get_all_imports(name, cpython_prefix)
307319

@@ -312,22 +324,23 @@ def get_soft_deps(name: str, cpython_prefix: str = "cpython") -> set[str]:
312324
if module_path.exists():
313325
stdlib_deps.add(imp)
314326

315-
return stdlib_deps
327+
return frozenset(stdlib_deps)
316328

317329

318-
def get_rust_deps(name: str, cpython_prefix: str = "cpython") -> set[str]:
330+
@functools.cache
331+
def get_rust_deps(name: str, cpython_prefix: str = "cpython") -> frozenset[str]:
319332
"""Get Rust/C dependencies (imports that don't exist in cpython/Lib/).
320333
321334
Args:
322335
name: Module name
323336
cpython_prefix: CPython directory prefix
324337
325338
Returns:
326-
Set of imported module names that are built-in or C extensions
339+
Frozenset of imported module names that are built-in or C extensions
327340
"""
328341
all_imports = get_all_imports(name, cpython_prefix)
329342
soft_deps = get_soft_deps(name, cpython_prefix)
330-
return all_imports - soft_deps
343+
return frozenset(all_imports - soft_deps)
331344

332345

333346
def _dircmp_is_same(dcmp) -> bool:
@@ -350,6 +363,7 @@ def _dircmp_is_same(dcmp) -> bool:
350363
return True
351364

352365

366+
@functools.cache
353367
def is_up_to_date(
354368
name: str, cpython_prefix: str = "cpython", lib_prefix: str = "Lib"
355369
) -> bool:
@@ -472,9 +486,9 @@ def resolve_all_paths(
472486
Dict with "lib", "test", "data", "test_deps" keys
473487
"""
474488
result = {
475-
"lib": get_lib_paths(name, cpython_prefix),
476-
"test": get_test_paths(name, cpython_prefix),
477-
"data": get_data_paths(name, cpython_prefix),
489+
"lib": list(get_lib_paths(name, cpython_prefix)),
490+
"test": list(get_test_paths(name, cpython_prefix)),
491+
"data": list(get_data_paths(name, cpython_prefix)),
478492
"test_deps": [],
479493
}
480494

scripts/update_lib/show_deps.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,17 @@ def format_deps(
169169

170170
lines = []
171171

172-
# lib paths
172+
# lib paths (only show existing)
173173
lib_paths = get_lib_paths(name, cpython_prefix)
174174
for p in lib_paths:
175-
exists = "+" if p.exists() else "-"
176-
lines.append(f"[{exists}] lib: {p}")
175+
if p.exists():
176+
lines.append(f"[+] lib: {p}")
177177

178-
# test paths
178+
# test paths (only show existing)
179179
test_paths = get_test_paths(name, cpython_prefix)
180180
for p in test_paths:
181-
exists = "+" if p.exists() else "-"
182-
lines.append(f"[{exists}] test: {p}")
181+
if p.exists():
182+
lines.append(f"[+] test: {p}")
183183

184184
# hard_deps (from DEPENDENCIES table)
185185
dep_info = DEPENDENCIES.get(name, {})

0 commit comments

Comments
 (0)