Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
    def _do_import(self, import_path, sys_path):
        """
        This method is very similar to importlib's `_gcd_import`.
        """
        import_parts = [
            i.value if isinstance(i, tree.Name) else i for i in import_path
        ]

        # Handle "magic" Flask extension imports:
        # ``flask.ext.foo`` is really ``flask_foo`` or ``flaskext.foo``.
        if len(import_path) > 2 and import_parts[:2] == ['flask', 'ext']:
            # New style.
            ipath = ('flask_' + str(import_parts[2]), ) + import_path[3:]
            modules = self._do_import(ipath, sys_path)
            if modules:
                return modules
            else:
                # Old style
                return self._do_import(('flaskext', ) + import_path[2:],
                                       sys_path)

        module_name = '.'.join(import_parts)
        try:
            return ContextSet(self._evaluator.modules[module_name])
        except KeyError:
            pass

        if len(import_path) > 1:
            # This is a recursive way of importing that works great with
            # the module cache.
            bases = self._do_import(import_path[:-1], sys_path)
            if not bases:
                return NO_CONTEXTS
            # We can take the first element, because only the os special
            # case yields multiple modules, which is not important for
            # further imports.
            parent_module = list(bases)[0]

            # This is a huge exception, we follow a nested import
            # ``os.path``, because it's a very important one in Python
            # that is being achieved by messing with ``sys.modules`` in
            # ``os``.
            if import_parts == ['os', 'path']:
                return parent_module.py__getattribute__('path')

            try:
                method = parent_module.py__path__
            except AttributeError:
                # The module is not a package.
                _add_error(self.module_context, import_path[-1])
                return NO_CONTEXTS
            else:
                paths = method()
                debug.dbg('search_module %s in paths %s', module_name, paths)
                for path in paths:
                    # At the moment we are only using one path. So this is
                    # not important to be correct.
                    try:
                        if not isinstance(path, list):
                            path = [path]
                        module_file, module_path, is_pkg = \
                            find_module(import_parts[-1], path, fullname=module_name)
                        break
                    except ImportError:
                        module_path = None
                if module_path is None:
                    _add_error(self.module_context, import_path[-1])
                    return NO_CONTEXTS
        else:
            parent_module = None
            try:
                debug.dbg('search_module %s in %s', import_parts[-1],
                          self.file_path)
                # Override the sys.path. It works only good that way.
                # Injecting the path directly into `find_module` did not work.
                sys.path, temp = sys_path, sys.path
                try:
                    module_file, module_path, is_pkg = \
                        find_module(import_parts[-1], fullname=module_name)
                finally:
                    sys.path = temp
            except ImportError:
                # The module is not a package.
                _add_error(self.module_context, import_path[-1])
                return NO_CONTEXTS

        code = None
        if is_pkg:
            # In this case, we don't have a file yet. Search for the
            # __init__ file.
            if module_path.endswith(('.zip', '.egg')):
                code = module_file.loader.get_source(module_name)
            else:
                module_path = get_init_path(module_path)
        elif module_file:
            if module_path.endswith(('.zip', '.egg')):
                # Unfortunately we are reading unicode here already, not byes.
                # It seems however hard to get bytes, because the zip importer
                # logic just unpacks the zip file and returns a file descriptor
                # that we cannot as easily access. Therefore we just read it as
                # a string.
                code = module_file.read()
            else:
                # Read the code with a binary file, because the binary file
                # might not be proper unicode. This is handled by the parser
                # wrapper.
                with open(module_path, 'rb') as f:
                    code = f.read()
            module_file.close()

        if isinstance(module_path, ImplicitNSInfo):
            from jedi.evaluate.context.namespace import ImplicitNamespaceContext
            fullname, paths = module_path.name, module_path.paths
            module = ImplicitNamespaceContext(self._evaluator,
                                              fullname=fullname)
            module.paths = paths
        elif module_file is None and not module_path.endswith(
            ('.py', '.zip', '.egg')):
            module = compiled.load_module(self._evaluator, module_path)
        else:
            module = _load_module(self._evaluator, module_path, code, sys_path,
                                  parent_module)

        if module is None:
            # The file might raise an ImportError e.g. and therefore not be
            # importable.
            return NO_CONTEXTS

        self._evaluator.modules[module_name] = module
        return ContextSet(module)
