Skip to content

Commit 691d281

Browse files
authored
update_lib todo also shows test todo (#6859)
also tracking untracked files considered in #6775
1 parent eedc70d commit 691d281

File tree

3 files changed

+427
-30
lines changed

3 files changed

+427
-30
lines changed

scripts/update_lib/deps.py

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,24 +68,9 @@ def clear_import_graph_caches() -> None:
6868
"lib": [], # No Python lib (Rust implementation)
6969
"hard_deps": ["_pylong.py"],
7070
},
71-
# Pure Python implementations
72-
"abc": {
73-
"hard_deps": ["_py_abc.py"],
74-
},
75-
"codecs": {
76-
"hard_deps": ["_pycodecs.py"],
77-
},
78-
"datetime": {
79-
"hard_deps": ["_pydatetime.py"],
80-
},
81-
"decimal": {
82-
"hard_deps": ["_pydecimal.py"],
83-
},
84-
"io": {
85-
"hard_deps": ["_pyio.py"],
86-
},
87-
"warnings": {
88-
"hard_deps": ["_py_warnings.py"],
71+
# Non-pattern hard_deps (can't be auto-detected)
72+
"ast": {
73+
"hard_deps": ["_ast_unparse.py"],
8974
},
9075
# Data directories
9176
"pydoc": {
@@ -102,29 +87,52 @@ def clear_import_graph_caches() -> None:
10287
}
10388

10489

105-
def resolve_hard_dep_parent(name: str) -> str | None:
90+
def resolve_hard_dep_parent(name: str, cpython_prefix: str = "cpython") -> str | None:
10691
"""Resolve a hard_dep name to its parent module.
10792
108-
If 'name' is listed as a hard_dep of another module, return that module's name.
109-
E.g., 'pydoc_data' -> 'pydoc', '_pydatetime' -> 'datetime'
93+
Only returns a parent if the file is actually tracked:
94+
- Explicitly listed in DEPENDENCIES as a hard_dep
95+
- Or auto-detected _py{module}.py pattern where the parent module exists
11096
11197
Args:
11298
name: Module or file name (with or without .py extension)
99+
cpython_prefix: CPython directory prefix
113100
114101
Returns:
115-
Parent module name if found, None otherwise
102+
Parent module name if found and tracked, None otherwise
116103
"""
117104
# Normalize: remove .py extension if present
118105
if name.endswith(".py"):
119106
name = name[:-3]
120107

108+
# Check DEPENDENCIES table first (explicit hard_deps)
121109
for module_name, dep_info in DEPENDENCIES.items():
122110
hard_deps = dep_info.get("hard_deps", [])
123111
for dep in hard_deps:
124112
# Normalize dep: remove .py extension
125113
dep_normalized = dep[:-3] if dep.endswith(".py") else dep
126114
if dep_normalized == name:
127115
return module_name
116+
117+
# Auto-detect _py{module} or _py_{module} patterns
118+
# Only if the parent module actually exists
119+
if name.startswith("_py"):
120+
if name.startswith("_py_"):
121+
# _py_abc -> abc
122+
parent = name[4:]
123+
else:
124+
# _pydatetime -> datetime
125+
parent = name[3:]
126+
127+
# Verify the parent module exists
128+
lib_dir = pathlib.Path(cpython_prefix) / "Lib"
129+
parent_file = lib_dir / f"{parent}.py"
130+
parent_dir = lib_dir / parent
131+
if parent_file.exists() or (
132+
parent_dir.exists() and (parent_dir / "__init__.py").exists()
133+
):
134+
return parent
135+
128136
return None
129137

130138

@@ -234,10 +242,16 @@ def get_lib_paths(
234242
# Default: try file first, then directory
235243
paths = [resolve_module_path(name, cpython_prefix, prefer="file")]
236244

237-
# Add hard_deps
245+
# Add hard_deps from DEPENDENCIES
238246
for dep in dep_info.get("hard_deps", []):
239247
paths.append(construct_lib_path(cpython_prefix, dep))
240248

249+
# Auto-detect _py{module}.py or _py_{module}.py patterns
250+
for pattern in [f"_py{name}.py", f"_py_{name}.py"]:
251+
auto_path = construct_lib_path(cpython_prefix, pattern)
252+
if auto_path.exists() and auto_path not in paths:
253+
paths.append(auto_path)
254+
241255
return tuple(paths)
242256

243257

scripts/update_lib/show_deps.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,42 @@
1919
def get_all_modules(cpython_prefix: str = "cpython") -> list[str]:
2020
"""Get all top-level module names from cpython/Lib/.
2121
22+
Includes private modules (_*) that are not hard_deps of other modules.
23+
2224
Returns:
2325
Sorted list of module names (without .py extension)
2426
"""
27+
from update_lib.deps import resolve_hard_dep_parent
28+
2529
lib_dir = pathlib.Path(cpython_prefix) / "Lib"
2630
if not lib_dir.exists():
2731
return []
2832

2933
modules = set()
3034
for entry in lib_dir.iterdir():
31-
# Skip private/internal modules and special directories
32-
if entry.name.startswith(("_", ".")):
35+
# Skip hidden files
36+
if entry.name.startswith("."):
3337
continue
3438
# Skip test directory
3539
if entry.name == "test":
3640
continue
3741

3842
if entry.is_file() and entry.suffix == ".py":
39-
modules.add(entry.stem)
43+
name = entry.stem
4044
elif entry.is_dir() and (entry / "__init__.py").exists():
41-
modules.add(entry.name)
45+
name = entry.name
46+
else:
47+
continue
48+
49+
# Skip private modules that are hard_deps of other modules
50+
# e.g., _pydatetime is a hard_dep of datetime, so skip it
51+
if (
52+
name.startswith("_")
53+
and resolve_hard_dep_parent(name, cpython_prefix) is not None
54+
):
55+
continue
56+
57+
modules.add(name)
4258

4359
return sorted(modules)
4460

0 commit comments

Comments
 (0)