def __init__(self, evaluator, tree_module, namespaces, path): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path) self.tree_node = tree_module
def _create(evaluator, obj, parent_context=None, *args): tree_node, path = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_node is None: return compiled_object module_node = tree_node.get_root_node() if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: module_context = ModuleContext(evaluator, module_node, path=path) # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() imports.add_module(evaluator, name, module_context) tree_context = module_context.create_context( tree_node, node_is_context=True, node_is_object=True ) if tree_node.type == 'classdef': if not inspect.isclass(obj): # Is an instance, not a class. tree_context, = tree_context.execute_evaluated() return MixedObject( evaluator, parent_context, compiled_object, tree_context=tree_context )
def _create(evaluator, access_handle, parent_context, *args): compiled_object = create_cached_compiled_object( evaluator, access_handle, parent_context=parent_context and parent_context.compiled_object) # TODO accessing this is bad, but it probably doesn't matter that much, # because we're working with interpreteters only here. python_object = access_handle.access._obj result = _find_syntax_node_name(evaluator, python_object) if result is None: # TODO Care about generics from stuff like `[1]` and don't return like this. if type(python_object) in (dict, list, tuple): return ContextSet({compiled_object}) tree_contexts = to_stub(compiled_object) if not tree_contexts: return ContextSet({compiled_object}) else: module_node, tree_node, file_io, code_lines = result if parent_context is None: # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() string_names = tuple(name.split('.')) module_context = ModuleContext( evaluator, module_node, file_io=file_io, string_names=string_names, code_lines=code_lines, is_package=hasattr(compiled_object, 'py__path__'), ) if name is not None: evaluator.module_cache.add(string_names, ContextSet([module_context])) else: if parent_context.tree_node.get_root_node() != module_node: # This happens e.g. when __module__ is wrong, or when using # TypeVar('foo'), where Jedi uses 'foo' as the name and # Python's TypeVar('foo').__module__ will be typing. return ContextSet({compiled_object}) module_context = parent_context.get_root_context() tree_contexts = ContextSet({ module_context.create_context(tree_node, node_is_context=True, node_is_object=True) }) if tree_node.type == 'classdef': if not access_handle.is_class(): # Is an instance, not a class. tree_contexts = tree_contexts.execute_evaluated() return ContextSet( MixedObject(compiled_object, tree_context=tree_context) for tree_context in tree_contexts)
def py__getitem__(context, typ, node): if not typ.get_root_context().name.string_name == "typing": return None # we assume that any class using [] in a module called # "typing" with a name for which we have a replacement # should be replaced by that class. This is not 100% # airtight but I don't have a better idea to check that it's # actually the PEP-0484 typing module and not some other if node.type == "subscriptlist": nodes = node.children[::2] # skip the commas else: nodes = [node] del node nodes = [_fix_forward_reference(context, node) for node in nodes] type_name = typ.name.string_name # hacked in Union and Optional, since it's hard to do nicely in parsed code if type_name in ("Union", '_Union'): # In Python 3.6 it's still called typing.Union but it's an instance # called _Union. return ContextSet.from_sets(context.eval_node(node) for node in nodes) if type_name in ("Optional", '_Optional'): # Here we have the same issue like in Union. Therefore we also need to # check for the instance typing._Optional (Python 3.6). return context.eval_node(nodes[0]) module_node, code_lines = _get_typing_replacement_module(context.evaluator.latest_grammar) typing = ModuleContext( context.evaluator, module_node=module_node, path=None, code_lines=code_lines, ) factories = typing.py__getattribute__("factory") assert len(factories) == 1 factory = list(factories)[0] assert factory function_body_nodes = factory.tree_node.children[4].children valid_classnames = set(child.name.value for child in function_body_nodes if isinstance(child, tree.Class)) if type_name not in valid_classnames: return None compiled_classname = compiled.create_simple_object(context.evaluator, type_name) from jedi.evaluate.context.iterable import FakeSequence args = FakeSequence( context.evaluator, u'tuple', [LazyTreeContext(context, n) for n in nodes] ) result = factory.execute_evaluated(compiled_classname, args) return result
def py__getitem__(context, typ, node): if not typ.get_root_context().name.string_name == "typing": return None # we assume that any class using [] in a module called # "typing" with a name for which we have a replacement # should be replaced by that class. This is not 100% # airtight but I don't have a better idea to check that it's # actually the PEP-0484 typing module and not some other if node.type == "subscriptlist": nodes = node.children[::2] # skip the commas else: nodes = [node] del node nodes = [_fix_forward_reference(context, node) for node in nodes] type_name = typ.name.string_name # hacked in Union and Optional, since it's hard to do nicely in parsed code if type_name in ("Union", '_Union'): # In Python 3.6 it's still called typing.Union but it's an instance # called _Union. return ContextSet.from_sets(context.eval_node(node) for node in nodes) if type_name in ("Optional", '_Optional'): # Here we have the same issue like in Union. Therefore we also need to # check for the instance typing._Optional (Python 3.6). return context.eval_node(nodes[0]) module_node, code_lines = _get_typing_replacement_module(context.evaluator.latest_grammar) typing = ModuleContext( context.evaluator, module_node=module_node, path=None, code_lines=code_lines, ) factories = typing.py__getattribute__("factory") assert len(factories) == 1 factory = list(factories)[0] assert factory function_body_nodes = factory.tree_node.children[4].children valid_classnames = set(child.name.value for child in function_body_nodes if isinstance(child, tree.Class)) if type_name not in valid_classnames: return None compiled_classname = compiled.create_simple_object(context.evaluator, type_name) from jedi.evaluate.context.iterable import FakeSequence args = FakeSequence( context.evaluator, u'tuple', [LazyTreeContext(context, n) for n in nodes] ) result = factory.execute_evaluated(compiled_classname, args) return result
def __init__(self, evaluator, tree_module, namespaces, path, code_lines): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path, string_names=('__main__', ), code_lines=code_lines) self.tree_node = tree_module
def collections_namedtuple(obj, arguments, callback): """ Implementation of the namedtuple function. This has to be done by processing the namedtuple class template and evaluating the result. """ evaluator = obj.evaluator # Process arguments name = u'jedi_unknown_namedtuple' for c in _follow_param(evaluator, arguments, 0): x = get_str_or_none(c) if x is not None: name = force_unicode(x) break # TODO here we only use one of the types, we should use all. param_contexts = _follow_param(evaluator, arguments, 1) if not param_contexts: return NO_CONTEXTS _fields = list(param_contexts)[0] string = get_str_or_none(_fields) if string is not None: fields = force_unicode(string).replace(',', ' ').split() elif isinstance(_fields, iterable.Sequence): fields = [ force_unicode(get_str_or_none(v)) for lazy_context in _fields.py__iter__() for v in lazy_context.infer() ] fields = [f for f in fields if f is not None] else: return NO_CONTEXTS # Build source code code = _NAMEDTUPLE_CLASS_TEMPLATE.format( typename=name, field_names=tuple(fields), num_fields=len(fields), arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1], repr_fmt='', field_defs='\n'.join( _NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name) for index, name in enumerate(fields))) # Parse source code module = evaluator.grammar.parse(code) generated_class = next(module.iter_classdefs()) parent_context = ModuleContext( evaluator, module, file_io=None, string_names=None, code_lines=parso.split_lines(code, keepends=True), ) return ContextSet( [ClassContext(evaluator, parent_context, generated_class)])
class MixedModuleContext(Context): resets_positions = True type = 'mixed_module' def __init__(self, evaluator, tree_module, namespaces, path): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path) self.tree_node = tree_module def get_node(self): return self.tree_node def get_filters(self, *args, **kwargs): for filter in self._module_context.get_filters(*args, **kwargs): yield filter for namespace_obj in self._namespace_objects: compiled_object = compiled.create(self.evaluator, namespace_obj) mixed_object = mixed.MixedObject(self.evaluator, parent_context=self, compiled_object=compiled_object, tree_context=self._module_context) for filter in mixed_object.get_filters(*args, **kwargs): yield filter def __getattr__(self, name): return getattr(self._module_context, name)
def __init__(self, evaluator, tree_module, namespaces, path): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path) self.tree_node = tree_module
class MixedModuleContext(Context): resets_positions = True type = 'mixed_module' def __init__(self, evaluator, tree_module, namespaces, path): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path) self.tree_node = tree_module def get_node(self): return self.tree_node def get_filters(self, *args, **kwargs): for filter in self._module_context.get_filters(*args, **kwargs): yield filter for namespace_obj in self._namespace_objects: compiled_object = compiled.create(self.evaluator, namespace_obj) mixed_object = mixed.MixedObject( self.evaluator, parent_context=self, compiled_object=compiled_object, tree_context=self._module_context ) for filter in mixed_object.get_filters(*args, **kwargs): yield filter def __getattr__(self, name): return getattr(self._module_context, name)
def collections_namedtuple(evaluator, obj, arguments): """ Implementation of the namedtuple function. This has to be done by processing the namedtuple class template and evaluating the result. """ collections_context = obj.parent_context _class_template_set = collections_context.py__getattribute__( u'_class_template') if not _class_template_set: # Namedtuples are not supported on Python 2.6, early 2.7, because the # _class_template variable is not defined, there. return NO_CONTEXTS # Process arguments # TODO here we only use one of the types, we should use all. # TODO this is buggy, doesn't need to be a string name = list(_follow_param(evaluator, arguments, 0))[0].get_safe_value() _fields = list(_follow_param(evaluator, arguments, 1))[0] if isinstance(_fields, compiled.CompiledObject): fields = _fields.get_safe_value().replace(',', ' ').split() elif isinstance(_fields, iterable.Sequence): fields = [ v.get_safe_value() for lazy_context in _fields.py__iter__() for v in lazy_context.infer() if is_string(v) ] else: return NO_CONTEXTS def get_var(name): x, = collections_context.py__getattribute__(name) return x.get_safe_value() base = next(iter(_class_template_set)).get_safe_value() base += _NAMEDTUPLE_INIT # Build source code code = base.format( typename=name, field_names=tuple(fields), num_fields=len(fields), arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1], repr_fmt=', '.join( get_var(u'_repr_template').format(name=name) for name in fields), field_defs='\n'.join( get_var(u'_field_template').format(index=index, name=name) for index, name in enumerate(fields))) # Parse source code module = evaluator.grammar.parse(code) generated_class = next(module.iter_classdefs()) parent_context = ModuleContext( evaluator, module, None, code_lines=parso.split_lines(code, keepends=True), ) return ContextSet(ClassContext(evaluator, parent_context, generated_class))
def _get_module(self): module = ModuleContext(self._evaluator, self._module_node, self.path) if self.path is not None: name = dotted_path_in_sys_path(self._evaluator.get_sys_path(), self.path) if name is not None: imports.add_module(self._evaluator, name, module) return module
def _load_module(evaluator, path=None, code=None, sys_path=None, import_names=None, safe_module_name=False): if import_names is None: dotted_name = None else: dotted_name = '.'.join(import_names) try: return evaluator.module_cache.get(dotted_name) except KeyError: pass try: return evaluator.module_cache.get_from_path(path) except KeyError: pass if isinstance(path, ImplicitNSInfo): from jedi.evaluate.context.namespace import ImplicitNamespaceContext module = ImplicitNamespaceContext( evaluator, fullname=path.name, paths=path.paths, ) else: if sys_path is None: sys_path = evaluator.get_sys_path() if path is not None and path.endswith(('.py', '.zip', '.egg')): module_node = evaluator.parse(code=code, path=path, cache=True, diff_cache=settings.fast_parser, cache_path=settings.cache_directory) from jedi.evaluate.context import ModuleContext module = ModuleContext( evaluator, module_node, path=path, code_lines=get_cached_code_lines(evaluator.grammar, path), ) else: assert dotted_name is not None module = compiled.load_module(evaluator, dotted_name=dotted_name, sys_path=sys_path) if module is not None and dotted_name is not None: add_module_to_cache(evaluator, dotted_name, module, safe=safe_module_name) return module
def __init__(self, evaluator, tree_module, namespaces, file_io, code_lines): module_context = ModuleContext( evaluator, tree_module, file_io=file_io, string_names=('__main__',), code_lines=code_lines ) super(MixedModuleContext, self).__init__(module_context) self._namespace_objects = [NamespaceObject(n) for n in namespaces]
def _create(evaluator, access_handle, parent_context, *args): compiled_object = create_cached_compiled_object( evaluator, access_handle, parent_context=parent_context and parent_context.compiled_object) result = _find_syntax_node_name(evaluator, access_handle) # TODO use stub contexts here. If we do that we probably have to care about # generics from stuff like `[1]`. if result is None: return compiled_object module_node, tree_node, file_io, code_lines = result if parent_context is None: # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() string_names = tuple(name.split('.')) module_context = ModuleContext( evaluator, module_node, file_io=file_io, string_names=string_names, code_lines=code_lines, is_package=hasattr(compiled_object, 'py__path__'), ) if name is not None: evaluator.module_cache.add(string_names, ContextSet([module_context])) else: assert parent_context.tree_node.get_root_node() == module_node module_context = parent_context.get_root_context() tree_context = module_context.create_context(tree_node, node_is_context=True, node_is_object=True) if tree_node.type == 'classdef': if not access_handle.is_class(): # Is an instance, not a class. tree_context, = execute_evaluated(tree_context) return MixedObject(compiled_object, tree_context=tree_context)
def _create(evaluator, access_handle, parent_context, *args): compiled_object = create_cached_compiled_object( evaluator, access_handle, parent_context=parent_context.compiled_object) result = _find_syntax_node_name(evaluator, access_handle) if result is None: return compiled_object module_node, tree_node, path, code_lines = result if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() string_names = tuple(name.split('.')) module_context = ModuleContext( evaluator, module_node, path=path, string_names=string_names, code_lines=code_lines, is_package=hasattr(compiled_object, 'py__path__'), ) if name is not None: evaluator.module_cache.add(string_names, ContextSet([module_context])) tree_context = module_context.create_context(tree_node, node_is_context=True, node_is_object=True) if tree_node.type == 'classdef': if not access_handle.is_class(): # Is an instance, not a class. tree_context, = execute_evaluated(tree_context) return MixedObject(evaluator, parent_context, compiled_object, tree_context=tree_context)
def check_python_file(path): try: # TODO I don't think we should use the cache here?! node_cache_item = parser_cache[evaluator.grammar._hashed][path] except KeyError: try: return check_fs(path) except IOError: return None else: module_node = node_cache_item.node return ModuleContext(evaluator, module_node, path=path)
def _create(evaluator, access_handle, parent_context, *args): compiled_object = create_cached_compiled_object( evaluator, access_handle, parent_context=parent_context.compiled_object) result = _find_syntax_node_name(evaluator, access_handle) if result is None: return compiled_object module_node, tree_node, path, code_lines = result if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: module_context = ModuleContext( evaluator, module_node, path=path, code_lines=code_lines, ) # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() if name is not None: imports.add_module_to_cache(evaluator, name, module_context) tree_context = module_context.create_context( tree_node, node_is_context=True, node_is_object=True ) if tree_node.type == 'classdef': if not access_handle.is_class(): # Is an instance, not a class. tree_context, = tree_context.execute_evaluated() return MixedObject( evaluator, parent_context, compiled_object, tree_context=tree_context )
def _get_module(self): name = '__main__' if self.path is not None: import_names = dotted_path_in_sys_path(self._evaluator.get_sys_path(), self.path) if import_names is not None: name = '.'.join(import_names) module = ModuleContext( self._evaluator, self._module_node, self.path, code_lines=self._code_lines ) imports.add_module_to_cache(self._evaluator, name, module) return module
def _get_paths_from_buildout_script(evaluator, buildout_script_path): try: module_node = evaluator.parse(path=buildout_script_path, cache=True, cache_path=settings.cache_directory) except IOError: debug.warning('Error trying to read buildout_script: %s', buildout_script_path) return from jedi.evaluate.context import ModuleContext module = ModuleContext(evaluator, module_node, buildout_script_path) for path in check_sys_path_modifications(module): yield path
def collections_namedtuple(evaluator, obj, arguments): """ Implementation of the namedtuple function. This has to be done by processing the namedtuple class template and evaluating the result. .. note:: |jedi| only supports namedtuples on Python >2.6. """ # Namedtuples are not supported on Python 2.6 if not hasattr(collections, '_class_template'): return NO_CONTEXTS # Process arguments # TODO here we only use one of the types, we should use all. id:464 gh:465 name = list(_follow_param(evaluator, arguments, 0))[0].obj _fields = list(_follow_param(evaluator, arguments, 1))[0] if isinstance(_fields, compiled.CompiledObject): fields = _fields.obj.replace(',', ' ').split() elif isinstance(_fields, iterable.AbstractIterable): fields = [ v.obj for lazy_context in _fields.py__iter__() for v in lazy_context.infer() if hasattr(v, 'obj') ] else: return NO_CONTEXTS base = collections._class_template base += _NAMEDTUPLE_INIT # Build source source = base.format( typename=name, field_names=tuple(fields), num_fields=len(fields), arg_list=repr(tuple(fields)).replace("'", "")[1:-1], repr_fmt=', '.join( collections._repr_template.format(name=name) for name in fields), field_defs='\n'.join( collections._field_template.format(index=index, name=name) for index, name in enumerate(fields))) # Parse source module = evaluator.grammar.parse(source) generated_class = next(module.iter_classdefs()) parent_context = ModuleContext(evaluator, module, '') return ContextSet(ClassContext(evaluator, parent_context, generated_class))
def _load_module(evaluator, path=None, code=None, sys_path=None, module_name=None, safe_module_name=False): try: return evaluator.module_cache.get(module_name) except KeyError: pass try: return evaluator.module_cache.get_from_path(path) except KeyError: pass if isinstance(path, ImplicitNSInfo): from jedi.evaluate.context.namespace import ImplicitNamespaceContext module = ImplicitNamespaceContext( evaluator, fullname=path.name, paths=path.paths, ) else: if sys_path is None: sys_path = evaluator.get_sys_path() dotted_path = path and dotted_from_fs_path(path, sys_path) if path is not None and path.endswith(('.py', '.zip', '.egg')) \ and dotted_path not in settings.auto_import_modules: module_node = evaluator.parse(code=code, path=path, cache=True, diff_cache=True, cache_path=settings.cache_directory) from jedi.evaluate.context import ModuleContext module = ModuleContext(evaluator, module_node, path=path) else: module = compiled.load_module(evaluator, path=path, sys_path=sys_path) add_module(evaluator, module_name, module, safe=safe_module_name) return module
def _get_module(self): names = None is_package = False if self.path is not None: import_names, is_p = transform_path_to_dotted( self._evaluator.get_sys_path(add_parent_paths=False), self.path ) if import_names is not None: names = import_names is_package = is_p if self.path is None: file_io = None else: file_io = KnownContentFileIO(cast_path(self.path), self._code) if self.path is not None and self.path.endswith('.pyi'): # We are in a stub file. Try to load the stub properly. stub_module = load_proper_stub_module( self._evaluator, file_io, names, self._module_node ) if stub_module is not None: return stub_module if names is None: names = ('__main__',) module = ModuleContext( self._evaluator, self._module_node, file_io, string_names=names, code_lines=self._code_lines, is_package=is_package, ) if names[0] not in ('builtins', '__builtin__', 'typing'): # These modules are essential for Jedi, so don't overwrite them. self._evaluator.module_cache.add(names, ContextSet([module])) return module
def _load_python_module(evaluator, file_io, sys_path=None, import_names=None, is_package=False): try: return evaluator.module_cache.get_from_path(file_io.path) except KeyError: pass module_node = evaluator.parse( file_io=file_io, cache=True, diff_cache=settings.fast_parser, cache_path=settings.cache_directory ) from jedi.evaluate.context import ModuleContext return ModuleContext( evaluator, module_node, file_io=file_io, string_names=import_names, code_lines=get_cached_code_lines(evaluator.grammar, file_io.path), is_package=is_package, )
def _load_module(evaluator, path=None, code=None, sys_path=None, parent_module=None): if sys_path is None: sys_path = evaluator.project.sys_path dotted_path = path and compiled.dotted_from_fs_path(path, sys_path) if path is not None and path.endswith(('.py', '.zip', '.egg')) \ and dotted_path not in settings.auto_import_modules: module_node = evaluator.parse(code=code, path=path, cache=True, diff_cache=True, cache_path=settings.cache_directory) from jedi.evaluate.context import ModuleContext return ModuleContext(evaluator, module_node, path=path) else: return compiled.load_module(evaluator, path)
def _get_paths_from_buildout_script(evaluator, buildout_script_path): file_io = FileIO(buildout_script_path) try: module_node = evaluator.parse(file_io=file_io, cache=True, cache_path=settings.cache_directory) except IOError: debug.warning('Error trying to read buildout_script: %s', buildout_script_path) return from jedi.evaluate.context import ModuleContext module = ModuleContext( evaluator, module_node, file_io, string_names=None, code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path), ) for path in check_sys_path_modifications(module): yield path
class MixedModuleContext(Context): # TODO use ContextWrapper! type = 'mixed_module' def __init__(self, evaluator, tree_module, namespaces, path, code_lines): self.evaluator = evaluator self._namespaces = namespaces self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._module_context = ModuleContext(evaluator, tree_module, path=path, string_names=('__main__', ), code_lines=code_lines) self.tree_node = tree_module def get_node(self): return self.tree_node def get_filters(self, *args, **kwargs): for filter in self._module_context.get_filters(*args, **kwargs): yield filter for namespace_obj in self._namespace_objects: compiled_object = _create(self.evaluator, namespace_obj) mixed_object = mixed.MixedObject(self.evaluator, parent_context=self, compiled_object=compiled_object, tree_context=self._module_context) for filter in mixed_object.get_filters(*args, **kwargs): yield filter @property def code_lines(self): return self._module_context.code_lines def __getattr__(self, name): return getattr(self._module_context, name)