diff --git a/jedi/api/environment.py b/jedi/api/environment.py index f34e9a26..9d095bad 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -66,7 +66,7 @@ class InterpreterEnvironment(_BaseEnvironment): return EvaluatorSameProcess(evaluator) def get_sys_path(self): - return sys.sys_path + return sys.path def get_default_environment(): diff --git a/jedi/evaluate/project.py b/jedi/evaluate/project.py index 6f6a15e7..80d618f5 100644 --- a/jedi/evaluate/project.py +++ b/jedi/evaluate/project.py @@ -1,7 +1,4 @@ -import os -import sys - -from jedi.evaluate.sys_path import get_venv_path, detect_additional_paths +from jedi.evaluate.sys_path import detect_additional_paths from jedi.cache import memoize_method @@ -9,23 +6,7 @@ class Project(object): def __init__(self, sys_path=None): self._script_path = None - if sys_path is not None: - self._base_sys_path = sys_path - - if sys_path is None: - venv = os.getenv('VIRTUAL_ENV') - if venv: - sys_path = get_venv_path(venv) - else: - sys_path = sys.path - - base_sys_path = list(sys_path) - try: - base_sys_path.remove('') - except ValueError: - pass - - self._base_sys_path = base_sys_path + self._base_sys_path = sys_path def add_script_path(self, script_path): self._script_path = script_path @@ -36,7 +17,17 @@ class Project(object): @property @memoize_method def sys_path(self): - if self._script_path is None: - return self._base_sys_path + sys_path = self._base_sys_path + if sys_path is None: + sys_path = self._evaluator.environment.get_sys_path() - return self._base_sys_path + detect_additional_paths(self._evaluator, self._script_path) + sys_path = list(sys_path) + try: + sys_path.remove('') + except ValueError: + pass + + if self._script_path is None: + return sys_path + + return sys_path + detect_additional_paths(self._evaluator, self._script_path) diff --git a/jedi/evaluate/site.py b/jedi/evaluate/site.py deleted file mode 100644 index bf884fae..00000000 --- a/jedi/evaluate/site.py +++ /dev/null @@ -1,110 +0,0 @@ -"""An adapted copy of relevant site-packages functionality from Python stdlib. - -This file contains some functions related to handling site-packages in Python -with jedi-specific modifications: - -- the functions operate on sys_path argument rather than global sys.path - -- in .pth files "import ..." lines that allow execution of arbitrary code are - skipped to prevent code injection into jedi interpreter - -""" - -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013, 2014, 2015 Python Software Foundation; All Rights Reserved - -from __future__ import print_function - -import sys -import os - - -def makepath(*paths): - dir = os.path.join(*paths) - try: - dir = os.path.abspath(dir) - except OSError: - pass - return dir, os.path.normcase(dir) - - -def _init_pathinfo(sys_path): - """Return a set containing all existing directory entries from sys_path""" - d = set() - for dir in sys_path: - try: - if os.path.isdir(dir): - dir, dircase = makepath(dir) - d.add(dircase) - except TypeError: - continue - return d - - -def addpackage(sys_path, sitedir, name, known_paths): - """Process a .pth file within the site-packages directory: - For each line in the file, either combine it with sitedir to a path - and add that to known_paths, or execute it if it starts with 'import '. - """ - if known_paths is None: - known_paths = _init_pathinfo(sys_path) - reset = 1 - else: - reset = 0 - fullname = os.path.join(sitedir, name) - try: - f = open(fullname, "r") - except OSError: - return - with f: - for n, line in enumerate(f): - if line.startswith("#"): - continue - try: - if line.startswith(("import ", "import\t")): - # Change by immerrr: don't evaluate import lines to prevent - # code injection into jedi through pth files. - # - # exec(line) - continue - line = line.rstrip() - dir, dircase = makepath(sitedir, line) - if not dircase in known_paths and os.path.exists(dir): - sys_path.append(dir) - known_paths.add(dircase) - except Exception: - print("Error processing line {:d} of {}:\n".format(n+1, fullname), - file=sys.stderr) - import traceback - for record in traceback.format_exception(*sys.exc_info()): - for line in record.splitlines(): - print(' '+line, file=sys.stderr) - print("\nRemainder of file ignored", file=sys.stderr) - break - if reset: - known_paths = None - return known_paths - - -def addsitedir(sys_path, sitedir, known_paths=None): - """Add 'sitedir' argument to sys_path if missing and handle .pth files in - 'sitedir'""" - if known_paths is None: - known_paths = _init_pathinfo(sys_path) - reset = 1 - else: - reset = 0 - sitedir, sitedircase = makepath(sitedir) - if not sitedircase in known_paths: - sys_path.append(sitedir) # Add path component - known_paths.add(sitedircase) - try: - names = os.listdir(sitedir) - except OSError: - return - names = [name for name in names if name.endswith(".pth")] - for name in sorted(names): - addpackage(sys_path, sitedir, name, known_paths) - if reset: - known_paths = None - return known_paths diff --git a/jedi/evaluate/sys_path.py b/jedi/evaluate/sys_path.py index 8110c33d..11728430 100644 --- a/jedi/evaluate/sys_path.py +++ b/jedi/evaluate/sys_path.py @@ -1,8 +1,5 @@ -import glob import os -import sys import imp -from jedi.evaluate.site import addsitedir from jedi._compatibility import unicode from jedi.evaluate.cache import evaluator_method_cache @@ -13,62 +10,6 @@ from jedi import debug from jedi.evaluate.utils import ignored -def get_venv_path(venv): - """Get sys.path for specified virtual environment.""" - sys_path = _get_venv_path_dirs(venv) - with ignored(ValueError): - sys_path.remove('') - sys_path = _get_sys_path_with_egglinks(sys_path) - # As of now, get_venv_path_dirs does not scan built-in pythonpath and - # user-local site-packages, let's approximate them using path from Jedi - # interpreter. - return sys_path + sys.path - - -def _get_sys_path_with_egglinks(sys_path): - """Find all paths including those referenced by egg-links. - - Egg-link-referenced directories are inserted into path immediately before - the directory on which their links were found. Such directories are not - taken into consideration by normal import mechanism, but they are traversed - when doing pkg_resources.require. - """ - result = [] - for p in sys_path: - # pkg_resources does not define a specific order for egg-link files - # using os.listdir to enumerate them, we're sorting them to have - # reproducible tests. - for egg_link in sorted(glob.glob(os.path.join(p, '*.egg-link'))): - with open(egg_link) as fd: - for line in fd: - line = line.strip() - if line: - result.append(os.path.join(p, line)) - # pkg_resources package only interprets the first - # non-empty line in egg-link files. - break - result.append(p) - return result - - -def _get_venv_path_dirs(venv): - """Get sys.path for venv without starting up the interpreter.""" - venv = os.path.abspath(venv) - sitedir = _get_venv_sitepackages(venv) - sys_path = [] - addsitedir(sys_path, sitedir) - return sys_path - - -def _get_venv_sitepackages(venv): - if os.name == 'nt': - p = os.path.join(venv, 'lib', 'site-packages') - else: - p = os.path.join(venv, 'lib', 'python%d.%d' % sys.version_info[:2], - 'site-packages') - return p - - def _abs_path(module_context, path): module_path = module_context.py__file__() if os.path.isabs(path): @@ -87,7 +28,7 @@ def _paths_from_assignment(module_context, expr_stmt): """ Extracts the assigned strings from an assignment that looks as follows:: - >>> sys.path[0:0] = ['module/path', 'another/module/path'] + sys.path[0:0] = ['module/path', 'another/module/path'] This function is in general pretty tolerant (and therefore 'buggy'). However, it's not a big issue usually to add more paths to Jedi's sys_path,