1
0
forked from VimPlug/jedi

sys path modifications

This commit is contained in:
David Halter
2012-09-14 03:05:31 +02:00
parent 65064b1312
commit 9a2ec13230
8 changed files with 140 additions and 6 deletions

View File

@@ -53,11 +53,11 @@ Jedi supports many of the widely used Python features:
I don't know what to do with them.) I don't know what to do with them.)
- class decorators (py3k feature, are being ignored too, until I find a use - class decorators (py3k feature, are being ignored too, until I find a use
case, that doesn't work with Jedi) 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 However, it does not yet support (and probably will in future versions, because
they are on my todo list): they are on my todo list):
- `sys.path` modifications
- assert / isinstance - assert / isinstance
- manipulations of instances outside the instance variables, without using - manipulations of instances outside the instance variables, without using
functions functions

View File

@@ -10,6 +10,7 @@ import re
import os import os
import parsing import parsing
import modules
import evaluate import evaluate
import helpers import helpers
import settings import settings

View File

@@ -1,13 +1,12 @@
import re import re
import weakref import weakref
import os
import parsing import parsing
import dynamic # must be before evaluate, because it needs to be loaded first. import dynamic
import imports
import evaluate import evaluate
import modules import modules
import debug import debug
import imports
import settings import settings
import keywords import keywords

View File

@@ -115,13 +115,18 @@ class ImportPath(object):
Get the names of all modules in the search_path. This means file names Get the names of all modules in the search_path. This means file names
and not names defined in the files. and not names defined in the files.
""" """
if not search_path:
search_path = self.sys_path_with_modifications()
names = [] names = []
for module_loader, name, is_pkg in pkgutil.iter_modules(search_path): for module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
inf = float('inf') inf_pos = (float('inf'), float('inf'))
inf_pos = (inf, inf)
names.append(parsing.Name([(name, inf_pos)], inf_pos, inf_pos)) names.append(parsing.Name([(name, inf_pos)], inf_pos, inf_pos))
return names 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): def follow(self):
""" """
Returns the imported modules. Returns the imported modules.

View File

@@ -1,11 +1,16 @@
from __future__ import with_statement from __future__ import with_statement
from _compatibility import exec_function
import re import re
import tokenize import tokenize
import sys import sys
import os
import parsing import parsing
import builtin import builtin
import debug import debug
import evaluate
class Module(builtin.CachedModule): class Module(builtin.CachedModule):
@@ -170,3 +175,64 @@ class ModuleWithCursor(Module):
return self._line_cache[line_nr - 1] return self._line_cache[line_nr - 1]
except IndexError: except IndexError:
raise StopIteration() 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

View File

@@ -900,6 +900,17 @@ class Call(Base):
for y in self.next.generate_call_path(): for y in self.next.generate_call_path():
yield y 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): def __repr__(self):
return "<%s: %s>" % \ return "<%s: %s>" % \
(self.__class__.__name__, self.name) (self.__class__.__name__, self.name)
@@ -991,6 +1002,34 @@ class Array(Call):
else: else:
return iter(self.values) 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): def __repr__(self):
if self.type == self.NOARRAY: if self.type == self.NOARRAY:
type = 'noarray' type = 'noarray'

View 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_

View File

@@ -12,6 +12,8 @@ from _compatibility import unicode, BytesIO, reduce, literal_eval, is_py25
import functions import functions
import debug import debug
sys.path.pop() # pop again, because it might affect the completion
def run_completion_test(correct, source, line_nr, index, line, path): def run_completion_test(correct, source, line_nr, index, line, path):
""" """