Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi/api/completion.py: 14%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

399 statements  

1import re 

2from textwrap import dedent 

3from typing import Any 

4from inspect import Parameter 

5 

6from parso.python.token import PythonTokenTypes 

7from parso.python import tree 

8from parso.tree import Leaf 

9from parso import split_lines 

10 

11from jedi import debug 

12from jedi import settings 

13from jedi.api import classes 

14from jedi.api import helpers 

15from jedi.api import keywords 

16from jedi.api.strings import complete_dict 

17from jedi.api.file_name import complete_file_name 

18from jedi.inference import imports 

19from jedi.inference.base_value import ValueSet 

20from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names 

21from jedi.inference.context import get_global_filters 

22from jedi.inference.value import TreeInstance 

23from jedi.inference.docstring_utils import DocstringModule 

24from jedi.inference.names import ParamNameWrapper, SubModuleName 

25from jedi.inference.gradual.conversion import convert_values, convert_names 

26from jedi.parser_utils import cut_value_at_position 

27from jedi.plugins import plugin_manager 

28 

29 

30class ParamNameWithEquals(ParamNameWrapper): 

31 def get_public_name(self): 

32 return self.string_name + '=' 

33 

34 

35def _get_signature_param_names(signatures, positional_count, used_kwargs): 

36 # Add named params 

37 for call_sig in signatures: 

38 for i, p in enumerate(call_sig.params): 

39 kind = p.kind 

40 if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD: 

41 continue 

42 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \ 

43 and p.name not in used_kwargs: 

44 yield ParamNameWithEquals(p._name) 

45 

46 

47def _must_be_kwarg(signatures, positional_count, used_kwargs): 

48 if used_kwargs: 

49 return True 

50 

51 must_be_kwarg = True 

52 for signature in signatures: 

53 for i, p in enumerate(signature.params): 

54 kind = p.kind 

55 if kind is Parameter.VAR_POSITIONAL: 

56 # In case there were not already kwargs, the next param can 

57 # always be a normal argument. 

58 return False 

59 

60 if i >= positional_count and kind in (Parameter.POSITIONAL_OR_KEYWORD, 

61 Parameter.POSITIONAL_ONLY): 

62 must_be_kwarg = False 

63 break 

64 if not must_be_kwarg: 

65 break 

66 return must_be_kwarg 

67 

68 

69def filter_names(inference_state, completion_names, stack, like_name, fuzzy, 

70 imported_names, cached_name): 

71 comp_dct = set() 

72 if settings.case_insensitive_completion: 

73 like_name = like_name.lower() 

74 for name in completion_names: 

75 string = name.string_name 

76 if string in imported_names and string != like_name: 

77 continue 

78 if settings.case_insensitive_completion: 

79 string = string.lower() 

80 if helpers.match(string, like_name, fuzzy=fuzzy): 

81 new = classes.Completion( 

82 inference_state, 

83 name, 

84 stack, 

85 len(like_name), 

86 is_fuzzy=fuzzy, 

87 cached_name=cached_name, 

88 ) 

89 k = (new.name, new.complete) # key 

90 if k not in comp_dct: 

91 comp_dct.add(k) 

92 tree_name = name.tree_name 

93 if tree_name is not None: 

94 definition = tree_name.get_definition() 

95 if definition is not None and definition.type == 'del_stmt': 

96 continue 

97 yield new 

98 

99 

100def _remove_duplicates(completions, other_completions): 

101 names = {d.name for d in other_completions} 

102 return [c for c in completions if c.name not in names] 

103 

104 

105def get_user_context(module_context, position): 

106 """ 

107 Returns the scope in which the user resides. This includes flows. 

108 """ 

109 leaf = module_context.tree_node.get_leaf_for_position(position, include_prefixes=True) 

110 return module_context.create_context(leaf) 

111 

112 

113def get_flow_scope_node(module_node, position): 

114 node = module_node.get_leaf_for_position(position, include_prefixes=True) 

115 while not isinstance(node, (tree.Scope, tree.Flow)): 

116 node = node.parent 

117 

118 return node 

119 

120 

121@plugin_manager.decorate() 

122def complete_param_names(context, function_name, decorator_nodes): 

123 # Basically there's no way to do param completion. The plugins are 

124 # responsible for this. 

125 return [] 

126 

127 

128class Completion: 

129 def __init__(self, inference_state, module_context, code_lines, position, 

130 signatures_callback, fuzzy=False): 

