forked from VimPlug/jedi
Refactor django path support
This commit is contained in:
@@ -14,6 +14,7 @@ collect_ignore = [
|
||||
'__main__.py',
|
||||
'jedi/evaluate/compiled/subprocess/__main__.py',
|
||||
'build/',
|
||||
'test/examples',
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -264,6 +264,11 @@ try:
|
||||
except NameError:
|
||||
FileNotFoundError = IOError
|
||||
|
||||
try:
|
||||
NotADirectoryError = NotADirectoryError
|
||||
except NameError:
|
||||
NotADirectoryError = IOError
|
||||
|
||||
|
||||
def no_unicode_pprint(dct):
|
||||
"""
|
||||
|
||||
@@ -101,7 +101,7 @@ class Script(object):
|
||||
sys_path = list(map(force_unicode, sys_path))
|
||||
|
||||
# Load the Python grammar of the current interpreter.
|
||||
project = get_default_project()
|
||||
project = get_default_project(path or os.getcwd())
|
||||
# TODO deprecate and remove sys_path from the Script API.
|
||||
if sys_path is not None:
|
||||
project._sys_path = sys_path
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from jedi._compatibility import FileNotFoundError
|
||||
from jedi._compatibility import FileNotFoundError, NotADirectoryError
|
||||
from jedi.api.environment import DefaultEnvironment, \
|
||||
get_default_environment, from_executable
|
||||
from jedi.api.exceptions import WrongVersion
|
||||
from jedi._compatibility import force_unicode
|
||||
from jedi.evaluate.sys_path import detect_additional_paths
|
||||
from jedi.evaluate.cache import evaluator_as_method_param_cache
|
||||
from jedi.evaluate.sys_path import traverse_parents
|
||||
|
||||
_CONFIG_FOLDER = '.jedi'
|
||||
_CONTAINS_POTENTIAL_PROJECT = 'setup.py', '.git', '.hg', 'MANIFEST.in'
|
||||
@@ -54,7 +55,8 @@ class Project(object):
|
||||
rely on your packages being properly configured on the
|
||||
``sys.path``.
|
||||
"""
|
||||
def py2_comp(path, environment=None, sys_path=None, smart_sys_path=True):
|
||||
def py2_comp(path, environment=None, sys_path=None,
|
||||
smart_sys_path=True, _django=False):
|
||||
self._path = path
|
||||
if isinstance(environment, DefaultEnvironment):
|
||||
self._environment = environment
|
||||
@@ -62,6 +64,7 @@ class Project(object):
|
||||
|
||||
self._sys_path = sys_path
|
||||
self._smart_sys_path = smart_sys_path
|
||||
self._django = _django
|
||||
|
||||
py2_comp(path, **kwargs)
|
||||
|
||||
@@ -90,11 +93,15 @@ class Project(object):
|
||||
if evaluator.script_path is None or not self._smart_sys_path:
|
||||
return sys_path
|
||||
|
||||
prefixed = []
|
||||
if self._smart_sys_path:
|
||||
if self._django:
|
||||
prefixed.append(self._path)
|
||||
added_paths = map(
|
||||
force_unicode,
|
||||
detect_additional_paths(evaluator, evaluator.script_path)
|
||||
)
|
||||
return sys_path + list(added_paths)
|
||||
return prefixed + sys_path + list(added_paths)
|
||||
|
||||
def save(self):
|
||||
data = dict(self.__dict__)
|
||||
@@ -121,26 +128,38 @@ def _is_potential_project(path):
|
||||
return False
|
||||
|
||||
|
||||
def _is_django_path(directory):
|
||||
""" Detects the path of the very well known Django library (if used) """
|
||||
try:
|
||||
with open(os.path.join(directory, 'manage.py'), 'br') as f:
|
||||
return b"DJANGO_SETTINGS_MODULE" in f.read()
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_default_project(path=None):
|
||||
if path is None:
|
||||
path = os.getcwd()
|
||||
|
||||
previous = None
|
||||
curdir = dir = os.path.realpath(path)
|
||||
check = os.path.realpath(path)
|
||||
probable_path = None
|
||||
while dir != previous:
|
||||
for dir in traverse_parents(check, include_current=True):
|
||||
try:
|
||||
return Project.load(dir)
|
||||
except FileNotFoundError:
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
pass
|
||||
|
||||
if _is_django_path(dir):
|
||||
return Project(dir, _django=True)
|
||||
|
||||
if probable_path is None and _is_potential_project(dir):
|
||||
probable_path = dir
|
||||
|
||||
previous = dir
|
||||
dir = os.path.dirname(dir)
|
||||
else:
|
||||
if probable_path is not None:
|
||||
# TODO search for setup.py etc
|
||||
return Project(probable_path)
|
||||
return Project(curdir)
|
||||
if probable_path is not None:
|
||||
# TODO search for setup.py etc
|
||||
return Project(probable_path)
|
||||
|
||||
curdir = path if os.path.isdir(path) else os.path.dirname(path)
|
||||
return Project(curdir)
|
||||
|
||||
@@ -134,14 +134,13 @@ def sys_path_with_modifications(evaluator, module_context):
|
||||
|
||||
|
||||
def detect_additional_paths(evaluator, script_path):
|
||||
django_paths = _detect_django_path(script_path)
|
||||
buildout_script_paths = set()
|
||||
|
||||
for buildout_script_path in _get_buildout_script_paths(script_path):
|
||||
for path in _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
||||
buildout_script_paths.add(path)
|
||||
|
||||
return django_paths + list(buildout_script_paths)
|
||||
return list(buildout_script_paths)
|
||||
|
||||
|
||||
def _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
||||
@@ -161,13 +160,15 @@ def _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
||||
yield path
|
||||
|
||||
|
||||
def traverse_parents(path):
|
||||
while True:
|
||||
new = os.path.dirname(path)
|
||||
if new == path:
|
||||
return
|
||||
path = new
|
||||
def traverse_parents(path, include_current=False):
|
||||
if not include_current:
|
||||
path = os.path.dirname(path)
|
||||
|
||||
previous = None
|
||||
while previous != path:
|
||||
yield path
|
||||
previous = path
|
||||
path = os.path.dirname(path)
|
||||
|
||||
|
||||
def _get_parent_dir_with_file(path, filename):
|
||||
@@ -177,18 +178,6 @@ def _get_parent_dir_with_file(path, filename):
|
||||
return None
|
||||
|
||||
|
||||
def _detect_django_path(module_path):
|
||||
""" Detects the path of the very well known Django library (if used) """
|
||||
result = []
|
||||
|
||||
for parent in traverse_parents(module_path):
|
||||
with ignored(IOError):
|
||||
with open(parent + os.path.sep + 'manage.py'):
|
||||
debug.dbg('Found django path: %s', module_path)
|
||||
result.append(parent)
|
||||
return result
|
||||
|
||||
|
||||
def _get_buildout_script_paths(module_path):
|
||||
"""
|
||||
if there is a 'buildout.cfg' file in one of the parent directories of the
|
||||
|
||||
@@ -13,7 +13,7 @@ else:
|
||||
TestCase = unittest.TestCase
|
||||
|
||||
import os
|
||||
from os.path import abspath, dirname
|
||||
from os.path import abspath, dirname, join
|
||||
import functools
|
||||
|
||||
test_dir = dirname(abspath(__file__))
|
||||
@@ -21,6 +21,11 @@ root_dir = dirname(test_dir)
|
||||
|
||||
sample_int = 1 # This is used in completion/imports.py
|
||||
|
||||
|
||||
def get_example_dir(name):
|
||||
return join(test_dir, 'examples', name)
|
||||
|
||||
|
||||
def cwd_at(path):
|
||||
"""
|
||||
Decorator to run function at `path`.
|
||||
|
||||
15
test/test_api/test_project.py
Normal file
15
test/test_api/test_project.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
|
||||
from ..helpers import get_example_dir
|
||||
|
||||
|
||||
def test_django_default_project(Script):
|
||||
dir = get_example_dir('django')
|
||||
|
||||
script = Script(
|
||||
"from app import models\nmodels.SomeMo",
|
||||
path=os.path.join(dir, 'models/x.py')
|
||||
)
|
||||
c, = script.completions()
|
||||
assert c.name == "SomeModel"
|
||||
assert script._project._django is True
|
||||
Reference in New Issue
Block a user