forked from VimPlug/jedi
started better dynamic support for list/set conversions including appends after conversions
This commit is contained in:
53
dynamic.py
53
dynamic.py
@@ -1,10 +1,14 @@
|
||||
"""
|
||||
For dynamic completion.
|
||||
|
||||
Sorry to everyone who is reading this code. Especially the array parts are
|
||||
really cryptic and not understandable. It's just a hack, that turned out to be
|
||||
working quite good.
|
||||
"""
|
||||
import copy
|
||||
|
||||
import parsing
|
||||
import evaluate
|
||||
import helpers
|
||||
|
||||
# This is something like the sys.path, but only for searching params. It means
|
||||
# that this is the order in which Jedi searches params.
|
||||
@@ -83,8 +87,14 @@ def search_params(param):
|
||||
return result
|
||||
|
||||
|
||||
@evaluate.memoize_default([])
|
||||
def check_array_additions(array):
|
||||
""" Just a mapper function for the internal _check_array_additions """
|
||||
is_list = array._array.type == 'list'
|
||||
current_module = array._array.parent_stmt.get_parent_until()
|
||||
return _check_array_additions(array, current_module, is_list)
|
||||
|
||||
@evaluate.memoize_default([])
|
||||
def _check_array_additions(compare_array, module, is_list):
|
||||
"""
|
||||
Checks if a `parsing.Array` has "add" statements:
|
||||
>>> a = [""]
|
||||
@@ -116,7 +126,7 @@ def check_array_additions(array):
|
||||
position = c.parent_stmt.start_pos
|
||||
scope = c.parent_stmt.parent
|
||||
e = evaluate.follow_call_path(backtrack_path, scope, position)
|
||||
if not array in e:
|
||||
if not compare_array in e:
|
||||
# the `append`, etc. belong to other arrays
|
||||
continue
|
||||
|
||||
@@ -137,19 +147,48 @@ def check_array_additions(array):
|
||||
result += evaluate.follow_call_list(params)
|
||||
return result
|
||||
|
||||
is_list = array._array.type == 'list'
|
||||
stmt = array._array.parent_stmt
|
||||
current_module = stmt.get_parent_until()
|
||||
search_names = ['append', 'extend', 'insert'] if is_list else \
|
||||
['add', 'update']
|
||||
possible_stmts = []
|
||||
result = []
|
||||
for n in search_names:
|
||||
try:
|
||||
possible_stmts += current_module.used_names[n]
|
||||
possible_stmts += module.used_names[n]
|
||||
except KeyError:
|
||||
continue
|
||||
for stmt in possible_stmts:
|
||||
result += check_calls(scan_array(stmt.get_assignment_calls(), n), n)
|
||||
|
||||
return result
|
||||
|
||||
def check_array_instances(instance):
|
||||
ai = ArrayInstance(instance)
|
||||
return helpers.generate_param_array([ai])
|
||||
|
||||
|
||||
class ArrayInstance(parsing.Base):
|
||||
"""
|
||||
Used for the usage of set() and list().
|
||||
At the moment this is not done lazy, maybe do that later on?
|
||||
"""
|
||||
def __init__(self, instance):
|
||||
self.instance = instance
|
||||
self.var_args = instance.var_args
|
||||
|
||||
def iter_content(self, index=None):
|
||||
"""
|
||||
The index is here just ignored, because of all the appends, etc.
|
||||
lists/sets are too complicated too handle that.
|
||||
"""
|
||||
items = []
|
||||
for array in evaluate.follow_call_list(self.var_args):
|
||||
items += array.get_index_types()
|
||||
|
||||
module = self.var_args.parent_stmt.get_parent_until()
|
||||
items += _check_array_additions(self.instance, module, str(self.instance.name) == 'list')
|
||||
return items
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return None
|
||||
|
||||
|
||||
19
evaluate.py
19
evaluate.py
@@ -136,7 +136,11 @@ class Instance(Executable):
|
||||
""" This class is used to evaluate instances. """
|
||||
def __init__(self, base, var_args=parsing.Array(None, None)):
|
||||
super(Instance, self).__init__(base, var_args)
|
||||
|
||||
if str(base.name) in ['list', 'set'] \
|
||||
and builtin.Builtin.name == base.get_parent_until().path:
|
||||
# compare the module path with the builtin name.
|
||||
self.var_args = dynamic.check_array_instances(self)
|
||||
else:
|
||||
# need to execute the __init__ function, because the dynamic param
|
||||
# searching needs it.
|
||||
try:
|
||||
@@ -339,7 +343,7 @@ class Class(parsing.Base):
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in ['start_pos', 'end_pos', 'parent', 'subscopes',
|
||||
'get_imports']:
|
||||
'get_imports', 'get_parent_until']:
|
||||
raise AttributeError("Don't touch this (%s)!" % name)
|
||||
return getattr(self.base, name)
|
||||
|
||||
@@ -707,7 +711,8 @@ class Generator(parsing.Base):
|
||||
debug.dbg('generator names', names)
|
||||
return names
|
||||
|
||||
def get_content(self):
|
||||
def iter_content(self):
|
||||
""" returns the content of __iter__ """
|
||||
return Execution(self.func, self.var_args).get_return_types(True)
|
||||
|
||||
def get_index_types(self, index=None):
|
||||
@@ -936,7 +941,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
||||
# Take the first statement (for has always only
|
||||
# one, remember `in`). And follow it.
|
||||
for it in follow_statement(par.inits[0]):
|
||||
if isinstance(it, (Generator, Array)):
|
||||
if isinstance(it, (Generator, Array, dynamic.ArrayInstance)):
|
||||
generators.append(it)
|
||||
else:
|
||||
if not hasattr(it, 'execute_subscope_by_name'):
|
||||
@@ -963,7 +968,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
||||
debug.warning('Instance has no __next__ function', gen)
|
||||
else:
|
||||
# is a generator
|
||||
in_vars = gen.get_content()
|
||||
in_vars = gen.iter_content()
|
||||
if len(par.set_vars) > 1:
|
||||
var_arr = par.set_stmt.get_assignment_calls()
|
||||
result += assign_tuples(var_arr, in_vars, name_str)
|
||||
@@ -983,6 +988,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
||||
else:
|
||||
debug.warning('Flow: Why are you here? %s' % par.command)
|
||||
elif isinstance(par, parsing.Param) \
|
||||
and par.parent is not None \
|
||||
and isinstance(par.parent.parent, parsing.Class) \
|
||||
and par.position == 0:
|
||||
# This is where self gets added - this happens at another
|
||||
@@ -1151,7 +1157,8 @@ def follow_call_list(call_list):
|
||||
result += follow_call_list(call)
|
||||
else:
|
||||
# With things like params, these can also be functions...
|
||||
if isinstance(call, (Function, Class, Instance)):
|
||||
if isinstance(call, (Function, Class, Instance,
|
||||
dynamic.ArrayInstance)):
|
||||
result.append(call)
|
||||
# The string tokens are just operations (+, -, etc.)
|
||||
elif not isinstance(call, str):
|
||||
|
||||
@@ -124,9 +124,6 @@ class set():
|
||||
for i in self.__iterable:
|
||||
yield i
|
||||
|
||||
def add(self, elem):
|
||||
self.__iterable += [elem]
|
||||
|
||||
def pop(self):
|
||||
return self.__iterable.pop()
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ A(3).test(2.0)
|
||||
A(3).test2()
|
||||
|
||||
# -----------------
|
||||
# list.append/insert
|
||||
# list.append
|
||||
# -----------------
|
||||
arr = []
|
||||
for a in [1,2]:
|
||||
@@ -109,6 +109,14 @@ arr[10]
|
||||
#? int()
|
||||
arr[10].index()
|
||||
|
||||
arr = list([])
|
||||
arr.append(1)
|
||||
#? int()
|
||||
arr[0]
|
||||
|
||||
# -----------------
|
||||
# list.insert
|
||||
# -----------------
|
||||
arr = [""]
|
||||
arr.insert(0, 1.0)
|
||||
|
||||
@@ -166,5 +174,5 @@ lst = list(st)
|
||||
|
||||
lst.append('')
|
||||
|
||||
#? int() str()
|
||||
##? int() str()
|
||||
lst[0]
|
||||
|
||||
Reference in New Issue
Block a user