131 self._inference_state = inference_state 

132 self._module_context = module_context 

133 self._module_node = module_context.tree_node 

134 self._code_lines = code_lines 

135 

136 # The first step of completions is to get the name 

137 self._like_name = helpers.get_on_completion_name(self._module_node, code_lines, position) 

138 # The actual cursor position is not what we need to calculate 

139 # everything. We want the start of the name we're on. 

140 self._original_position = position 

141 self._signatures_callback = signatures_callback 

142 

143 self._fuzzy = fuzzy 

144 

145 # Return list of completions in this order: 

146 # - Beginning with what user is typing 

147 # - Public (alphabet) 

148 # - Private ("_xxx") 

149 # - Dunder ("__xxx") 

150 def complete(self): 

151 leaf = self._module_node.get_leaf_for_position( 

152 self._original_position, 

153 include_prefixes=True 

154 ) 

155 string, start_leaf, quote = _extract_string_while_in_string(leaf, self._original_position) 

156 

157 prefixed_completions = complete_dict( 

158 self._module_context, 

159 self._code_lines, 

160 start_leaf or leaf, 

161 self._original_position, 

162 None if string is None else quote + string, 

163 fuzzy=self._fuzzy, 

164 ) 

165 

166 if string is not None and not prefixed_completions: 

167 prefixed_completions = list(complete_file_name( 

168 self._inference_state, self._module_context, start_leaf, quote, string, 

169 self._like_name, self._signatures_callback, 

170 self._code_lines, self._original_position, 

171 self._fuzzy 

172 )) 

173 if string is not None: 

174 if not prefixed_completions and '\n' in string: 

175 # Complete only multi line strings 

176 prefixed_completions = self._complete_in_string(start_leaf, string) 

177 return prefixed_completions 

178 

179 cached_name, completion_names = self._complete_python(leaf) 

180 

181 imported_names = [] 

182 if leaf.parent is not None and leaf.parent.type in ['import_as_names', 'dotted_as_names']: 

183 imported_names.extend(extract_imported_names(leaf.parent)) 

184 

185 completions = list(filter_names(self._inference_state, completion_names, 

186 self.stack, self._like_name, 

187 self._fuzzy, imported_names, cached_name=cached_name)) 

188 

189 return ( 

190 # Removing duplicates mostly to remove False/True/None duplicates. 

191 _remove_duplicates(prefixed_completions, completions) 

192 + sorted(completions, key=lambda x: (not x.name.startswith(self._like_name), 

193 x.name.startswith('__'), 

194 x.name.startswith('_'), 

195 x.name.lower())) 

196 ) 

197 

198 def _complete_python(self, leaf): 

199 """ 

200 Analyzes the current context of a completion and decides what to 

201 return. 

202 

203 Technically this works by generating a parser stack and analysing the 

204 current stack for possible grammar nodes. 

205 

206 Possible enhancements: 

207 - global/nonlocal search global 

208 - yield from / raise from <- could be only exceptions/generators 

209 - In args: */**: no completion 

210 - In params (also lambda): no completion before = 

211 """ 

212 grammar = self._inference_state.grammar 

213 self.stack = stack = None 

214 self._position = ( 

215 self._original_position[0], 

216 self._original_position[1] - len(self._like_name) 

217 ) 

218 cached_name = None 

219 

220 try: 

221 self.stack = stack = helpers.get_stack_at_position( 

222 grammar, self._code_lines, leaf, self._position 

223 ) 

224 except helpers.OnErrorLeaf as e: 

225 value = e.error_leaf.value 

226 if value == '.': 

227 # After ErrorLeaf's that are dots, we will not do any 

228 # completions since this probably just confuses the user. 

229 return cached_name, [] 

230 

231 # If we don't have a value, just use global completion. 

232 return cached_name, self._complete_global_scope() 

233 

234 allowed_transitions = \ 

235 list(stack._allowed_transition_names_and_token_types()) 

236 

237 if 'if' in allowed_transitions: 

238 leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True) 

239 previous_leaf = leaf.get_previous_leaf() 

240 

241 indent = self._position[1] 

242 if not (leaf.start_pos <= self._position <= leaf.end_pos): 

243 indent = leaf.start_pos[1] 

244 

245 if previous_leaf is not None: 

246 stmt = previous_leaf 

247 while True: 