Beispiel #4
0
    def _do_import(self, import_path, sys_path):
        """
        This method is very similar to importlib's `_gcd_import`.
        """
        import_parts = [
            force_unicode(i.value if isinstance(i, tree.Name) else i)
            for i in import_path
        ]

        # Handle "magic" Flask extension imports:
        # ``flask.ext.foo`` is really ``flask_foo`` or ``flaskext.foo``.
        if len(import_path) > 2 and import_parts[:2] == ['flask', 'ext']:
            # New style.
            ipath = ('flask_' + str(import_parts[2]), ) + import_path[3:]
            modules = self._do_import(ipath, sys_path)
            if modules:
                return modules
            else:
                # Old style
                return self._do_import(('flaskext', ) + import_path[2:],
                                       sys_path)

        module_name = '.'.join(import_parts)
        try:
            return ContextSet(self._evaluator.modules[module_name])
        except KeyError:
            pass

        if len(import_path) > 1:
            # This is a recursive way of importing that works great with
            # the module cache.
            bases = self._do_import(import_path[:-1], sys_path)
            if not bases:
                return NO_CONTEXTS
            # We can take the first element, because only the os special
            # case yields multiple modules, which is not important for
            # further imports.
            parent_module = list(bases)[0]

            # This is a huge exception, we follow a nested import
            # ``os.path``, because it's a very important one in Python
            # that is being achieved by messing with ``sys.modules`` in
            # ``os``.
            if import_parts == ['os', 'path']:
                return parent_module.py__getattribute__('path')

            try:
                method = parent_module.py__path__
            except AttributeError:
                # The module is not a package.
                _add_error(self.module_context, import_path[-1])
                return NO_CONTEXTS
            else:
                paths = method()
                debug.dbg('search_module %s in paths %s', module_name, paths)
                for path in paths:
                    # At the moment we are only using one path. So this is
                    # not important to be correct.
                    if not isinstance(path, list):
                        path = [path]
                    code, module_path, is_pkg = self._evaluator.compiled_subprocess.get_module_info(
                        string=import_parts[-1],
                        path=path,
                        full_name=module_name)
                    if module_path is not None:
                        break
                else:
                    _add_error(self.module_context, import_path[-1])
                    return NO_CONTEXTS
        else:
            parent_module = None
            debug.dbg('search_module %s in %s', import_parts[-1],
                      self.file_path)
            # Override the sys.path. It works only good that way.
            # Injecting the path directly into `find_module` did not work.
            code, module_path, is_pkg = self._evaluator.compiled_subprocess.get_module_info(
                string=import_parts[-1],
                full_name=module_name,
                sys_path=sys_path,
            )
            if module_path is None:
                # The module is not a package.
                _add_error(self.module_context, import_path[-1])
                return NO_CONTEXTS

        if isinstance(module_path, ImplicitNSInfo):
            from jedi.evaluate.context.namespace import ImplicitNamespaceContext
            module = ImplicitNamespaceContext(
                self._evaluator,
                fullname=module_path.name,
                paths=module_path.paths,
            )
        elif code is not None or module_path.endswith(('.py', '.zip', '.egg')):
            module = _load_module(self._evaluator, module_path, code, sys_path,
                                  parent_module)
        else:
            module = compiled.load_module(self._evaluator,
                                          path=module_path,
                                          sys_path=sys_path)

        if module is None:
            # The file might raise an ImportError e.g. and therefore not be
            # importable.
            return NO_CONTEXTS

        self._evaluator.modules[module_name] = module
        return ContextSet(module)
Beispiel #5
0
def import_module(evaluator, import_names, parent_module_context, sys_path):
    """
    This method is very similar to importlib's `_gcd_import`.
    """
    if import_names[0] in settings.auto_import_modules:
        module = _load_builtin_module(evaluator, import_names, sys_path)
        if module is None:
            return NO_CONTEXTS
        return ContextSet([module])

    module_name = '.'.join(import_names)
    if parent_module_context is None:
        # Override the sys.path. It works only good that way.
        # Injecting the path directly into `find_module` did not work.
        file_io_or_ns, is_pkg = evaluator.compiled_subprocess.get_module_info(
            string=import_names[-1],
            full_name=module_name,
            sys_path=sys_path,
            is_global_search=True,
        )
        if is_pkg is None:
            return NO_CONTEXTS
    else:
        try:
            method = parent_module_context.py__path__
        except AttributeError:
            # The module is not a package.
            return NO_CONTEXTS
        else:
            paths = method()
            for path in paths:
                # At the moment we are only using one path. So this is
                # not important to be correct.
                if not isinstance(path, list):
                    path = [path]
                file_io_or_ns, is_pkg = evaluator.compiled_subprocess.get_module_info(
                    string=import_names[-1],
                    path=path,
                    full_name=module_name,
                    is_global_search=False,
                )
                if is_pkg is not None:
                    break
            else:
                return NO_CONTEXTS

    if isinstance(file_io_or_ns, ImplicitNSInfo):
        from jedi.evaluate.context.namespace import ImplicitNamespaceContext
        module = ImplicitNamespaceContext(
            evaluator,
            fullname=file_io_or_ns.name,
            paths=file_io_or_ns.paths,
        )
    elif file_io_or_ns is None:
        module = _load_builtin_module(evaluator, import_names, sys_path)
        if module is None:
            return NO_CONTEXTS
    else:
        module = _load_python_module(
            evaluator, file_io_or_ns, sys_path,
            import_names=import_names,
            is_package=is_pkg,
        )

    if parent_module_context is None:
        debug.dbg('global search_module %s: %s', import_names[-1], module)
    else:
        debug.dbg('search_module %s in paths %s: %s', module_name, paths, module)
    return ContextSet([module])