mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 14:34:31 +08:00
instances are basically working now, tests are not -> satisfy tests!
This commit is contained in:
181
evaluate.py
181
evaluate.py
@@ -8,6 +8,7 @@ TODO include super classes
|
|||||||
TODO nonlocal statement
|
TODO nonlocal statement
|
||||||
TODO doc
|
TODO doc
|
||||||
TODO list comprehensions, priority?
|
TODO list comprehensions, priority?
|
||||||
|
TODO care for *args **kwargs
|
||||||
"""
|
"""
|
||||||
from _compatibility import next
|
from _compatibility import next
|
||||||
|
|
||||||
@@ -54,49 +55,144 @@ def memoize(default=None):
|
|||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
class Exec(object):
|
class Executable(object):
|
||||||
def __init__(self, base, params=None):
|
""" An instance is also an executable - because __init__ is called """
|
||||||
|
def __init__(self, base, params=[]):
|
||||||
self.base = base
|
self.base = base
|
||||||
self.params = params
|
self.params = params
|
||||||
|
self.func = None
|
||||||
|
|
||||||
def get_parent_until(self, *args):
|
def get_parent_until(self, *args):
|
||||||
return self.base.get_parent_until(*args)
|
return self.base.get_parent_until(*args)
|
||||||
|
|
||||||
|
@memoize(default=[])
|
||||||
|
def get_params(self):
|
||||||
|
"""
|
||||||
|
This returns the params for an Execution/Instance and is injected as a
|
||||||
|
'hack' into the parsing.Function class.
|
||||||
|
This needs to be here, because Instance can have __init__ functions,
|
||||||
|
which act the same way as normal functions
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
offset = 0
|
||||||
|
#print '\n\nfunc_params', self.func, self.func.parent, self.func
|
||||||
|
if isinstance(self.func, InstanceElement):
|
||||||
|
# care for self -> just exclude it and add the instance
|
||||||
|
#print '\n\nyes', self.func, self.func.instance
|
||||||
|
offset = 1
|
||||||
|
self_name = copy.copy(self.func.params[0].get_name())
|
||||||
|
self_name.parent = self.func.instance
|
||||||
|
result.append(self_name)
|
||||||
|
# There may be calls, which don't fit all the params, this just ignores
|
||||||
|
# it.
|
||||||
|
for i, value in enumerate(self.params, offset):
|
||||||
|
try:
|
||||||
|
param = self.func.params[i]
|
||||||
|
except IndexError:
|
||||||
|
debug.warning('Too many arguments given.', value)
|
||||||
|
else:
|
||||||
|
new_param = copy.copy(param)
|
||||||
|
calls = parsing.Array(parsing.Array.NOARRAY,
|
||||||
|
self.params.parent_stmt)
|
||||||
|
calls.values = [value]
|
||||||
|
new_param._assignment_calls = calls
|
||||||
|
name = copy.copy(param.get_name())
|
||||||
|
name.parent = new_param
|
||||||
|
#print 'insert', i, name, calls.values, value, self.func.params
|
||||||
|
result.append(name)
|
||||||
|
return result
|
||||||
|
|
||||||
class Instance(Exec):
|
def set_param_cb(self, func):
|
||||||
|
self.func = func
|
||||||
|
func.param_cb = self.get_params
|
||||||
|
|
||||||
|
|
||||||
|
class Instance(Executable):
|
||||||
""" This class is used to evaluate instances. """
|
""" This class is used to evaluate instances. """
|
||||||
|
def __init__(self, base, params=[]):
|
||||||
|
super(Instance, self).__init__(base, params)
|
||||||
|
if params:
|
||||||
|
self.set_init_params()
|
||||||
|
|
||||||
|
def set_init_params(self):
|
||||||
|
for sub in self.base.subscopes:
|
||||||
|
if isinstance(sub, parsing.Function) \
|
||||||
|
and sub.name.get_code() == '__init__':
|
||||||
|
self.set_param_cb(InstanceElement(self, sub))
|
||||||
|
|
||||||
|
def get_func_self_name(self, func):
|
||||||
|
"""
|
||||||
|
Returns the name of the first param in a class method (which is
|
||||||
|
normally self
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return func.params[0].used_vars[0].names[0]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
def get_set_vars(self):
|
def get_set_vars(self):
|
||||||
"""
|
"""
|
||||||
Get the instance vars of a class. This includes the vars of all
|
Get the instance vars of a class. This includes the vars of all
|
||||||
classes
|
classes
|
||||||
"""
|
"""
|
||||||
n = []
|
def add_self_name(name):
|
||||||
|
n = copy.copy(name)
|
||||||
|
n.names = n.names[1:]
|
||||||
|
names.append(InstanceElement(self, n))
|
||||||
|
names = []
|
||||||
|
# this loop adds the names of the self object, copies them and removes
|
||||||
|
# the self.
|
||||||
for s in self.base.subscopes:
|
for s in self.base.subscopes:
|
||||||
try:
|
# get the self name, if there's one
|
||||||
# get the self name, if there's one
|
self_name = self.get_func_self_name(s)
|
||||||
self_name = s.params[0].used_vars[0].names[0]
|
if self_name:
|
||||||
except:
|
for n in s.get_set_vars():
|
||||||
pass
|
|
||||||
else:
|
|
||||||
for n2 in s.get_set_vars():
|
|
||||||
# Only names with the selfname are being added.
|
# Only names with the selfname are being added.
|
||||||
# It is also important, that they have a len() of 2,
|
# It is also important, that they have a len() of 2,
|
||||||
# because otherwise, they are just something else
|
# because otherwise, they are just something else
|
||||||
if n2.names[0] == self_name and len(n2.names) == 2:
|
if n.names[0] == self_name and len(n.names) == 2:
|
||||||
n.append(n2)
|
add_self_name(n)
|
||||||
n += self.base.get_set_vars()
|
for var in self.base.get_set_vars():
|
||||||
return n
|
# functions are also instance elements
|
||||||
|
if isinstance(var.parent, (parsing.Function)):
|
||||||
|
var = InstanceElement(self, var)
|
||||||
|
names.append(var)
|
||||||
|
return names
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
return self.get_set_vars()
|
return self.get_set_vars()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % \
|
return "<%s of %s (params: %s)>" % \
|
||||||
(self.__class__.__name__, self.base)
|
(self.__class__.__name__, self.base, len(self.params or []))
|
||||||
|
|
||||||
|
|
||||||
class Execution(Exec):
|
class InstanceElement(object):
|
||||||
|
def __init__(self, instance, var):
|
||||||
|
super(InstanceElement, self).__init__()
|
||||||
|
self.instance = instance
|
||||||
|
self.var = var
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent(self):
|
||||||
|
return InstanceElement(self.instance, self.var.parent)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def param_cb(self):
|
||||||
|
return self.var.param_cb
|
||||||
|
|
||||||
|
@param_cb.setter
|
||||||
|
def param_cb(self, value):
|
||||||
|
self.var.param_cb = value
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.var, name)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s of %s>" % (self.__class__.__name__, self.var)
|
||||||
|
|
||||||
|
|
||||||
|
class Execution(Executable):
|
||||||
"""
|
"""
|
||||||
This class is used to evaluate functions and their returns.
|
This class is used to evaluate functions and their returns.
|
||||||
"""
|
"""
|
||||||
@@ -114,7 +210,7 @@ class Execution(Exec):
|
|||||||
stmts = [Instance(self.base, self.params)]
|
stmts = [Instance(self.base, self.params)]
|
||||||
else:
|
else:
|
||||||
# set the callback function to get the params
|
# set the callback function to get the params
|
||||||
self.base.param_cb = self.get_params
|
self.set_param_cb(self.base)
|
||||||
# don't do this with exceptions, as usual, because some deeper
|
# don't do this with exceptions, as usual, because some deeper
|
||||||
# exceptions could be catched - and I wouldn't know what happened.
|
# exceptions could be catched - and I wouldn't know what happened.
|
||||||
if hasattr(self.base, 'returns'):
|
if hasattr(self.base, 'returns'):
|
||||||
@@ -126,32 +222,13 @@ class Execution(Exec):
|
|||||||
|
|
||||||
# reset the callback function on exit
|
# reset the callback function on exit
|
||||||
self.base.param_cb = None
|
self.base.param_cb = None
|
||||||
|
else:
|
||||||
|
debug.warning("no execution possible", self.base)
|
||||||
|
|
||||||
debug.dbg('exec stmts=', stmts, self.base, repr(self))
|
debug.dbg('exec stmts=', stmts, self.base, repr(self))
|
||||||
|
|
||||||
return stmts
|
return stmts
|
||||||
|
|
||||||
@memoize(default=[])
|
|
||||||
def get_params(self):
|
|
||||||
result = []
|
|
||||||
for i, param in enumerate(self.base.params):
|
|
||||||
try:
|
|
||||||
value = self.params.values[i]
|
|
||||||
except IndexError:
|
|
||||||
# This means, that there is no param in the call. So we just
|
|
||||||
# ignore it and take the default params.
|
|
||||||
result.append(param.get_name())
|
|
||||||
else:
|
|
||||||
new_param = copy.copy(param)
|
|
||||||
calls = parsing.Array(parsing.Array.NOARRAY,
|
|
||||||
self.params.parent_stmt)
|
|
||||||
calls.values = [value]
|
|
||||||
new_param._assignment_calls = calls
|
|
||||||
name = copy.copy(param.get_name())
|
|
||||||
name.parent = new_param
|
|
||||||
result.append(name)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % \
|
return "<%s of %s>" % \
|
||||||
(self.__class__.__name__, self.base)
|
(self.__class__.__name__, self.base)
|
||||||
@@ -196,6 +273,7 @@ class Array(object):
|
|||||||
|
|
||||||
class ArrayElement(object):
|
class ArrayElement(object):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
super(ArrayElement, self).__init__()
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -254,7 +332,9 @@ def get_scopes_for_name(scope, name, search_global=False):
|
|||||||
"""
|
"""
|
||||||
res_new = []
|
res_new = []
|
||||||
for r in result:
|
for r in result:
|
||||||
if isinstance(r, parsing.Statement):
|
if isinstance(r, parsing.Statement) \
|
||||||
|
or isinstance(r, InstanceElement) \
|
||||||
|
and isinstance(r.var, parsing.Statement):
|
||||||
# global variables handling
|
# global variables handling
|
||||||
if r.is_global():
|
if r.is_global():
|
||||||
for token_name in r.token_list[1:]:
|
for token_name in r.token_list[1:]:
|
||||||
@@ -289,11 +369,14 @@ def get_scopes_for_name(scope, name, search_global=False):
|
|||||||
else:
|
else:
|
||||||
result += for_vars
|
result += for_vars
|
||||||
else:
|
else:
|
||||||
debug.warning('Why are you here? %s' % par.command)
|
debug.warning('Flow: Why are you here? %s' % par.command)
|
||||||
elif isinstance(par, parsing.Param) \
|
elif isinstance(par, parsing.Param) \
|
||||||
and isinstance(par.parent.parent, parsing.Class) \
|
and isinstance(par.parent.parent, parsing.Class) \
|
||||||
and par.position == 0:
|
and par.position == 0:
|
||||||
# this is where self gets added
|
# this is where self gets added - this happens at another
|
||||||
|
# place, if the params are clear. But some times the class is
|
||||||
|
# not known. Therefore set self.
|
||||||
|
#print '\nselfadd', par, scope, scope.parent, par.parent, par.parent.parent
|
||||||
result.append(Instance(par.parent.parent))
|
result.append(Instance(par.parent.parent))
|
||||||
result.append(par)
|
result.append(par)
|
||||||
else:
|
else:
|
||||||
@@ -307,7 +390,7 @@ def get_scopes_for_name(scope, name, search_global=False):
|
|||||||
result.append(scope)
|
result.append(scope)
|
||||||
else:
|
else:
|
||||||
result += handle_non_arrays()
|
result += handle_non_arrays()
|
||||||
debug.dbg('sfn filter', result)
|
debug.dbg('sfn filter', name, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if search_global:
|
if search_global:
|
||||||
@@ -386,11 +469,15 @@ def follow_statement(stmt, scope=None, seek_name=None):
|
|||||||
:param stmt: contains a statement
|
:param stmt: contains a statement
|
||||||
:param scope: contains a scope. If not given, takes the parent of stmt.
|
:param scope: contains a scope. If not given, takes the parent of stmt.
|
||||||
"""
|
"""
|
||||||
|
debug.dbg('follow_stmt', stmt, 'in', stmt.parent, scope, seek_name)
|
||||||
if scope is None:
|
if scope is None:
|
||||||
scope = stmt.get_parent_until(parsing.Function, Execution,
|
scope = stmt.get_parent_until(parsing.Function, Execution,
|
||||||
parsing.Class, Instance)
|
parsing.Class, Instance,
|
||||||
|
InstanceElement)
|
||||||
|
debug.dbg('follow_stmt', stmt, 'in', stmt.parent, scope, seek_name)
|
||||||
|
|
||||||
call_list = stmt.get_assignment_calls()
|
call_list = stmt.get_assignment_calls()
|
||||||
debug.dbg('calls', call_list, call_list)
|
debug.dbg('calls', call_list, call_list.values)
|
||||||
result = set(follow_call_list(scope, call_list))
|
result = set(follow_call_list(scope, call_list))
|
||||||
|
|
||||||
# assignment checking is only important if the statement defines multiple
|
# assignment checking is only important if the statement defines multiple
|
||||||
@@ -489,8 +576,6 @@ def follow_path(path, scope):
|
|||||||
exe = Execution(scope, current)
|
exe = Execution(scope, current)
|
||||||
result = strip_imports(exe.get_return_types())
|
result = strip_imports(exe.get_return_types())
|
||||||
debug.dbg('exec', result)
|
debug.dbg('exec', result)
|
||||||
#except AttributeError:
|
|
||||||
# debug.dbg('cannot execute:', scope)
|
|
||||||
else:
|
else:
|
||||||
# curly braces are not allowed, because they make no sense
|
# curly braces are not allowed, because they make no sense
|
||||||
debug.warning('strange function call with {}', current, scope)
|
debug.warning('strange function call with {}', current, scope)
|
||||||
|
|||||||
2
ftest.py
2
ftest.py
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import functions
|
import functions
|
||||||
|
|
||||||
#functions.debug.debug_function = functions.debug.print_to_stdout
|
functions.debug.debug_function = functions.debug.print_to_stdout
|
||||||
functions.debug.ignored_modules = ['parsing', 'builtin']
|
functions.debug.ignored_modules = ['parsing', 'builtin']
|
||||||
#functions.debug.ignored_modules = ['parsing', 'builtin', 'evaluate', 'modules']
|
#functions.debug.ignored_modules = ['parsing', 'builtin', 'evaluate', 'modules']
|
||||||
functions.modules.module_find_path.insert(0, '.')
|
functions.modules.module_find_path.insert(0, '.')
|
||||||
|
|||||||
12
parsetest.py
12
parsetest.py
@@ -3,7 +3,7 @@
|
|||||||
# test comment
|
# test comment
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from token import *
|
#from token import *
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from token import OP as OP_TEST, INDENT as INDENT_TEST
|
from token import OP as OP_TEST, INDENT as INDENT_TEST
|
||||||
|
|
||||||
@@ -128,14 +128,16 @@ if True or a:
|
|||||||
import time
|
import time
|
||||||
class c1():
|
class c1():
|
||||||
c2,c5 = c1(), c1().c3()
|
c2,c5 = c1(), c1().c3()
|
||||||
def c3(self, daeparam):
|
def __init__(self, athefirst):
|
||||||
|
self.acp = athefirst; self.bcp = 3
|
||||||
|
def c3(self, daeparam):
|
||||||
import os as c4 #from parsing import Scope as c4
|
import os as c4 #from parsing import Scope as c4
|
||||||
c5 = 1
|
c5 = 1
|
||||||
c5 = c4(
|
c5 = c4(
|
||||||
if 1:
|
if 1:
|
||||||
print 1
|
print 1
|
||||||
#return c5+'asdf'
|
#return c5+'asdf'
|
||||||
return daeparam
|
return self.acp # self.bcp +
|
||||||
(c1().c2.\
|
(c1().c2.\
|
||||||
c, 1, c3()) [0].pop()
|
c, 1, c3()) [0].pop()
|
||||||
c = u"asdf".join([1,2])
|
c = u"asdf".join([1,2])
|
||||||
@@ -155,6 +157,4 @@ def globalfunc():
|
|||||||
global globalvar, globalvar2
|
global globalvar, globalvar2
|
||||||
globalvar = 3
|
globalvar = 3
|
||||||
|
|
||||||
|
c1(1).c3(r"")
|
||||||
|
|
||||||
c1().c3(1)
|
|
||||||
|
|||||||
@@ -34,8 +34,12 @@ b2.upper
|
|||||||
|
|
||||||
# list assignment
|
# list assignment
|
||||||
[list1, list2] = (1, "")
|
[list1, list2] = (1, "")
|
||||||
|
#? []
|
||||||
|
list1.index
|
||||||
#? ['real']
|
#? ['real']
|
||||||
list1.real
|
list1.real
|
||||||
|
#? []
|
||||||
|
list1.lower
|
||||||
#? ['lower']
|
#? ['lower']
|
||||||
list2.lower
|
list2.lower
|
||||||
#? []
|
#? []
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
|
|
||||||
class TestClass(object):
|
class TestClass(object):
|
||||||
var_class = TestClass()
|
var_class = TestClass(1)
|
||||||
|
|
||||||
def __init__(self2, a):
|
def __init__(self2, first_param, second_param):
|
||||||
self2.var_inst = a
|
self2.var_inst = first_aparam
|
||||||
|
self2.second = second_param
|
||||||
|
|
||||||
|
def get_var_inst(self):
|
||||||
|
# traversal
|
||||||
|
self.second_new = self.second
|
||||||
|
return self.var_inst
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
self.var_local = 3
|
self.var_local = 3
|
||||||
@@ -19,7 +25,24 @@ inst = TestClass(1)
|
|||||||
inst.var
|
inst.var
|
||||||
|
|
||||||
#? ['var_class']
|
#? ['var_class']
|
||||||
TestClass.var_class
|
TestClass.var
|
||||||
|
|
||||||
|
#? ['real']
|
||||||
|
inst.var_local.real
|
||||||
|
#? []
|
||||||
|
TestClass.var_local.real
|
||||||
|
|
||||||
#? ['real']
|
#? ['real']
|
||||||
TestClass().ret(1).real
|
TestClass().ret(1).real
|
||||||
|
#? ['real']
|
||||||
|
inst.ret(1).real
|
||||||
|
|
||||||
|
myclass = TestClass(1, '')
|
||||||
|
#? ['real']
|
||||||
|
TestClass(1).var_inst.
|
||||||
|
#? ['real']
|
||||||
|
myclass.get_var_inst().real
|
||||||
|
#? []
|
||||||
|
myclass.get_var_inst().upper
|
||||||
|
#? []
|
||||||
|
myclass.get_var_inst.real
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ def openbrace():
|
|||||||
asdf = 3
|
asdf = 3
|
||||||
asdf
|
asdf
|
||||||
asdf(
|
asdf(
|
||||||
|
#? ['real']
|
||||||
|
asdf.real
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#? ['real']
|
#? ['real']
|
||||||
@@ -11,3 +13,17 @@ blub([
|
|||||||
#? ['real']
|
#? ['real']
|
||||||
openbrace().real
|
openbrace().real
|
||||||
|
|
||||||
|
def indentfault():
|
||||||
|
asd(
|
||||||
|
indentback
|
||||||
|
|
||||||
|
#? []
|
||||||
|
indentfault().
|
||||||
|
|
||||||
|
def openbrace2():
|
||||||
|
asd(
|
||||||
|
def normalfunc():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
#? ['real']
|
||||||
|
normalfunc().real
|
||||||
|
|||||||
15
test/run.py
15
test/run.py
@@ -60,13 +60,14 @@ def completion_test(source):
|
|||||||
completion_test_dir = 'completion'
|
completion_test_dir = 'completion'
|
||||||
summary = []
|
summary = []
|
||||||
for f_name in os.listdir(completion_test_dir):
|
for f_name in os.listdir(completion_test_dir):
|
||||||
if f_name.endswith(".py"):
|
if len(sys.argv) == 1 or [a for a in sys.argv[1:] if a in f_name]:
|
||||||
path = os.path.join(completion_test_dir, f_name)
|
if f_name.endswith(".py"):
|
||||||
f = open(path)
|
path = os.path.join(completion_test_dir, f_name)
|
||||||
num_tests, fails = completion_test(f.read())
|
f = open(path)
|
||||||
s = 'run %s tests with %s fails (%s)' % (num_tests, fails, f_name)
|
num_tests, fails = completion_test(f.read())
|
||||||
print s
|
s = 'run %s tests with %s fails (%s)' % (num_tests, fails, f_name)
|
||||||
summary.append(s)
|
print s
|
||||||
|
summary.append(s)
|
||||||
|
|
||||||
print '\nSummary:'
|
print '\nSummary:'
|
||||||
for s in summary:
|
for s in summary:
|
||||||
|
|||||||
Reference in New Issue
Block a user