248 stmt = stmt.search_ancestor( 

249 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt', 

250 'error_node', 

251 ) 

252 if stmt is None: 

253 break 

254 

255 type_ = stmt.type 

256 if type_ == 'error_node': 

257 first = stmt.children[0] 

258 if isinstance(first, Leaf): 

259 type_ = first.value + '_stmt' 

260 # Compare indents 

261 if stmt.start_pos[1] == indent: 

262 if type_ == 'if_stmt': 

263 allowed_transitions += ['elif', 'else'] 

264 elif type_ == 'try_stmt': 

265 allowed_transitions += ['except', 'finally', 'else'] 

266 elif type_ == 'for_stmt': 

267 allowed_transitions.append('else') 

268 

269 completion_names: list[Any] = [] 

270 

271 kwargs_only = False 

272 if any(t in allowed_transitions for t in (PythonTokenTypes.NAME, 

273 PythonTokenTypes.INDENT)): 

274 # This means that we actually have to do type inference. 

275 

276 nonterminals = [stack_node.nonterminal for stack_node in stack] 

277 

278 nodes = _gather_nodes(stack) 

279 if nodes and nodes[-1] in ('as', 'def', 'class'): 

280 # No completions for ``with x as foo`` and ``import x as foo``. 

281 # Also true for defining names as a class or function. 

282 return cached_name, list(self._complete_inherited(is_function=True)) 

283 elif "import_stmt" in nonterminals: 

284 level, names = parse_dotted_names(nodes, "import_from" in nonterminals) 

285 

286 only_modules = not ("import_from" in nonterminals and 'import' in nodes) 

287 completion_names += self._get_importer_names( 

288 names, 

289 level, 

290 only_modules=only_modules, 

291 ) 

292 elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.': 

293 dot = self._module_node.get_leaf_for_position(self._position) 

294 if dot.type == "newline": 

295 dot = dot.get_previous_leaf() 

296 if dot.type == "endmarker": 

297 # This is a bit of a weird edge case, maybe we can somehow 

298 # generalize this. 

299 dot = leaf.get_previous_leaf() 

300 cached_name, n = self._complete_trailer(dot.get_previous_leaf()) 

301 completion_names += n 

302 elif self._is_parameter_completion(): 

303 completion_names += self._complete_params(leaf) 

304 else: 

305 # Apparently this looks like it's good enough to filter most cases 

306 # so that signature completions don't randomly appear. 

307 # To understand why this works, three things are important: 

308 # 1. trailer with a `,` in it is either a subscript or an arglist. 

309 # 2. If there's no `,`, it's at the start and only signatures start 

310 # with `(`. Other trailers could start with `.` or `[`. 

311 # 3. Decorators are very primitive and have an optional `(` with 

312 # optional arglist in them. 

313 if nodes[-1] in ['(', ','] \ 

314 and nonterminals[-1] in ('trailer', 'arglist', 'decorator'): 

315 signatures = self._signatures_callback(*self._position) 

316 if signatures: 

317 call_details = signatures[0]._call_details 

318 used_kwargs = list(call_details.iter_used_keyword_arguments()) 

319 positional_count = call_details.count_positional_arguments() 

320 

321 completion_names += _get_signature_param_names( 

322 signatures, 

323 positional_count, 

324 used_kwargs, 

325 ) 

326 

327 kwargs_only = _must_be_kwarg(signatures, positional_count, used_kwargs) 

328 

329 if not kwargs_only: 

330 completion_names += self._complete_global_scope() 

331 completion_names += self._complete_inherited(is_function=False) 

332 

333 if not kwargs_only: 

334 current_line = self._code_lines[self._position[0] - 1][:self._position[1]] 

335 completion_names += self._complete_keywords( 

336 allowed_transitions, 

337 only_values=not (not current_line or current_line[-1] in ' \t.;' 

338 and current_line[-3:] != '...') 

339 ) 

340 

341 return cached_name, completion_names 

342 

343 def _is_parameter_completion(self): 

344 tos = self.stack[-1] 

345 if tos.nonterminal == 'lambdef' and len(tos.nodes) == 1: 

346 # We are at the position `lambda `, where basically the next node 

347 # is a param. 

348 return True 

349 if tos.nonterminal in 'parameters': 

350 # Basically we are at the position `foo(`, there's nothing there 

351 # yet, so we have no `typedargslist`. 

352 return True 

353 # var args is for lambdas and typed args for normal functions 

