1
0
forked from VimPlug/jedi

Refactor django path support

This commit is contained in:
Dave Halter
2018-01-24 19:13:05 +01:00
parent e4559bef51
commit 68f840de60
7 changed files with 70 additions and 36 deletions

View File

@@ -14,6 +14,7 @@ collect_ignore = [
'__main__.py',
'jedi/evaluate/compiled/subprocess/__main__.py',
'build/',
'test/examples',
]

View File

@@ -264,6 +264,11 @@ try:
except NameError:
FileNotFoundError = IOError
try:
NotADirectoryError = NotADirectoryError
except NameError:
NotADirectoryError = IOError
def no_unicode_pprint(dct):
"""

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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`.

View 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