forked from VimPlug/jedi
Refactor django path support
This commit is contained in:
@@ -14,6 +14,7 @@ collect_ignore = [
|
|||||||
'__main__.py',
|
'__main__.py',
|
||||||
'jedi/evaluate/compiled/subprocess/__main__.py',
|
'jedi/evaluate/compiled/subprocess/__main__.py',
|
||||||
'build/',
|
'build/',
|
||||||
|
'test/examples',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,11 @@ try:
|
|||||||
except NameError:
|
except NameError:
|
||||||
FileNotFoundError = IOError
|
FileNotFoundError = IOError
|
||||||
|
|
||||||
|
try:
|
||||||
|
NotADirectoryError = NotADirectoryError
|
||||||
|
except NameError:
|
||||||
|
NotADirectoryError = IOError
|
||||||
|
|
||||||
|
|
||||||
def no_unicode_pprint(dct):
|
def no_unicode_pprint(dct):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class Script(object):
|
|||||||
sys_path = list(map(force_unicode, sys_path))
|
sys_path = list(map(force_unicode, sys_path))
|
||||||
|
|
||||||
# Load the Python grammar of the current interpreter.
|
# 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.
|
# TODO deprecate and remove sys_path from the Script API.
|
||||||
if sys_path is not None:
|
if sys_path is not None:
|
||||||
project._sys_path = sys_path
|
project._sys_path = sys_path
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError
|
from jedi._compatibility import FileNotFoundError, NotADirectoryError
|
||||||
from jedi.api.environment import DefaultEnvironment, \
|
from jedi.api.environment import DefaultEnvironment, \
|
||||||
get_default_environment, from_executable
|
get_default_environment, from_executable
|
||||||
from jedi.api.exceptions import WrongVersion
|
from jedi.api.exceptions import WrongVersion
|
||||||
from jedi._compatibility import force_unicode
|
from jedi._compatibility import force_unicode
|
||||||
from jedi.evaluate.sys_path import detect_additional_paths
|
from jedi.evaluate.sys_path import detect_additional_paths
|
||||||
from jedi.evaluate.cache import evaluator_as_method_param_cache
|
from jedi.evaluate.cache import evaluator_as_method_param_cache
|
||||||
|
from jedi.evaluate.sys_path import traverse_parents
|
||||||
|
|
||||||
_CONFIG_FOLDER = '.jedi'
|
_CONFIG_FOLDER = '.jedi'
|
||||||
_CONTAINS_POTENTIAL_PROJECT = 'setup.py', '.git', '.hg', 'MANIFEST.in'
|
_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
|
rely on your packages being properly configured on the
|
||||||
``sys.path``.
|
``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
|
self._path = path
|
||||||
if isinstance(environment, DefaultEnvironment):
|
if isinstance(environment, DefaultEnvironment):
|
||||||
self._environment = environment
|
self._environment = environment
|
||||||
@@ -62,6 +64,7 @@ class Project(object):
|
|||||||
|
|
||||||
self._sys_path = sys_path
|
self._sys_path = sys_path
|
||||||
self._smart_sys_path = smart_sys_path
|
self._smart_sys_path = smart_sys_path
|
||||||
|
self._django = _django
|
||||||
|
|
||||||
py2_comp(path, **kwargs)
|
py2_comp(path, **kwargs)
|
||||||
|
|
||||||
@@ -90,11 +93,15 @@ class Project(object):
|
|||||||
if evaluator.script_path is None or not self._smart_sys_path:
|
if evaluator.script_path is None or not self._smart_sys_path:
|
||||||
return sys_path
|
return sys_path
|
||||||
|
|
||||||
|
prefixed = []
|
||||||
|
if self._smart_sys_path:
|
||||||
|
if self._django:
|
||||||
|
prefixed.append(self._path)
|
||||||
added_paths = map(
|
added_paths = map(
|
||||||
force_unicode,
|
force_unicode,
|
||||||
detect_additional_paths(evaluator, evaluator.script_path)
|
detect_additional_paths(evaluator, evaluator.script_path)
|
||||||
)
|
)
|
||||||
return sys_path + list(added_paths)
|
return prefixed + sys_path + list(added_paths)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
data = dict(self.__dict__)
|
data = dict(self.__dict__)
|
||||||
@@ -121,26 +128,38 @@ def _is_potential_project(path):
|
|||||||
return False
|
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):
|
def get_default_project(path=None):
|
||||||
if path is None:
|
if path is None:
|
||||||
path = os.getcwd()
|
path = os.getcwd()
|
||||||
|
|
||||||
previous = None
|
check = os.path.realpath(path)
|
||||||
curdir = dir = os.path.realpath(path)
|
|
||||||
probable_path = None
|
probable_path = None
|
||||||
while dir != previous:
|
for dir in traverse_parents(check, include_current=True):
|
||||||
try:
|
try:
|
||||||
return Project.load(dir)
|
return Project.load(dir)
|
||||||
except FileNotFoundError:
|
except (FileNotFoundError, NotADirectoryError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if _is_django_path(dir):
|
||||||
|
return Project(dir, _django=True)
|
||||||
|
|
||||||
if probable_path is None and _is_potential_project(dir):
|
if probable_path is None and _is_potential_project(dir):
|
||||||
probable_path = dir
|
probable_path = dir
|
||||||
|
|
||||||
previous = dir
|
if probable_path is not None:
|
||||||
dir = os.path.dirname(dir)
|
# TODO search for setup.py etc
|
||||||
else:
|
return Project(probable_path)
|
||||||
if probable_path is not None:
|
|
||||||
# TODO search for setup.py etc
|
curdir = path if os.path.isdir(path) else os.path.dirname(path)
|
||||||
return Project(probable_path)
|
return Project(curdir)
|
||||||
return Project(curdir)
|
|
||||||
|
|||||||
@@ -134,14 +134,13 @@ def sys_path_with_modifications(evaluator, module_context):
|
|||||||
|
|
||||||
|
|
||||||
def detect_additional_paths(evaluator, script_path):
|
def detect_additional_paths(evaluator, script_path):
|
||||||
django_paths = _detect_django_path(script_path)
|
|
||||||
buildout_script_paths = set()
|
buildout_script_paths = set()
|
||||||
|
|
||||||
for buildout_script_path in _get_buildout_script_paths(script_path):
|
for buildout_script_path in _get_buildout_script_paths(script_path):
|
||||||
for path in _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
for path in _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
||||||
buildout_script_paths.add(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):
|
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
|
yield path
|
||||||
|
|
||||||
|
|
||||||
def traverse_parents(path):
|
def traverse_parents(path, include_current=False):
|
||||||
while True:
|
if not include_current:
|
||||||
new = os.path.dirname(path)
|
path = os.path.dirname(path)
|
||||||
if new == path:
|
|
||||||
return
|
previous = None
|
||||||
path = new
|
while previous != path:
|
||||||
yield path
|
yield path
|
||||||
|
previous = path
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
|
||||||
|
|
||||||
def _get_parent_dir_with_file(path, filename):
|
def _get_parent_dir_with_file(path, filename):
|
||||||
@@ -177,18 +178,6 @@ def _get_parent_dir_with_file(path, filename):
|
|||||||
return None
|
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):
|
def _get_buildout_script_paths(module_path):
|
||||||
"""
|
"""
|
||||||
if there is a 'buildout.cfg' file in one of the parent directories of the
|
if there is a 'buildout.cfg' file in one of the parent directories of the
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ else:
|
|||||||
TestCase = unittest.TestCase
|
TestCase = unittest.TestCase
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from os.path import abspath, dirname
|
from os.path import abspath, dirname, join
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
test_dir = dirname(abspath(__file__))
|
test_dir = dirname(abspath(__file__))
|
||||||
@@ -21,6 +21,11 @@ root_dir = dirname(test_dir)
|
|||||||
|
|
||||||
sample_int = 1 # This is used in completion/imports.py
|
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):
|
def cwd_at(path):
|
||||||
"""
|
"""
|
||||||
Decorator to run function 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