Skip to content

Commit 5ef8d48

Browse files
update_lib hard dependency resolver (#6817)
* update_lib __init__ handling * dependency * Auto-format: ruff format --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent e01f26c commit 5ef8d48

File tree

13 files changed

+958
-17
lines changed

13 files changed

+958
-17
lines changed

.claude/commands/upgrade-pylib.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ If during the upgrade process you encounter any of the following issues with `sc
1414

1515
**STOP the upgrade and report the issue first.** Describe:
1616
1. What you were trying to do
17-
- Library name
18-
- The full command executed (e.g. python scripts/update_lib quick cpython/Lib/$ARGUMENTS.py)
17+
- Library name
18+
- The full command executed (e.g. python scripts/update_lib quick cpython/Lib/$ARGUMENTS.py)
1919
2. What went wrong or what's missing
2020
3. Expected vs actual behavior
2121

scripts/update_lib/auto_mark.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
from update_lib.path import test_name_from_path
2323

2424

25+
class TestRunError(Exception):
26+
"""Raised when test run fails entirely (e.g., import error, crash)."""
27+
28+
pass
29+
30+
2531
@dataclass
2632
class Test:
2733
name: str = ""
@@ -58,7 +64,8 @@ def run_test(test_name: str, skip_build: bool = False) -> TestResult:
5864

5965
result = subprocess.run(
6066
cmd + ["-m", "test", "-v", "-u", "all", "--slowest", test_name],
61-
capture_output=True,
67+
stdout=subprocess.PIPE, # Capture stdout for parsing
68+
stderr=None, # Let stderr pass through to terminal
6269
text=True,
6370
)
6471
return parse_results(result)
@@ -236,6 +243,9 @@ def _is_super_call_only(func_node: ast.FunctionDef | ast.AsyncFunctionDef) -> bo
236243
return False
237244
if not isinstance(call.func, ast.Attribute):
238245
return False
246+
# Verify the method name matches
247+
if call.func.attr != func_node.name:
248+
return False
239249
super_call = call.func.value
240250
if not isinstance(super_call, ast.Call):
241251
return False
@@ -487,6 +497,14 @@ def auto_mark_file(
487497
print(f"Running test: {test_name}")
488498

489499
results = run_test(test_name, skip_build=skip_build)
500+
501+
# Check if test run failed entirely (e.g., import error, crash)
502+
if not results.tests_result:
503+
raise TestRunError(
504+
f"Test run failed for {test_name}. "
505+
f"Output: {results.stdout[-500:] if results.stdout else '(no output)'}"
506+
)
507+
490508
contents = test_path.read_text(encoding="utf-8")
491509

492510
all_failing_tests, unexpected_successes, error_messages = collect_test_changes(
@@ -577,6 +595,13 @@ def auto_mark_directory(
577595

578596
results = run_test(test_name, skip_build=skip_build)
579597

598+
# Check if test run failed entirely (e.g., import error, crash)
599+
if not results.tests_result:
600+
raise TestRunError(
601+
f"Test run failed for {test_name}. "
602+
f"Output: {results.stdout[-500:] if results.stdout else '(no output)'}"
603+
)
604+
580605
total_added = 0
581606
total_removed = 0
582607
total_regressions = 0

scripts/update_lib/copy_lib.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,12 @@
1616
import sys
1717

1818

19-
def copy_lib(
19+
def _copy_single(
2020
src_path: pathlib.Path,
21+
lib_path: pathlib.Path,
2122
verbose: bool = True,
2223
) -> None:
23-
"""
24-
Copy library file or directory from CPython.
25-
26-
Args:
27-
src_path: Source path (e.g., cpython/Lib/dataclasses.py or cpython/Lib/json)
28-
verbose: Print progress messages
29-
"""
30-
from update_lib.path import parse_lib_path
31-
32-
lib_path = parse_lib_path(src_path)
33-
24+
"""Copy a single file or directory."""
3425
# Remove existing file/directory
3526
if lib_path.exists():
3627
if lib_path.is_dir():
@@ -46,6 +37,7 @@ def copy_lib(
4637
if src_path.is_dir():
4738
if verbose:
4839
print(f"Copying directory: {src_path} -> {lib_path}")
40+
lib_path.parent.mkdir(parents=True, exist_ok=True)
4941
shutil.copytree(src_path, lib_path)
5042
else:
5143
if verbose:
@@ -54,6 +46,46 @@ def copy_lib(
5446
shutil.copy2(src_path, lib_path)
5547

5648

49+
def copy_lib(
50+
src_path: pathlib.Path,
51+
verbose: bool = True,
52+
) -> None:
53+
"""
54+
Copy library file or directory from CPython.
55+
56+
Also copies additional files if defined in DEPENDENCIES table.
57+
58+
Args:
59+
src_path: Source path (e.g., cpython/Lib/dataclasses.py or cpython/Lib/json)
60+
verbose: Print progress messages
61+
"""
62+
from update_lib.deps import get_lib_paths
63+
from update_lib.path import parse_lib_path
64+
65+
# Extract module name and cpython prefix from path
66+
path_str = str(src_path).replace("\\", "/")
67+
if "/Lib/" in path_str:
68+
cpython_prefix, after_lib = path_str.split("/Lib/", 1)
69+
# Get module name (first component, without .py)
70+
name = after_lib.split("/")[0]
71+
if name.endswith(".py"):
72+
name = name[:-3]
73+
else:
74+
# Fallback: just copy the single file
75+
lib_path = parse_lib_path(src_path)
76+
_copy_single(src_path, lib_path, verbose)
77+
return
78+
79+
# Get all paths to copy from DEPENDENCIES table
80+
all_src_paths = get_lib_paths(name, cpython_prefix)
81+
82+
# Copy each file
83+
for src in all_src_paths:
84+
if src.exists():
85+
lib_path = parse_lib_path(src)
86+
_copy_single(src, lib_path, verbose)
87+
88+
5789
def main(argv: list[str] | None = None) -> int:
5890
parser = argparse.ArgumentParser(
5991
description=__doc__,

0 commit comments

Comments
 (0)