fixed property not found bug with builtins + cleaning

This commit is contained in:
David Halter
2012-06-24 18:47:57 +02:00
parent 548af3cc86
commit 3650e0ee64
5 changed files with 27 additions and 60 deletions

View File

@@ -39,7 +39,6 @@ class CachedModule(object):
def _load_module(self): def _load_module(self):
source = self._get_source() source = self._get_source()
print source
self._parser = parsing.PyFuzzyParser(source, self.path or self.name) self._parser = parsing.PyFuzzyParser(source, self.path or self.name)
p_time = None if not self.path else os.path.getmtime(self.path) p_time = None if not self.path else os.path.getmtime(self.path)
@@ -116,6 +115,7 @@ class Parser(CachedModule):
should work much better for builtins. should work much better for builtins.
""" """
regex = r'^(def|class)\s+([\w\d]+)' regex = r'^(def|class)\s+([\w\d]+)'
def process_code(code, depth=0): def process_code(code, depth=0):
funcs = {} funcs = {}
matches = list(re.finditer(regex, code, re.MULTILINE)) matches = list(re.finditer(regex, code, re.MULTILINE))
@@ -175,12 +175,11 @@ class Parser(CachedModule):
continue continue
# this has a builtin_function_or_method # this has a builtin_function_or_method
exe = getattr(scope, n) exe = getattr(scope, n)
#print exe, inspect.isbuiltin(exe) or inspect.ismethoddescriptor(exe)
if inspect.isbuiltin(exe) or inspect.ismethoddescriptor(exe): if inspect.isbuiltin(exe) or inspect.ismethoddescriptor(exe):
funcs[n] = exe funcs[n] = exe
elif type(exe) == type: elif inspect.isclass(exe):
classes[n] = exe classes[n] = exe
elif type(exe).__name__ == 'member_descriptor': elif inspect.ismemberdescriptor(exe):
members[n] = exe members[n] = exe
else: else:
stmts[n] = exe stmts[n] = exe
@@ -237,10 +236,11 @@ class Parser(CachedModule):
# class members (functions) properties? # class members (functions) properties?
for name, func in members.items(): for name, func in members.items():
# recursion problem in properties TODO remove
if name in ['fget', 'fset', 'fdel']: continue
ret = 'pass' ret = 'pass'
code += '@property\ndef %s(self):\n' % (name) code += '@property\ndef %s(self):\n' % (name)
block = get_doc(func, indent=True) + '%s\n\n' % ret code += parsing.indent_block(get_doc(func) + '%s\n\n' % ret)
code += parsing.indent_block(block)
# variables # variables
for name, value in stmts.items(): for name, value in stmts.items():
@@ -328,7 +328,7 @@ class _Builtin(object):
if sys.hexversion >= 0x03000000: if sys.hexversion >= 0x03000000:
name = 'builtins' name = 'builtins'
else: else:
name='__builtin__' name = '__builtin__'
_builtins = Parser(name=name) _builtins = Parser(name=name)
@property @property

View File

