1 """ 2 Searching for names with given scope and name. This is very central in Jedi and 3 Python. The name resolution is quite complicated with descripter, 4 ``__getattribute__``, ``__getattr__``, ``global``, etc. 5 6 If you want to understand name resolution, please read the first few chapters 7 in http://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/. 8 9 Flow checks 10 +++++++++++ 11 12 Flow checks are not really mature. There's only a check for ``isinstance``. It 13 would check whether a flow has the form of ``if isinstance(a, type_or_tuple)``. 14 Unfortunately every other thing is being ignored (e.g. a == '' would be easy to 15 check for -> a is a string). There's big potential in these checks. 16 """ 17 18 from parso.tree import search_ancestor 19 from parso.python.tree import Name 20 21 from jedi import settings 22 from jedi.inference.arguments import TreeArguments 23 from jedi.inference.value import iterable 24 from jedi.inference.base_value import NO_VALUES 25 from jedi.parser_utils import is_scope 26 27 28 def filter_name(filters, name_or_str): 29 """ 30 Searches names that are defined in a scope (the different 31 ``filters``), until a name fits. 32 """ 33 string_name = name_or_str.value if isinstance(name_or_str, Name) else name_or_str 34 names = [] 35 for filter in filters: 36 names = filter.get(string_name) 37 if names: 38 break 39 40 return list(_remove_del_stmt(names)) 41 42 43 def _remove_del_stmt(names): 44 # Catch del statements and remove them from results. 45 for name in names: 46 if name.tree_name is not None: 47 definition = name.tree_name.get_definition() 48 if definition is not None and definition.type == 'del_stmt': 49 continue 50 yield name 51 52 53 def check_flow_information(value, flow, search_name, pos): 54 """ Try to find out the type of a variable just with the information that 55 is given by the flows: e.g. It is also responsible for assert checks.:: 56 57 if isinstance(k, str): 58 k. # <- completion here 59 60 ensures that `k` is a string. 61 """ 62 if not settings.dynamic_flow_information: 63 return None 64 65 result = None 66 if is_scope(flow): 67 # Check for asserts. 68 module_node = flow.get_root_node() 69 try: 70 names = module_node.get_used_names()[search_name.value] 71 except KeyError: 72 return None 73 names = reversed([ 74 n for n in names 75 if flow.start_pos <= n.start_pos < (pos or flow.end_pos) 76 ]) 77 78 for name in names: 79 ass = search_ancestor(name, 'assert_stmt') 80 if ass is not None: 81 result = _check_isinstance_type(value, ass.assertion, search_name) 82 if result is not None: 83 return result 84 85 if flow.type in ('if_stmt', 'while_stmt'): 86 potential_ifs = [c for c in flow.children[1::4] if c != ':'] 87 for if_test in reversed(potential_ifs): 88 if search_name.start_pos > if_test.end_pos: 89 return _check_isinstance_type(value, if_test, search_name) 90 return result 91 92 93 def _get_isinstance_trailer_arglist(node): 94 if node.type in ('power', 'atom_expr') and len(node.children) == 2: 95 # This might be removed if we analyze and, etc 96 first, trailer = node.children 97 if first.type == 'name' and first.value == 'isinstance' \ 98 and trailer.type == 'trailer' and trailer.children[0] == '(': 99 return trailer 100 return None 101 102 103 def _check_isinstance_type(value, node, search_name): 104 lazy_cls = None 105 trailer = _get_isinstance_trailer_arglist(node) 106 if trailer is not None and len(trailer.children) == 3: 107 arglist = trailer.children[1] 108 args = TreeArguments(value.inference_state, value, arglist, trailer) 109 param_list = list(args.unpack()) 110 # Disallow keyword arguments 111 if len(param_list) == 2 and len(arglist.children) == 3: 112 (key1, _), (key2, lazy_value_cls) = param_list 113 if key1 is None and key2 is None: 114 call = _get_call_string(search_name) 115 is_instance_call = _get_call_string(arglist.children[0]) 116 # Do a simple get_code comparison of the strings . They should 117 # just have the same code, and everything will be all right. 118 # There are ways that this is not correct, if some stuff is 119 # redefined in between. However here we don't care, because 120 # it's a heuristic that works pretty well. 121 if call == is_instance_call: 122 lazy_cls = lazy_value_cls 123 if lazy_cls is None: 124 return None 125 126 value_set = NO_VALUES 127 for cls_or_tup in lazy_cls.infer(): 128 if isinstance(cls_or_tup, iterable.Sequence) and cls_or_tup.array_type == 'tuple': 129 for lazy_value in cls_or_tup.py__iter__(): 130 value_set |= lazy_value.infer().execute_with_values() 131 else: 132 value_set |= cls_or_tup.execute_with_values() 133 return value_set 134 135 136 def _get_call_string(node): 137 if node.parent.type == 'atom_expr': 138 return _get_call_string(node.parent) 139 140 code = '' 141 leaf = node.get_first_leaf() 142 end = node.get_last_leaf().end_pos 143 while leaf.start_pos < end: 144 code += leaf.value 145 leaf = leaf.get_next_leaf() 146 return code 147