354 return tos.nonterminal in ('typedargslist', 'varargslist') and tos.nodes[-1] == ',' 

355 

356 def _complete_params(self, leaf): 

357 stack_node = self.stack[-2] 

358 if stack_node.nonterminal == 'parameters': 

359 stack_node = self.stack[-3] 

360 if stack_node.nonterminal == 'funcdef': 

361 context = get_user_context(self._module_context, self._position) 

362 node = leaf.search_ancestor('error_node', 'funcdef') 

363 if node is not None: 

364 if node.type == 'error_node': 

365 n = node.children[0] 

366 if n.type == 'decorators': 

367 decorators = n.children 

368 elif n.type == 'decorator': 

369 decorators = [n] 

370 else: 

371 decorators = [] 

372 else: 

373 decorators = node.get_decorators() 

374 function_name = stack_node.nodes[1] 

375 

376 return complete_param_names(context, function_name.value, decorators) 

377 return [] 

378 

379 def _complete_keywords(self, allowed_transitions, only_values): 

380 for k in allowed_transitions: 

381 if isinstance(k, str) and k.isalpha(): 

382 if not only_values or k in ('True', 'False', 'None'): 

383 yield keywords.KeywordName(self._inference_state, k) 

384 

385 def _complete_global_scope(self): 

386 context = get_user_context(self._module_context, self._position) 

387 debug.dbg('global completion scope: %s', context) 

388 flow_scope_node = get_flow_scope_node(self._module_node, self._position) 

389 filters = get_global_filters( 

390 context, 

391 self._position, 

392 flow_scope_node 

393 ) 

394 completion_names = [] 

395 for filter in filters: 

396 completion_names += filter.values() 

397 return completion_names 

398 

399 def _complete_trailer(self, previous_leaf): 

400 inferred_context = self._module_context.create_context(previous_leaf) 

401 values = infer_call_of_leaf(inferred_context, previous_leaf) 

402 debug.dbg('trailer completion values: %s', values, color='MAGENTA') 

403 

404 # The cached name simply exists to make speed optimizations for certain 

405 # modules. 

406 cached_name = None 

407 if len(values) == 1: 

408 v, = values 

409 if v.is_module(): 

410 if len(v.string_names) == 1: 

411 module_name = v.string_names[0] 

412 if module_name in ('numpy', 'tensorflow', 'matplotlib', 'pandas'): 

413 cached_name = module_name 

414 

415 return cached_name, self._complete_trailer_for_values(values) 

416 

417 def _complete_trailer_for_values(self, values): 

418 user_context = get_user_context(self._module_context, self._position) 

419 

420 return complete_trailer(user_context, values) 

421 

422 def _get_importer_names(self, names, level=0, only_modules=True): 

423 names = [n.value for n in names] 

424 i = imports.Importer(self._inference_state, names, self._module_context, level) 

425 return i.completion_names(self._inference_state, only_modules=only_modules) 

426 

427 def _complete_inherited(self, is_function=True): 

428 """ 

429 Autocomplete inherited methods when overriding in child class. 

430 """ 

431 leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True) 

432 cls = leaf.search_ancestor('classdef') 

433 if cls is None: 

434 return 

435 

436 # Complete the methods that are defined in the super classes. 

437 class_value = self._module_context.create_value(cls) 

438 

439 if cls.start_pos[1] >= leaf.start_pos[1]: 

440 return 

441 

442 filters = class_value.get_filters(is_instance=True) 

443 # The first dict is the dictionary of class itself. 

444 next(filters) 

445 for filter in filters: 

446 for name in filter.values(): 

447 # TODO we should probably check here for properties 

448 if (name.api_type == 'function') == is_function: 

449 yield name 

450 

451 def _complete_in_string(self, start_leaf, string): 

452 """ 

453 To make it possible for people to have completions in doctests or 

454 generally in "Python" code in docstrings, we use the following 

455 heuristic: 

456 

457 - Having an indented block of code 

458 - Having some doctest code that starts with `>>>` 

459 - Having backticks that doesn't have whitespace inside it 

460 """ 

461 

462 def iter_relevant_lines(lines): 

463 include_next_line = False 

464 for l in code_lines: 

465 if include_next_line or l.startswith('>>>') or l.startswith(' '): 

466 yield re.sub(r'^( *>>> ?| +)', '', l) 

467 else: 

468 yield None 

469 