@@ -5,7 +5,8 @@ follow_statement -> follow_call -> follow_paths -> follow_path
`get_names_for_scope` and `get_scopes_for_name` are search functions `get_names_for_scope` and `get_scopes_for_name` are search functions
TODO doc TODO doc
TODO list comprehensions, priority? TODO list comprehensions, priority? +1
TODO `a = b if b else None` expressions
TODO evaluate asserts (type safety) TODO evaluate asserts (type safety)
python 3 stuff: python 3 stuff:
@@ -14,9 +15,10 @@ TODO annotations ? how ? type evaluation and return?
TODO nonlocal statement TODO nonlocal statement
TODO getattr / __getattr__ / __getattribute__ ? TODO getattr / __getattr__ / __getattribute__ ?
TODO descriptors (also for classes, for instances it should work) TODO descriptors (also for classes, for instances it should work)
TODO @staticmethod @classmethod (implement descriptors, builtins are done) TODO @staticmethod @classmethod (implement descriptors, builtins are done)
TODO variable assignments in classes (see test/completion/classes @230) TODO variable assignments in classes (see test/completion/classes @230) +1
""" """
from _compatibility import next, property from _compatibility import next, property
import sys import sys
@@ -219,7 +221,6 @@ class InstanceElement(object):
par = InstanceElement(self.instance, par) par = InstanceElement(self.instance, par)
return par return par
def get_parent_until(self, *classes): def get_parent_until(self, *classes):
scope = self.var.get_parent_until(*classes) scope = self.var.get_parent_until(*classes)
return InstanceElement(self.instance, scope) return InstanceElement(self.instance, scope)
@@ -233,6 +234,7 @@ class InstanceElement(object):
class Class(object): class Class(object):
__metaclass__ = CachedMetaClass __metaclass__ = CachedMetaClass
def __init__(self, base): def __init__(self, base):
self.base = base self.base = base
@@ -288,6 +290,7 @@ class Function(object):
""" """
""" """
__metaclass__ = CachedMetaClass __metaclass__ = CachedMetaClass
def __init__(self, func, is_decorated=False): def __init__(self, func, is_decorated=False):
""" This should not be called directly """ """ This should not be called directly """
self.base_func = func self.base_func = func
@@ -330,7 +333,7 @@ class Function(object):
# this is here, that the wrapper gets executed # this is here, that the wrapper gets executed
f = wrappers[0] f = wrappers[0]
debug.dbg('decorator end') debug.dbg('decorator end', f)
if f != self.base_func and isinstance(f, parsing.Function): if f != self.base_func and isinstance(f, parsing.Function):
f = Function(f) f = Function(f)
return f return f
@@ -564,12 +567,6 @@ class Execution(Executable):
Call the default method with the own instance (self implements all Call the default method with the own instance (self implements all
the necessary functions). Add also the params. the necessary functions). Add also the params.
""" """
# result = self.get_params() + parsing.Scope._get_set_vars(self)
# print '\n\ndef', result, 'par', self, self.parent
# print 'set', parsing.Scope._get_set_vars(self)
# print 'set', [r.parent for r in parsing.Scope._get_set_vars(self)]
# print 'para', [r.parent.parent for r in self.get_params()]
# return result
return self.get_params() + parsing.Scope._get_set_vars(self) return self.get_params() + parsing.Scope._get_set_vars(self)
@property @property
@@ -599,7 +596,7 @@ class Execution(Executable):
def __getattr__(self, name): def __getattr__(self, name):
if name not in ['indent', 'line_nr', 'imports']: if name not in ['indent', 'line_nr', 'imports']:
raise AttributeError('Tried to access %s. Why?' % name) raise AttributeError('Tried to access %s: %s. Why?' % (name, self))
return getattr(self.base, name) return getattr(self.base, name)
@property @property
@@ -755,14 +752,15 @@ class ArrayElement(object):
return "<%s of %s>" % (self.__class__.__name__, self.name) return "<%s of %s>" % (self.__class__.__name__, self.name)
def get_defined_names_for_position(obj, position=(float('inf'), float('inf'))): def get_defined_names_for_position(obj, position=None):
""" """
:param position: the position as a row/column tuple, default is infinity. :param position: the position as a row/column tuple, default is infinity.
""" """
names = obj.get_defined_names() names = obj.get_defined_names()
# instances have special rules, always return all the possible completions, # instances have special rules, always return all the possible completions,
# because class variables are always valid and the `self.` variables, too. # because class variables are always valid and the `self.` variables, too.
if not position or isinstance(obj, Instance): if not position or isinstance(obj, Instance) or isinstance(obj, Function) \
and isinstance(obj.decorated_func, Instance):
return names return names
names_new = [] names_new = []
for n in names: for n in names:
@@ -907,10 +905,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
if search_global: if search_global:
scope_generator = get_names_for_scope(scope, position=position) scope_generator = get_names_for_scope(scope, position=position)
else: else:
if position: names = get_defined_names_for_position(scope, position)
names = get_defined_names_for_position(scope, position)
else:
names = scope.get_defined_names()
scope_generator = iter([(scope, names)]) scope_generator = iter([(scope, names)])
return remove_statements(filter_name(scope_generator)) return remove_statements(filter_name(scope_generator))

View File

@@ -43,9 +43,9 @@ class staticmethod():
class classmethod(): class classmethod():
def __init__(self, func): def __init__(self, func):
self.func = func self._func = func
def __get__(self, obj, cls): def __get__(self, obj, cls):
def method(*args, **kwargs): def _method(*args, **kwargs):
self.func(cls, *args, **kwargs) self._func(cls, *args, **kwargs)
return method return _method

View File

@@ -150,36 +150,9 @@ CallClass()()
# ----------------- # -----------------
# properties # properties
# ----------------- # -----------------
class Property():
def __init__(self, fget, fset = None, fdel = None, doc = None):
self.fget = fget
self.fset = fset
self.fdel = fdel
self.__doc__ = doc
def __get__(self, obj, cls):
return self.fget(obj)
def __set__(self, obj, value):
self.fset(obj, value)
def __delete__(self, obj):
self.fdel(obj)
def setter(self, func):
self.fset = func
return self
def getter(self, func):
self.fget = func
return self
def deleter(self, func):
self.fdel = func
return self
class B(): class B():
@Property @property
def r(self): def r(self):
return 1 return 1
@r.setter @r.setter
@@ -187,7 +160,7 @@ class B():
pass pass
def t(self): def t(self):
return '' return ''
p = Property(t) ##p = property(t)
#? [] #? []
B().r() B().r()

View File

@@ -22,12 +22,11 @@ def run_completion_test(correct, source, line_nr, line):
try: try:
completions = functions.complete(source, line_nr, 999, completions = functions.complete(source, line_nr, 999,
completion_test_dir) completion_test_dir)
except Exception: except (Exception, functions.evaluate.MultiLevelAttributeError):
print('test @%s: %s' % (line_nr-1, line)) print('test @%s: %s' % (line_nr-1, line))
print(traceback.format_exc()) print(traceback.format_exc())
return 1 return 1
else: else:
# TODO remove sorted? completions should be sorted?
# TODO remove set! duplicates should not be normal # TODO remove set! duplicates should not be normal
comp_str = str(sorted(set([str(c) for c in completions]))) comp_str = str(sorted(set([str(c) for c in completions])))
if comp_str != correct: if comp_str != correct:
@@ -47,7 +46,7 @@ def run_definition_test(correct, source, line_nr, line, correct_start):
completion_test_dir)) completion_test_dir))
try: try:
result = defs(line_nr, 999) result = defs(line_nr, 999)
except Exception: except (Exception, functions.evaluate.MultiLevelAttributeError):
print('test @%s: %s' % (line_nr-1, line)) print('test @%s: %s' % (line_nr-1, line))
print(traceback.format_exc()) print(traceback.format_exc())
return 1 return 1