forked from VimPlug/jedi
sys path modifications
This commit is contained in:
@@ -53,11 +53,11 @@ Jedi supports many of the widely used Python features:
|
||||
I don't know what to do with them.)
|
||||
- class decorators (py3k feature, are being ignored too, until I find a use
|
||||
case, that doesn't work with Jedi)
|
||||
- simple/usual `sys.path` modifications
|
||||
|
||||
However, it does not yet support (and probably will in future versions, because
|
||||
they are on my todo list):
|
||||
|
||||
- `sys.path` modifications
|
||||
- assert / isinstance
|
||||
- manipulations of instances outside the instance variables, without using
|
||||
functions
|
||||
|
||||
@@ -10,6 +10,7 @@ import re
|
||||
import os
|
||||
|
||||
import parsing
|
||||
import modules
|
||||
import evaluate
|
||||
import helpers
|
||||
import settings
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import re
|
||||
import weakref
|
||||
import os
|
||||
|
||||
import parsing
|
||||
import dynamic # must be before evaluate, because it needs to be loaded first.
|
||||
import dynamic
|
||||
import imports
|
||||
import evaluate
|
||||
import modules
|
||||
import debug
|
||||
import imports
|
||||
import settings
|
||||
import keywords
|
||||
|
||||
|
||||
@@ -115,13 +115,18 @@ class ImportPath(object):
|
||||
Get the names of all modules in the search_path. This means file names
|
||||
and not names defined in the files.
|
||||
"""
|
||||
if not search_path:
|
||||
search_path = self.sys_path_with_modifications()
|
||||
names = []
|
||||
for module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
|
||||
inf = float('inf')
|
||||
inf_pos = (inf, inf)
|
||||
inf_pos = (float('inf'), float('inf'))
|
||||
names.append(parsing.Name([(name, inf_pos)], inf_pos, inf_pos))
|
||||
return names
|
||||
|
||||
def sys_path_with_modifications(self):
|
||||
module = self.import_stmt.get_parent_until()
|
||||
return modules.sys_path_with_modifications(module)
|
||||
|
||||
def follow(self):
|
||||
"""
|
||||
Returns the imported modules.
|
||||
|
||||
66
modules.py
66
modules.py
@@ -1,11 +1,16 @@
|
||||
from __future__ import with_statement
|
||||
|
||||
from _compatibility import exec_function
|
||||
|
||||
import re
|
||||
import tokenize
|
||||
import sys
|
||||
import os
|
||||
|
||||
import parsing
|
||||
import builtin
|
||||
import debug
|
||||
import evaluate
|
||||
|
||||
|
||||
class Module(builtin.CachedModule):
|
||||
@@ -170,3 +175,64 @@ class ModuleWithCursor(Module):
|
||||
return self._line_cache[line_nr - 1]
|
||||
except IndexError:
|
||||
raise StopIteration()
|
||||
|
||||
|
||||
@evaluate.memoize_default([])
|
||||
def sys_path_with_modifications(module):
|
||||
def execute_code(code):
|
||||
c = "import os; from os.path import *; result=%s"
|
||||
variables = {}
|
||||
try:
|
||||
exec_function(c % code, variables)
|
||||
except Exception:
|
||||
return None
|
||||
try:
|
||||
return os.path.abspath(variables['result'])
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
curdir = os.path.abspath(os.curdir)
|
||||
try:
|
||||
os.chdir(os.path.dirname(module.path))
|
||||
except OSError:
|
||||
pass
|
||||
sys_path = list(builtin.module_find_path) # copy
|
||||
try:
|
||||
possible_stmts = module.used_names['path']
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
for p in possible_stmts:
|
||||
try:
|
||||
call = p.get_assignment_calls().get_only_subelement()
|
||||
except AttributeError:
|
||||
continue
|
||||
n = call.name
|
||||
if not isinstance(n, parsing.Name) or len(n.names) != 3:
|
||||
continue
|
||||
if n.names[:2] != ('sys', 'path'):
|
||||
continue
|
||||
array_cmd = n.names[2]
|
||||
if call.execution is None:
|
||||
continue
|
||||
exe = call.execution
|
||||
if not (array_cmd == 'insert' and len(exe) == 2 \
|
||||
or array_cmd == 'append' and len(exe) == 1):
|
||||
continue
|
||||
|
||||
if array_cmd == 'insert':
|
||||
exe_type, exe.type = exe.type, parsing.Array.NOARRAY
|
||||
exe_pop = exe.values.pop(0)
|
||||
res = execute_code(exe.get_code())
|
||||
if res:
|
||||
sys_path.insert(0, res)
|
||||
exe.type = exe_type
|
||||
exe.values.insert(0, exe_pop)
|
||||
elif array_cmd == 'append':
|
||||
res = execute_code(exe.get_code())
|
||||
if res:
|
||||
sys_path.append(res)
|
||||
|
||||
# cleanup, back to old directory
|
||||
os.chdir(curdir)
|
||||
return sys_path
|
||||
|
||||
39
parsing.py
39
parsing.py
@@ -900,6 +900,17 @@ class Call(Base):
|
||||
for y in self.next.generate_call_path():
|
||||
yield y
|
||||
|
||||
def get_code(self):
|
||||
if self.type == Call.NAME:
|
||||
s = self.name.get_code()
|
||||
else:
|
||||
s = repr(self.name)
|
||||
if self.execution is not None:
|
||||
s += '(%s)' % self.execution.get_code()
|
||||
if self.next is not None:
|
||||
s += self.next.get_code()
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % \
|
||||
(self.__class__.__name__, self.name)
|
||||
@@ -991,6 +1002,34 @@ class Array(Call):
|
||||
else:
|
||||
return iter(self.values)
|
||||
|
||||
def get_code(self):
|
||||
def to_str(el):
|
||||
try:
|
||||
return el.get_code()
|
||||
except AttributeError:
|
||||
return str(el)
|
||||
|
||||
map = {Array.NOARRAY: '%s',
|
||||
Array.TUPLE: '(%s)',
|
||||
Array.LIST: '[%s]',
|
||||
Array.DICT: '{%s}',
|
||||
Array.SET: '{%s}'
|
||||
}
|
||||
inner = []
|
||||
for i, value in enumerate(self.values):
|
||||
s = ''
|
||||
try:
|
||||
key = self.keys[i]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
for el in key[i]:
|
||||
s += to_str(el)
|
||||
for el in value:
|
||||
s += to_str(el)
|
||||
inner.append(s)
|
||||
return map[self.type] % ', '.join(inner)
|
||||
|
||||
def __repr__(self):
|
||||
if self.type == self.NOARRAY:
|
||||
type = 'noarray'
|
||||
|
||||
22
test/completion/sys_path.py
Normal file
22
test/completion/sys_path.py
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
from os import dirname
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
sys.path.append(dirname(os.path.abspath('thirdparty' + os.path.sep + 'asdf')))
|
||||
|
||||
# modifications, that should fail:
|
||||
# because of sys module
|
||||
sys.path.append(sys.path[1] + '/thirdparty')
|
||||
# syntax err
|
||||
sys.path.append('a' +* '/thirdparty')
|
||||
|
||||
#? ['evaluate']
|
||||
import evaluate
|
||||
|
||||
#? ['goto']
|
||||
evaluate.goto
|
||||
|
||||
#? ['pylab_']
|
||||
import pylab_
|
||||
@@ -12,6 +12,8 @@ from _compatibility import unicode, BytesIO, reduce, literal_eval, is_py25
|
||||
import functions
|
||||
import debug
|
||||
|
||||
sys.path.pop() # pop again, because it might affect the completion
|
||||
|
||||
|
||||
def run_completion_test(correct, source, line_nr, index, line, path):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user