@@ -72,32 +72,43 @@ def __init__(self, namespace: Mapping[str, Any] | None = None) -> None:
7272 self ._curr_sys_path : list [str ] = sys .path [:]
7373 self ._stdlib_path = os .path .dirname (importlib .__path__ [0 ])
7474
75- def get_completions (self , line : str ) -> tuple [list [str ], list [Any ], CompletionAction | None ] | None :
75+ def get_completions (
76+ self , line : str , * , include_values : bool = True
77+ ) -> tuple [list [str ], list [Any ], CompletionAction | None ] | None :
7678 """Return the next possible import completions for 'line'.
7779
7880 For attributes completion, if the module to complete from is not
7981 imported, also return an action (prompt + callback to run if the
8082 user press TAB again) to import the module.
83+
84+ If *include_values* is false, the returned values list is empty and
85+ attribute values are not resolved.
8186 """
8287 result = ImportParser (line ).parse ()
8388 if not result :
8489 return None
8590 try :
86- return self .complete (* result )
91+ return self .complete (* result , include_values = include_values )
8792 except Exception :
8893 # Some unexpected error occurred, make it look like
8994 # no completions are available
9095 return [], [], None
9196
92- def complete (self , from_name : str | None , name : str | None ) -> tuple [list [str ], list [Any ], CompletionAction | None ]:
97+ def complete (
98+ self ,
99+ from_name : str | None ,
100+ name : str | None ,
101+ * ,
102+ include_values : bool = True ,
103+ ) -> tuple [list [str ], list [Any ], CompletionAction | None ]:
93104 if from_name is None :
94105 # import x.y.z<tab>
95106 assert name is not None
96107 path , prefix = self .get_path_and_prefix (name )
97108 modules = self .find_modules (path , prefix )
98109 names = [self .format_completion (path , module ) for module in modules ]
99110 # These are always modules, use dummy values to get the right color
100- values = [sys ] * len (names )
111+ values = [sys ] * len (names ) if include_values else []
101112 return names , values , None
102113
103114 if name is None :
@@ -106,18 +117,22 @@ def complete(self, from_name: str | None, name: str | None) -> tuple[list[str],
106117 modules = self .find_modules (path , prefix )
107118 names = [self .format_completion (path , module ) for module in modules ]
108119 # These are always modules, use dummy values to get the right color
109- values = [sys ] * len (names )
120+ values = [sys ] * len (names ) if include_values else []
110121 return names , values , None
111122
112123 # from x.y import z<tab>
113124 submodules = self .find_modules (from_name , name )
114- attr_names , attr_values , action = self .find_attributes (from_name , name )
125+ attr_names , attr_module , action = self ._find_attributes (from_name , name )
115126 all_names = sorted ({* submodules , * attr_names })
127+ if not include_values :
128+ return all_names , [], action
129+
116130 # Build values list matching the sorted order:
117131 # submodules use `sys` as a dummy value so they get the 'module' color,
118132 # attributes use their actual value.
119- submodule_set = set (submodules )
120- attr_map = dict (zip (attr_names , attr_values ))
133+ attr_map = {}
134+ if attr_module is not None :
135+ attr_map = {n : safe_getattr (attr_module , n ) for n in attr_names }
121136 all_values = [attr_map [n ] if n in attr_map else sys for n in all_names ]
122137 return all_names , all_values , action
123138
@@ -180,43 +195,43 @@ def _is_stdlib_module(self, module_info: pkgutil.ModuleInfo) -> bool:
180195 return (isinstance (module_info .module_finder , FileFinder )
181196 and module_info .module_finder .path == self ._stdlib_path )
182197
183- def find_attributes (self , path : str , prefix : str ) -> tuple [list [str ], list [Any ], CompletionAction | None ]:
198+ def find_attributes (
199+ self , path : str , prefix : str
200+ ) -> tuple [list [str ], list [Any ], CompletionAction | None ]:
184201 """Find all attributes of module 'path' that start with 'prefix'."""
185- attributes , values , action = self ._find_attributes (path , prefix )
186- # Filter out invalid attribute names
187- # (for example those containing dashes that cannot be imported with 'import')
188- filtered_names = []
189- filtered_values = []
190- for attr , val in zip (attributes , values ):
191- if attr .isidentifier ():
192- filtered_names .append (attr )
193- filtered_values .append (val )
194- return filtered_names , filtered_values , action
195-
196- def _find_attributes (self , path : str , prefix : str ) -> tuple [list [str ], list [Any ], CompletionAction | None ]:
202+ attributes , module , action = self ._find_attributes (path , prefix )
203+ if module is not None :
204+ values = [safe_getattr (module , attr ) for attr in attributes ]
205+ else :
206+ values = []
207+ return attributes , values , action
208+
209+ def _find_attributes (
210+ self , path : str , prefix : str
211+ ) -> tuple [list [str ], ModuleType | None , CompletionAction | None ]:
197212 path = self ._resolve_relative_path (path ) # type: ignore[assignment]
198213 if path is None :
199- return [], [] , None
214+ return [], None , None
200215
201216 imported_module = sys .modules .get (path )
202217 if not imported_module :
203218 if path in self ._failed_imports : # Do not propose to import again
204- return [], [] , None
219+ return [], None , None
205220 imported_module = self ._maybe_import_module (path )
206221 if not imported_module :
207- return [], [] , self ._get_import_completion_action (path )
222+ return [], None , self ._get_import_completion_action (path )
208223 try :
209224 module_attributes = dir (imported_module )
210225 except Exception :
211226 module_attributes = []
212- names = []
213- values = []
214- for attr_name in module_attributes :
215- if not self . is_suggestion_match ( attr_name , prefix ):
216- continue
217- names . append ( attr_name )
218- values . append ( safe_getattr ( imported_module , attr_name ))
219- return names , values , None
227+ # Filter out invalid attribute names, such as dashes that cannot be
228+ # imported with 'import'.
229+ names = [
230+ attr_name for attr_name in module_attributes
231+ if ( self . is_suggestion_match ( attr_name , prefix )
232+ and attr_name . isidentifier () )
233+ ]
234+ return names , imported_module , None
220235
221236 def is_suggestion_match (self , module_name : str , prefix : str ) -> bool :
222237 if prefix :
0 commit comments