1 """ 2 Used only for REPL Completion. 3 """ 4 5 import inspect 6 from pathlib import Path 7 8 from jedi.parser_utils import get_cached_code_lines 9 10 from jedi import settings 11 from jedi.cache import memoize_method 12 from jedi.inference import compiled 13 from jedi.file_io import FileIO 14 from jedi.inference.names import NameWrapper 15 from jedi.inference.base_value import ValueSet, ValueWrapper, NO_VALUES 16 from jedi.inference.value import ModuleValue 17 from jedi.inference.cache import inference_state_function_cache, \ 18 inference_state_method_cache 19 from jedi.inference.compiled.access import ALLOWED_GETITEM_TYPES, get_api_type 20 from jedi.inference.gradual.conversion import to_stub 21 from jedi.inference.context import CompiledContext, CompiledModuleContext, \ 22 TreeContextMixin 23 24 _sentinel = object() 25 26 27 class MixedObject(ValueWrapper): 28 """ 29 A ``MixedObject`` is used in two ways: 30 31 1. It uses the default logic of ``parser.python.tree`` objects, 32 2. except for getattr calls and signatures. The names dicts are generated 33 in a fashion like ``CompiledValue``. 34 35 This combined logic makes it possible to provide more powerful REPL 36 completion. It allows side effects that are not noticable with the default 37 parser structure to still be completable. 38 39 The biggest difference from CompiledValue to MixedObject is that we are 40 generally dealing with Python code and not with C code. This will generate 41 fewer special cases, because we in Python you don't have the same freedoms 42 to modify the runtime. 43 """ 44 def __init__(self, compiled_value, tree_value): 45 super().__init__(tree_value) 46 self.compiled_value = compiled_value 47 self.access_handle = compiled_value.access_handle 48 49 def get_filters(self, *args, **kwargs): 50 yield MixedObjectFilter( 51 self.inference_state, self.compiled_value, self._wrapped_value) 52 53 def get_signatures(self): 54 # Prefer `inspect.signature` over somehow analyzing Python code. It 55 # should be very precise, especially for stuff like `partial`. 56 return self.compiled_value.get_signatures() 57 58 @inference_state_method_cache(default=NO_VALUES) 59 def py__call__(self, arguments): 60 # Fallback to the wrapped value if to stub returns no values. 61 values = to_stub(self._wrapped_value) 62 if not values: 63 values = self._wrapped_value 64 return values.py__call__(arguments) 65 66 def get_safe_value(self, default=_sentinel): 67 if default is _sentinel: 68 return self.compiled_value.get_safe_value() 69 else: 70 return self.compiled_value.get_safe_value(default) 71 72 @property 73 def array_type(self): 74 return self.compiled_value.array_type 75 76 def get_key_values(self): 77 return self.compiled_value.get_key_values() 78 79 def py__simple_getitem__(self, index): 80 python_object = self.compiled_value.access_handle.access._obj 81 if type(python_object) in ALLOWED_GETITEM_TYPES: 82 return self.compiled_value.py__simple_getitem__(index) 83 return self._wrapped_value.py__simple_getitem__(index) 84 85 def negate(self): 86 return self.compiled_value.negate() 87 88 def _as_context(self): 89 if self.parent_context is None: 90 return MixedModuleContext(self) 91 return MixedContext(self) 92 93 def __repr__(self): 94 return '<%s: %s; %s>' % ( 95 type(self).__name__, 96 self.access_handle.get_repr(), 97 self._wrapped_value, 98 ) 99 100 101 class MixedContext(CompiledContext, TreeContextMixin): 102 @property 103 def compiled_value(self): 104 return self._value.compiled_value 105 106 107 class MixedModuleContext(CompiledModuleContext, MixedContext): 108 pass 109 110 111 class MixedName(NameWrapper): 112 """ 113 The ``CompiledName._compiled_value`` is our MixedObject. 114 """ 115 def __init__(self, wrapped_name, parent_tree_value): 116 super().__init__(wrapped_name) 117 self._parent_tree_value = parent_tree_value 118 119 @property 120 def start_pos(self): 121 values = list(self.infer()) 122 if not values: 123 # This means a start_pos that doesn't exist (compiled objects). 124 return 0, 0 125 return values[0].name.start_pos 126 127 @memoize_method 128 def infer(self): 129 compiled_value = self._wrapped_name.infer_compiled_value() 130 tree_value = self._parent_tree_value 131 if tree_value.is_instance() or tree_value.is_class(): 132 tree_values = tree_value.py__getattribute__(self.string_name) 133 if compiled_value.is_function(): 134 return ValueSet({MixedObject(compiled_value, v) for v in tree_values}) 135 136 module_context = tree_value.get_root_context() 137 return _create(self._inference_state, compiled_value, module_context) 138 139 140 class MixedObjectFilter(compiled.CompiledValueFilter): 141 def __init__(self, inference_state, compiled_value, tree_value): 142 super().__init__(inference_state, compiled_value) 143 self._tree_value = tree_value 144 145 def _create_name(self, *args, **kwargs): 146 return MixedName( 147 super()._create_name(*args, **kwargs), 148 self._tree_value, 149 ) 150 151 152 @inference_state_function_cache() 153 def _load_module(inference_state, path): 154 return inference_state.parse( 155 path=path, 156 cache=True, 157 diff_cache=settings.fast_parser, 158 cache_path=settings.cache_directory 159 ).get_root_node() 160 161 162 def _get_object_to_check(python_object): 163 """Check if inspect.getfile has a chance to find the source.""" 164 try: 165 python_object = inspect.unwrap(python_object) 166 except ValueError: 167 # Can return a ValueError when it wraps around 168 pass 169 170 if (inspect.ismodule(python_object) 171 or inspect.isclass(python_object) 172 or inspect.ismethod(python_object) 173 or inspect.isfunction(python_object) 174 or inspect.istraceback(python_object) 175 or inspect.isframe(python_object) 176 or inspect.iscode(python_object)): 177 return python_object 178 179 try: 180 return python_object.__class__ 181 except AttributeError: 182 raise TypeError # Prevents computation of `repr` within inspect. 183 184 185 def _find_syntax_node_name(inference_state, python_object): 186 original_object = python_object 187 try: 188 python_object = _get_object_to_check(python_object) 189 path = inspect.getsourcefile(python_object) 190 except (OSError, TypeError): 191 # The type might not be known (e.g. class_with_dict.__weakref__) 192 return None 193 path = None if path is None else Path(path) 194 try: 195 if path is None or not path.exists(): 196 # The path might not exist or be e.g. <stdin>. 197 return None 198 except OSError: 199 # Might raise an OSError on Windows: 200 # 201 # [WinError 123] The filename, directory name, or volume label 202 # syntax is incorrect: '<string>' 203 return None 204 205 file_io = FileIO(path) 206 module_node = _load_module(inference_state, path) 207 208 if inspect.ismodule(python_object): 209 # We don't need to check names for modules, because there's not really 210 # a way to write a module in a module in Python (and also __name__ can 211 # be something like ``email.utils``). 212 code_lines = get_cached_code_lines(inference_state.grammar, path) 213 return module_node, module_node, file_io, code_lines 214 215 try: 216 name_str = python_object.__name__ 217 except AttributeError: 218 # Stuff like python_function.__code__. 219 return None 220 221 if name_str == '<lambda>': 222 return None # It's too hard to find lambdas. 223 224 # Doesn't always work (e.g. os.stat_result) 225 names = module_node.get_used_names().get(name_str, []) 226 # Only functions and classes are relevant. If a name e.g. points to an 227 # import, it's probably a builtin (like collections.deque) and needs to be 228 # ignored. 229 names = [ 230 n for n in names 231 if n.parent.type in ('funcdef', 'classdef') and n.parent.name == n 232 ] 233 if not names: 234 return None 235 236 try: 237 code = python_object.__code__ 238 # By using the line number of a code object we make the lookup in a 239 # file pretty easy. There's still a possibility of people defining 240 # stuff like ``a = 3; foo(a); a = 4`` on the same line, but if people 241 # do so we just don't care. 242 line_nr = code.co_firstlineno 243 except AttributeError: 244 pass 245 else: 246 line_names = [name for name in names if name.start_pos[0] == line_nr] 247 # There's a chance that the object is not available anymore, because 248 # the code has changed in the background. 249 if line_names: 250 names = line_names 251 252 code_lines = get_cached_code_lines(inference_state.grammar, path) 253 # It's really hard to actually get the right definition, here as a last 254 # resort we just return the last one. This chance might lead to odd 255 # completions at some points but will lead to mostly correct type 256 # inference, because people tend to define a public name in a module only 257 # once. 258 tree_node = names[-1].parent 259 if tree_node.type == 'funcdef' and get_api_type(original_object) == 'instance': 260 # If an instance is given and we're landing on a function (e.g. 261 # partial in 3.5), something is completely wrong and we should not 262 # return that. 263 return None 264 return module_node, tree_node, file_io, code_lines 265 266 267 @inference_state_function_cache() 268 def _create(inference_state, compiled_value, module_context): 269 # TODO accessing this is bad, but it probably doesn't matter that much, 270 # because we're working with interpreters only here. 271 python_object = compiled_value.access_handle.access._obj 272 result = _find_syntax_node_name(inference_state, python_object) 273 if result is None: 274 # TODO Care about generics from stuff like `[1]` and don't return like this. 275 if type(python_object) in (dict, list, tuple): 276 return ValueSet({compiled_value}) 277 278 tree_values = to_stub(compiled_value) 279 if not tree_values: 280 return ValueSet({compiled_value}) 281 else: 282 module_node, tree_node, file_io, code_lines = result 283 284 if module_context is None or module_context.tree_node != module_node: 285 root_compiled_value = compiled_value.get_root_context().get_value() 286 # TODO this __name__ might be wrong. 287 name = root_compiled_value.py__name__() 288 string_names = tuple(name.split('.')) 289 module_value = ModuleValue( 290 inference_state, module_node, 291 file_io=file_io, 292 string_names=string_names, 293 code_lines=code_lines, 294 is_package=root_compiled_value.is_package(), 295 ) 296 if name is not None: 297 inference_state.module_cache.add(string_names, ValueSet([module_value])) 298 module_context = module_value.as_context() 299 300 tree_values = ValueSet({module_context.create_value(tree_node)}) 301 if tree_node.type == 'classdef': 302 if not compiled_value.is_class(): 303 # Is an instance, not a class. 304 tree_values = tree_values.execute_with_values() 305 306 return ValueSet( 307 MixedObject(compiled_value, tree_value=tree_value) 308 for tree_value in tree_values 309 ) 310