@@ -32,7 +32,12 @@ def compute_todo_list(
3232 Returns:
3333 List of dicts with module info, sorted by priority
3434 """
35- from update_lib .deps import get_rust_deps , get_soft_deps , is_up_to_date
35+ from update_lib .deps import (
36+ get_all_hard_deps ,
37+ get_rust_deps ,
38+ get_soft_deps ,
39+ is_up_to_date ,
40+ )
3641 from update_lib .show_deps import get_all_modules
3742
3843 all_modules = get_all_modules (cpython_prefix )
@@ -44,11 +49,19 @@ def compute_todo_list(
4449 native_deps = get_rust_deps (name , cpython_prefix )
4550 up_to_date = is_up_to_date (name , cpython_prefix , lib_prefix )
4651
52+ # Get hard_deps and check their status
53+ hard_deps = get_all_hard_deps (name , cpython_prefix )
54+ hard_deps_status = {
55+ hd : is_up_to_date (hd , cpython_prefix , lib_prefix )
56+ for hd in hard_deps
57+ }
58+
4759 module_data [name ] = {
4860 "name" : name ,
4961 "soft_deps" : soft_deps ,
5062 "native_deps" : native_deps ,
5163 "up_to_date" : up_to_date ,
64+ "hard_deps_status" : hard_deps_status ,
5265 }
5366
5467 # Build reverse dependency map: who depends on this module
@@ -61,8 +74,11 @@ def compute_todo_list(
6174 # Compute scores and filter
6275 result = []
6376 for name , data in module_data .items ():
64- # Skip already up-to-date modules (unless --done)
65- if data ["up_to_date" ] and not include_done :
77+ hard_deps_status = data ["hard_deps_status" ]
78+ has_outdated_hard_deps = any (not ok for ok in hard_deps_status .values ())
79+
80+ # Include if: not up-to-date, or has outdated hard_deps, or --done
81+ if data ["up_to_date" ] and not has_outdated_hard_deps and not include_done :
6682 continue
6783
6884 soft_deps = data ["soft_deps" ]
@@ -90,6 +106,7 @@ def compute_todo_list(
90106 "native_deps" : data ["native_deps" ],
91107 "soft_deps" : soft_deps ,
92108 "up_to_date" : data ["up_to_date" ],
109+ "hard_deps_status" : hard_deps_status ,
93110 }
94111 )
95112
@@ -202,13 +219,15 @@ def get_original_files(
202219 cpython_prefix : str ,
203220 lib_prefix : str ,
204221) -> list [str ]:
205- """Get files that exist in our Lib but not in cpython/Lib.
222+ """Get top-level files/modules that exist in our Lib but not in cpython/Lib.
206223
207224 These are RustPython-original files that don't come from CPython.
225+ Modules that exist in cpython are handled by the library todo (even if
226+ they have additional local files), so they are excluded here.
208227 Excludes test/ directory (handled separately).
209228
210229 Returns:
211- Sorted list of relative paths (e.g., ["_rustpython_tokenize .py"])
230+ Sorted list of top-level names (e.g., ["_dummy_thread .py"])
212231 """
213232 cpython_lib = pathlib .Path (cpython_prefix ) / "Lib"
214233 local_lib = pathlib .Path (lib_prefix )
@@ -218,26 +237,26 @@ def get_original_files(
218237
219238 original = []
220239
221- for local_file in local_lib .rglob ("*" ):
222- # Skip directories
223- if local_file .is_dir ():
224- continue
240+ # Only check top-level entries
241+ for entry in local_lib .iterdir ():
242+ name = entry .name
225243
226- # Get relative path from Lib/
227- rel_path = local_file .relative_to (local_lib )
244+ # Skip hidden files and __pycache__
245+ if name .startswith ("." ) or name == "__pycache__" :
246+ continue
228247
229248 # Skip test/ directory (handled separately)
230- if rel_path . parts and rel_path . parts [ 0 ] == "test" :
249+ if name == "test" :
231250 continue
232251
233- # Skip __pycache__ directories
234- if "__pycache__" in rel_path . parts :
252+ # Skip site-packages (not a module)
253+ if name == "site-packages" :
235254 continue
236255
237- # Check if exists in cpython lib
238- cpython_file = cpython_lib / rel_path
239- if not cpython_file .exists ():
240- original .append (str ( rel_path ) )
256+ # Only include if it doesn't exist in cpython at all
257+ cpython_entry = cpython_lib / name
258+ if not cpython_entry .exists ():
259+ original .append (name )
241260
242261 return sorted (original )
243262
@@ -559,12 +578,25 @@ def format_todo_list(
559578
560579 rev_str = f"{ rev_count } dependents" if rev_count else ""
561580
562- parts = ["-" , done_mark , f"[{ score_str } ]" , name ]
581+ parts = ["-" , done_mark , f"[{ score_str } ]" , f"` { name } `" ]
563582 if rev_str :
564583 parts .append (f"({ rev_str } )" )
565584
566585 lines .append (" " .join (parts ))
567586
587+ # Show hard_deps:
588+ # - Normal mode: only show if lib is up-to-date but hard_deps are not
589+ # - Verbose mode: always show all hard_deps with their status
590+ hard_deps_status = item .get ("hard_deps_status" , {})
591+ if verbose and hard_deps_status :
592+ for hd in sorted (hard_deps_status .keys ()):
593+ hd_mark = "[x]" if hard_deps_status [hd ] else "[ ]"
594+ lines .append (f" - { hd_mark } { hd } (hard_dep)" )
595+ elif item ["up_to_date" ]:
596+ for hd , ok in sorted (hard_deps_status .items ()):
597+ if not ok :
598+ lines .append (f" - [ ] { hd } (hard_dep)" )
599+
568600 # Show corresponding tests if exist
569601 if test_by_lib and name in test_by_lib :
570602 for test_info in test_by_lib [name ]:
0 commit comments