11import importlib
22import importlib .util
3- import importlib .abc
3+ import importlib .abc
44import sys
55import os
6- from typing import Any , Callable , Optional , TypeVar , Generic , List
7- from contextlib import contextmanager
6+ import threading
7+ from typing import Any , Callable , Optional , TypeVar , Generic , List , Set
88
99_EAGER_MODE = os .environ .get ("CLI_SPEEDER_EAGER" , "0" ) == "1"
1010
@@ -88,59 +88,61 @@ def lazy_import(name: str, package: Optional[str] = None) -> Any:
8888def lazy_from_import (module_name : str , class_name : str , package : Optional [str ] = None ) -> Any :
8989 return LazyObjectProxy (module_name , class_name , package )
9090
91+
92+
9193class _LazyFinder (importlib .abc .MetaPathFinder ):
9294 """
9395 A custom importer that intercepts specific module names and
94- returns a LazyLoader instead of loading them immediately.
96+ returns a LazyLoader.
97+
98+ Uses thread-local storage to prevent recursion during delegation.
9599 """
96100 def __init__ (self , names : List [str ]):
97101 self .names = set (names )
98- self ._skip = set () # To prevent recursion
102+ self ._local = threading . local ()
99103
100104 def find_spec (self , fullname , path , target = None ):
101- # Check if we should intercept this module
105+ # RECURSION CHECK:
106+ # If we are already inside a find_spec call on this thread, ignore this call.
107+ if getattr (self ._local , "in_lookup" , False ):
108+ return None
109+
102110 # We only care if the TOP LEVEL package matches our list
103111 root_pkg = fullname .split ("." )[0 ]
104112 if root_pkg not in self .names :
105113 return None
106-
107- if fullname in self ._skip :
108- return None
109114
110- # Prevent recursion: Mark this module as "being looked up"
111- self ._skip .add (fullname )
112-
115+ # DELEGATION (With Guard):
113116 try :
114- # Find the *real* spec using other finders
115- # IMPORTANT: We iterate sys.meta_path manually to skip ourselves
117+ self ._local .in_lookup = True # LOCK
118+
119+ # Iterate over other finders manually
116120 spec = None
117121 for finder in sys .meta_path :
118122 if finder is self :
119123 continue
120124 try :
121- # Check if finder has find_spec (some legacy ones don't)
122125 if hasattr (finder , "find_spec" ):
123126 spec = finder .find_spec (fullname , path , target )
124127 if spec :
125128 break
126- except ImportError :
129+ except ( ImportError , AttributeError ) :
127130 continue
128131
129132 if spec is None :
130133 return None
131134
132- # MAGIC: Wrap the real loader in a LazyLoader
133- # Only wrap if it has a loader
135+ # WRAP IN LAZY LOADER
136+ # Only wrap if it has a loader and isn't already lazy
134137 if spec .loader and not isinstance (spec .loader , importlib .util .LazyLoader ):
135138 spec .loader = importlib .util .LazyLoader (spec .loader )
136139
137140 return spec
138141
139142 finally :
140- # Always clear the recursion guard
141- self ._skip .discard (fullname )
143+ self ._local .in_lookup = False # UNLOCK
142144
143- # Global reference to avoid adding multiple finders
145+ # Global reference
144146_INSTALLED_FINDER = None
145147
146148def speed_up_modules (modules : List [str ]):
@@ -152,20 +154,13 @@ def speed_up_modules(modules: List[str]):
152154 """
153155 global _INSTALLED_FINDER
154156
155- # Remove numpy/torch from the list if the user accidentally added them
156- # (Safety mechanism for V2)
157157 unsafe = {"numpy" , "torch" , "pydantic" }
158158 safe_modules = [m for m in modules if m not in unsafe ]
159159
160- if len (safe_modules ) != len (modules ):
161- # We could warn here, but silent safety is better for CLIs
162- pass
163-
164160 if _INSTALLED_FINDER is None :
165161 _INSTALLED_FINDER = _LazyFinder (safe_modules )
166162 sys .meta_path .insert (0 , _INSTALLED_FINDER )
167163 else :
168- # Just update the existing list
169164 _INSTALLED_FINDER .names .update (safe_modules )
170165
171166
0 commit comments