470 include_next_line = bool(re.match(' *>>>', l)) 

471 

472 string = dedent(string) 

473 code_lines = split_lines(string, keepends=True) 

474 relevant_code_lines = list(iter_relevant_lines(code_lines)) 

475 if relevant_code_lines[-1] is not None: 

476 # Some code lines might be None, therefore get rid of that. 

477 relevant_code_lines = ['\n' if c is None else c for c in relevant_code_lines] 

478 return self._complete_code_lines(relevant_code_lines) 

479 match = re.search(r'`([^`\s]+)', code_lines[-1]) 

480 if match: 

481 return self._complete_code_lines([match.group(1)]) 

482 return [] 

483 

484 def _complete_code_lines(self, code_lines): 

485 module_node = self._inference_state.grammar.parse(''.join(code_lines)) 

486 module_value = DocstringModule( 

487 in_module_context=self._module_context, 

488 inference_state=self._inference_state, 

489 module_node=module_node, 

490 code_lines=code_lines, 

491 ) 

492 return Completion( 

493 self._inference_state, 

494 module_value.as_context(), 

495 code_lines=code_lines, 

496 position=module_node.end_pos, 

497 signatures_callback=lambda *args, **kwargs: [], 

498 fuzzy=self._fuzzy 

499 ).complete() 

500 

501 

502def _gather_nodes(stack): 

503 nodes = [] 

504 for stack_node in stack: 

505 if stack_node.dfa.from_rule == 'small_stmt': 

506 nodes = [] 

507 else: 

508 nodes += stack_node.nodes 

509 return nodes 

510 

511 

512_string_start = re.compile(r'^\w*(\'{3}|"{3}|\'|")') 

513 

514 

515def _extract_string_while_in_string(leaf, position): 

516 def return_part_of_leaf(leaf): 

517 kwargs = {} 

518 if leaf.line == position[0]: 

519 kwargs['endpos'] = position[1] - leaf.column 

520 match = _string_start.match(leaf.value, **kwargs) 

521 if not match: 

522 return None, None, None 

523 start = match.group(0) 

524 if leaf.line == position[0] and position[1] < leaf.column + match.end(): 

525 return None, None, None 

526 return cut_value_at_position(leaf, position)[match.end():], leaf, start 

527 

528 if position < leaf.start_pos: 

529 return None, None, None 

530 

531 if leaf.type == 'string': 

532 return return_part_of_leaf(leaf) 

533 

534 leaves = [] 

535 while leaf is not None: 

536 if leaf.type == 'error_leaf' and ('"' in leaf.value or "'" in leaf.value): 

537 if len(leaf.value) > 1: 

538 return return_part_of_leaf(leaf) 

539 prefix_leaf = None 

540 if not leaf.prefix: 

541 prefix_leaf = leaf.get_previous_leaf() 

542 if prefix_leaf is None or prefix_leaf.type != 'name' \ 

543 or not all(c in 'rubf' for c in prefix_leaf.value.lower()): 

544 prefix_leaf = None 

545 

546 return ( 

547 ''.join(cut_value_at_position(l, position) for l in leaves), 

548 prefix_leaf or leaf, 

549 ('' if prefix_leaf is None else prefix_leaf.value) 

550 + cut_value_at_position(leaf, position), 

551 ) 

552 if leaf.line != position[0]: 

553 # Multi line strings are always simple error leaves and contain the 

554 # whole string, single line error leaves are atherefore important 

555 # now and since the line is different, it's not really a single 

556 # line string anymore. 

557 break 

558 leaves.insert(0, leaf) 

559 leaf = leaf.get_previous_leaf() 

560 return None, None, None 

561 

562 

563def complete_trailer(user_context, values): 

564 completion_names = [] 

565 for value in values: 

566 for filter in value.get_filters(origin_scope=user_context.tree_node): 

567 completion_names += filter.values() 

568 

569 if not value.is_stub() and isinstance(value, TreeInstance): 

570 completion_names += _complete_getattr(user_context, value) 

571 

572 python_values = convert_values(values) 

573 for c in python_values: 

574 if c not in values: 

575 for filter in c.get_filters(origin_scope=user_context.tree_node): 

576 completion_names += filter.values() 

577 return completion_names 

578 

579 

580def _complete_getattr(user_context, instance): 

