@@ -34,6 +34,7 @@ class LazyModule:
3434 _module_name (str): The full name of the module to import
3535 _extra_group (str): The extra dependency group required for this module
3636 _module (ModuleType): The actual imported module (None until first access)
37+ _submodules (dict): Cache for LazyModule instances of submodules
3738
3839 Example:
3940 >>> ray = LazyModule('ray', 'speculative')
@@ -52,36 +53,81 @@ def __init__(self, module_name: str, extra_group: str = None):
5253 self ._module_name = module_name
5354 self ._extra_group = extra_group
5455 self ._module = None
56+ self ._submodules = {}
57+
58+ def _import_module (self ):
59+ """
60+ Import the target module if not already imported.
61+
62+ Raises:
63+ ImportError: If the module cannot be imported
64+ """
65+ if self ._module is None :
66+ try :
67+ self ._module = importlib .import_module (self ._module_name )
68+ except ImportError as e :
69+ if self ._extra_group :
70+ raise ImportError (
71+ f"Module '{ self ._module_name } ' requires "
72+ f"additional dependencies. Please install: "
73+ f"pip install 'angelslim[{ self ._extra_group } ]'"
74+ ) from e
75+ raise
5576
5677 def __getattr__ (self , name : str ) -> Any :
5778 """
5879 Delegate attribute access to the actual module.
5980
6081 On first access, this method imports the target module and then
61- delegates the attribute lookup to the actual module.
82+ delegates the attribute lookup to the actual module. For submodules,
83+ it returns a LazyModule instance to support multi-level access.
6284
6385 Args:
6486 name: Name of the attribute to access
6587
6688 Returns:
67- The requested attribute from the target module
89+ The requested attribute from the target module, or a LazyModule
90+ instance for submodules
6891
6992 Raises:
7093 ImportError: If the module cannot be imported and an
7194 extra_group is specified, provides installation instructions
7295 """
73- if self ._module is None :
96+ # Return cached submodule if exists
97+ if name in self ._submodules :
98+ return self ._submodules [name ]
99+
100+ self ._import_module ()
101+
102+ # Try to get the attribute from the imported module
103+ try :
104+ attr = getattr (self ._module , name )
105+ # If it's a module, wrap it in LazyModule for consistent behavior
106+ if isinstance (attr , type (self ._module )):
107+ submodule_name = f"{ self ._module_name } .{ name } "
108+ lazy_submodule = LazyModule (submodule_name , self ._extra_group )
109+ lazy_submodule ._module = attr # Cache the already imported module
110+ self ._submodules [name ] = lazy_submodule
111+ return lazy_submodule
112+ return attr
113+ except AttributeError :
114+ # If attribute not found, try importing as a submodule
115+ submodule_name = f"{ self ._module_name } .{ name } "
74116 try :
75- self ._module = importlib .import_module (self ._module_name )
76- except ImportError as e :
77- if self ._extra_group :
78- raise ImportError (
79- f"Module '{ self ._module_name } ' requires "
80- f"additional dependencies. Please install: "
81- f"pip install 'angelslim[{ self ._extra_group } ]'"
82- ) from e
83- raise
84- return getattr (self ._module , name )
117+ # Create a LazyModule for the submodule
118+ lazy_submodule = LazyModule (submodule_name , self ._extra_group )
119+ # Trigger import to verify it exists
120+ lazy_submodule ._import_module ()
121+ # Cache it
122+ self ._submodules [name ] = lazy_submodule
123+ # Also cache in parent module for consistency
124+ setattr (self ._module , name , lazy_submodule ._module )
125+ return lazy_submodule
126+ except ImportError :
127+ # If submodule import fails, re-raise the original AttributeError
128+ raise AttributeError (
129+ f"module '{ self ._module_name } ' has no attribute '{ name } '"
130+ )
85131
86132
87133class LazyAttribute :
@@ -154,6 +200,7 @@ def __getattr__(self, name: str) -> Any:
154200anthropic = LazyModule ("anthropic" , "speculative" )
155201jsonschema_specifications = LazyModule ("jsonschema_specifications" , "speculative" )
156202referencing = LazyModule ("referencing" , "speculative" )
203+ deepspeed = LazyModule ("deepspeed" , "speculative" )
157204
158205
159206# --- VLM related lazy imports ---
0 commit comments