581 """ 

582 A heuristic to make completion for proxy objects work. This is not 

583 intended to work in all cases. It works exactly in this case: 

584 

585 def __getattr__(self, name): 

586 ... 

587 return getattr(any_object, name) 

588 

589 It is important that the return contains getattr directly, otherwise it 

590 won't work anymore. It's really just a stupid heuristic. It will not 

591 work if you write e.g. `return (getatr(o, name))`, because of the 

592 additional parentheses. It will also not work if you move the getattr 

593 to some other place that is not the return statement itself. 

594 

595 It is intentional that it doesn't work in all cases. Generally it's 

596 really hard to do even this case (as you can see below). Most people 

597 will write it like this anyway and the other ones, well they are just 

598 out of luck I guess :) ~dave. 

599 """ 

600 names = (instance.get_function_slot_names('__getattr__') 

601 or instance.get_function_slot_names('__getattribute__')) 

602 functions = ValueSet.from_sets( 

603 name.infer() 

604 for name in names 

605 ) 

606 for func in functions: 

607 tree_node = func.tree_node 

608 if tree_node is None or tree_node.type != 'funcdef': 

609 continue 

610 

611 for return_stmt in tree_node.iter_return_stmts(): 

612 # Basically until the next comment we just try to find out if a 

613 # return statement looks exactly like `return getattr(x, name)`. 

614 if return_stmt.type != 'return_stmt': 

615 continue 

616 atom_expr = return_stmt.children[1] 

617 if atom_expr.type != 'atom_expr': 

618 continue 

619 atom = atom_expr.children[0] 

620 trailer = atom_expr.children[1] 

621 if len(atom_expr.children) != 2 or atom.type != 'name' \ 

622 or atom.value != 'getattr': 

623 continue 

624 arglist = trailer.children[1] 

625 if arglist.type != 'arglist' or len(arglist.children) < 3: 

626 continue 

627 context = func.as_context() 

628 object_node = arglist.children[0] 

629 

630 # Make sure it's a param: foo in __getattr__(self, foo) 

631 name_node = arglist.children[2] 

632 name_list = context.goto(name_node, name_node.start_pos) 

633 if not any(n.api_type == 'param' for n in name_list): 

634 continue 

635 

636 # Now that we know that these are most probably completion 

637 # objects, we just infer the object and return them as 

638 # completions. 

639 objects = context.infer_node(object_node) 

640 return complete_trailer(user_context, objects) 

641 return [] 

642 

643 

644def search_in_module(inference_state, module_context, names, wanted_names, 

645 wanted_type, complete=False, fuzzy=False, 

646 ignore_imports=False, convert=False): 

647 for s in wanted_names[:-1]: 

648 new_names = [] 

649 for n in names: 

650 if s == n.string_name: 

651 if n.tree_name is not None and n.api_type in ('module', 'namespace') \ 

652 and ignore_imports: 

653 continue 

654 new_names += complete_trailer( 

655 module_context, 

656 n.infer() 

657 ) 

658 debug.dbg('dot lookup on search %s from %s', new_names, names[:10]) 

659 names = new_names 

660 

661 last_name = wanted_names[-1].lower() 

662 for n in names: 

663 string = n.string_name.lower() 

664 if complete and helpers.match(string, last_name, fuzzy=fuzzy) \ 

665 or not complete and string == last_name: 

666 if isinstance(n, SubModuleName): 

667 names = [v.name for v in n.infer()] 

668 else: 

669 names = [n] 

670 if convert: 

671 names = convert_names(names) 

672 for n2 in names: 

673 if complete: 

674 def_ = classes.Completion( 

675 inference_state, n2, 

676 stack=None, 

677 like_name_length=len(last_name), 

678 is_fuzzy=fuzzy, 

679 ) 

680 else: 

681 def_ = classes.Name(inference_state, n2) 

682 if not wanted_type or wanted_type == def_.type: 

683 yield def_ 

684 

685 

686def extract_imported_names(node): 

687 imported_names = [] 

688 

689 if node.type in ['import_as_names', 'dotted_as_names', 'dotted_as_name', 'import_as_name']: 

690 for index, child in enumerate(node.children): 

691 if child.type == 'name': 

692 if (index > 1 and node.children[index - 1].type == "keyword" 

693 and node.children[index - 1].value == "as"): 

694 continue 

695 imported_names.append(child.value) 

696 elif child.type in ('import_as_name', 'dotted_as_name'): 

697 imported_names.extend(extract_imported_names(child)) 

698 

699 return imported_names