removed all the weakref stuff again. It didn't speed up anything, but made things much more complicated

This commit is contained in:
David Halter
2012-12-09 16:30:19 +01:00
parent ac610f97fb
commit 6bdda36205
11 changed files with 119 additions and 124 deletions

View File

@@ -27,7 +27,6 @@ from __future__ import with_statement
__all__ = ['Script', 'NotFoundError', 'set_debug_function'] __all__ = ['Script', 'NotFoundError', 'set_debug_function']
import re import re
import weakref
import parsing import parsing
import dynamic import dynamic
@@ -93,12 +92,12 @@ class Script(object):
""" """
def follow_imports_if_possible(name): def follow_imports_if_possible(name):
# TODO remove this, or move to another place (not used) # TODO remove this, or move to another place (not used)
par = name.parent() par = name.parent
if isinstance(par, parsing.Import) and not \ if isinstance(par, parsing.Import) and not \
isinstance(self.parser.user_stmt, parsing.Import): isinstance(self.parser.user_stmt, parsing.Import):
new = imports.ImportPath(par).follow(is_goto=True) new = imports.ImportPath(par).follow(is_goto=True)
# Only remove the old entry if a new one has been found. # Only remove the old entry if a new one has been found.
#print par, new, par.parent() #print par, new, par.parent
if new: if new:
try: try:
return new return new
@@ -198,7 +197,7 @@ class Script(object):
except IndexError: except IndexError:
raise NotFoundError() raise NotFoundError()
stmt.start_pos = self.pos stmt.start_pos = self.pos
stmt.parent = weakref.ref(self.parser.user_scope) stmt.parent = self.parser.user_scope
return stmt return stmt
def get_definition(self): def get_definition(self):

View File

@@ -48,7 +48,7 @@ class BaseOutput(object):
self.path.insert(0, par.name) self.path.insert(0, par.name)
except AttributeError: except AttributeError:
pass pass
par = par.parent() par = par.parent
@property @property
def module_name(self): def module_name(self):
@@ -113,7 +113,7 @@ class Completion(BaseOutput):
""" `Completion` objects are returned from `Script.complete`. Providing """ `Completion` objects are returned from `Script.complete`. Providing
some useful functions for IDE's. """ some useful functions for IDE's. """
def __init__(self, name, needs_dot, like_name_length, base): def __init__(self, name, needs_dot, like_name_length, base):
super(Completion, self).__init__(name.parent(), name.start_pos) super(Completion, self).__init__(name.parent, name.start_pos)
self.name = name self.name = name
self.needs_dot = needs_dot self.needs_dot = needs_dot
@@ -154,7 +154,7 @@ class Completion(BaseOutput):
def description(self): def description(self):
""" Provides a description of the completion object """ Provides a description of the completion object
TODO return value is just __repr__ of some objects, improve! """ TODO return value is just __repr__ of some objects, improve! """
parent = self.name.parent() parent = self.name.parent
if parent is None: if parent is None:
return '' return ''
t = self.type t = self.type
@@ -175,7 +175,7 @@ class Definition(BaseOutput):
`Script.get_definition`. """ `Script.get_definition`. """
def __init__(self, definition): def __init__(self, definition):
super(Definition, self).__init__(definition, definition.start_pos) super(Definition, self).__init__(definition, definition.start_pos)
self._def_parent = definition.parent() # just here to limit gc self._def_parent = definition.parent # just here to limit gc
@property @property
def description(self): def description(self):
@@ -185,7 +185,7 @@ class Definition(BaseOutput):
if isinstance(d, evaluate.InstanceElement): if isinstance(d, evaluate.InstanceElement):
d = d.var d = d.var
if isinstance(d, evaluate.parsing.Name): if isinstance(d, evaluate.parsing.Name):
d = d.parent() d = d.parent
if isinstance(d, evaluate.Array): if isinstance(d, evaluate.Array):
d = 'class ' + d.type d = 'class ' + d.type

View File

@@ -463,7 +463,7 @@ class Builtin(object):
parser = parsing.PyFuzzyParser(source, None) parser = parsing.PyFuzzyParser(source, None)
# needed for caching (because of weakref) # needed for caching (because of weakref)
module = self.magic_func_module = parser.module module = self.magic_func_module = parser.module
module.parent = lambda: self.scope module.parent = self.scope
typ = evaluate.follow_path(iter(['FunctionType']), module, module) typ = evaluate.follow_path(iter(['FunctionType']), module, module)
self._magic_function_scope = s = typ.pop() self._magic_function_scope = s = typ.pop()

View File

@@ -7,8 +7,8 @@ import evaluate
#@evaluate.memoize_default() # TODO add #@evaluate.memoize_default() # TODO add
def follow_param(param): def follow_param(param):
func = param.parent_function() func = param.parent_function
#print func, param, param.parent_function() #print func, param, param.parent_function
param_str = search_param_in_docstr(func.docstr, str(param.get_name())) param_str = search_param_in_docstr(func.docstr, str(param.get_name()))
if param_str is not None: if param_str is not None:

View File

@@ -128,7 +128,7 @@ def search_params(param):
# no execution means that params cannot be set # no execution means that params cannot be set
call_path = c.generate_call_path() call_path = c.generate_call_path()
pos = c.start_pos pos = c.start_pos
scope = stmt.parent() scope = stmt.parent
evaluate.follow_call_path(call_path, scope, pos) evaluate.follow_call_path(call_path, scope, pos)
return listener.param_possibilities return listener.param_possibilities
@@ -136,14 +136,14 @@ def search_params(param):
for params in get_posibilities(module, func_name): for params in get_posibilities(module, func_name):
for p in params: for p in params:
if str(p) == param_name: if str(p) == param_name:
result += evaluate.follow_statement(p.parent()) result += evaluate.follow_statement(p.parent)
return result return result
func = param.get_parent_until(parsing.Function) func = param.get_parent_until(parsing.Function)
current_module = param.get_parent_until() current_module = param.get_parent_until()
func_name = str(func.name) func_name = str(func.name)
if func_name == '__init__' and isinstance(func.parent(), parsing.Class): if func_name == '__init__' and isinstance(func.parent, parsing.Class):
func_name = str(func.parent().name) func_name = str(func.parent.name)
# get the param name # get the param name
if param.assignment_details: if param.assignment_details:
@@ -177,7 +177,7 @@ def check_array_additions(array):
return [] return []
is_list = array._array.type == 'list' is_list = array._array.type == 'list'
current_module = array._array.parent_stmt().get_parent_until() current_module = array._array.parent_stmt.get_parent_until()
res = _check_array_additions(array, current_module, is_list) res = _check_array_additions(array, current_module, is_list)
return res return res
@@ -209,10 +209,10 @@ def dec(func):
global counter global counter
element = args[0] element = args[0]
if isinstance(element, evaluate.Array): if isinstance(element, evaluate.Array):
stmt = element._array.parent_stmt() stmt = element._array.parent_stmt
else: else:
# must be instance # must be instance
stmt = element.var_args.parent_stmt() stmt = element.var_args.parent_stmt
print(' ' * counter + 'recursion,', stmt) print(' ' * counter + 'recursion,', stmt)
counter += 1 counter += 1
res = func(*args, **kwargs) res = func(*args, **kwargs)
@@ -249,7 +249,7 @@ def _check_array_additions(compare_array, module, is_list):
backtrack_path = iter(call_path[:separate_index]) backtrack_path = iter(call_path[:separate_index])
position = c.start_pos position = c.start_pos
scope = c.parent_stmt().parent() scope = c.parent_stmt.parent
found = evaluate.follow_call_path(backtrack_path, scope, position) found = evaluate.follow_call_path(backtrack_path, scope, position)
if not compare_array in found: if not compare_array in found:
@@ -275,10 +275,10 @@ def _check_array_additions(compare_array, module, is_list):
def get_execution_parent(element, *stop_classes): def get_execution_parent(element, *stop_classes):
""" Used to get an Instance/Execution parent """ """ Used to get an Instance/Execution parent """
if isinstance(element, evaluate.Array): if isinstance(element, evaluate.Array):
stmt = element._array.parent_stmt() stmt = element._array.parent_stmt
else: else:
# must be instance # must be instance
stmt = element.var_args.parent_stmt() stmt = element.var_args.parent_stmt
if isinstance(stmt, evaluate.InstanceElement): if isinstance(stmt, evaluate.InstanceElement):
stop_classes = list(stop_classes) + [evaluate.Function] stop_classes = list(stop_classes) + [evaluate.Function]
return stmt.get_parent_until(stop_classes) return stmt.get_parent_until(stop_classes)
@@ -326,7 +326,7 @@ def check_array_instances(instance):
if not settings.dynamic_arrays_instances: if not settings.dynamic_arrays_instances:
return instance.var_args return instance.var_args
ai = ArrayInstance(instance) ai = ArrayInstance(instance)
return helpers.generate_param_array([ai], instance.var_args.parent_stmt()) return helpers.generate_param_array([ai], instance.var_args.parent_stmt)
class ArrayInstance(parsing.Base): class ArrayInstance(parsing.Base):
@@ -358,10 +358,10 @@ class ArrayInstance(parsing.Base):
continue continue
items += evaluate.get_iterator_types([array]) items += evaluate.get_iterator_types([array])
if self.var_args.parent_stmt() is None: if self.var_args.parent_stmt is None:
return [] # generated var_args should not be checked for arrays return [] # generated var_args should not be checked for arrays
module = self.var_args.parent_stmt().get_parent_until() module = self.var_args.parent_stmt.get_parent_until()
is_list = str(self.instance.name) == 'list' is_list = str(self.instance.name) == 'list'
items += _check_array_additions(self.instance, module, is_list) items += _check_array_additions(self.instance, module, is_list)
return items return items
@@ -378,13 +378,13 @@ def related_names(definitions, search_name, mods):
follow.append(call_path[:i + 1]) follow.append(call_path[:i + 1])
for f in follow: for f in follow:
follow_res, search = evaluate.goto(call.parent_stmt(), f) follow_res, search = evaluate.goto(call.parent_stmt, f)
follow_res = related_name_add_import_modules(follow_res, search) follow_res = related_name_add_import_modules(follow_res, search)
#print follow_res, [d.parent() for d in follow_res] #print follow_res, [d.parent for d in follow_res]
# compare to see if they match # compare to see if they match
if any(r in definitions for r in follow_res): if any(r in definitions for r in follow_res):
scope = call.parent_stmt() scope = call.parent_stmt
result.append(api_classes.RelatedName(search, scope)) result.append(api_classes.RelatedName(search, scope))
return result return result
@@ -442,8 +442,8 @@ def related_name_add_import_modules(definitions, search_name):
""" Adds the modules of the imports """ """ Adds the modules of the imports """
new = set() new = set()
for d in definitions: for d in definitions:
if isinstance(d.parent(), parsing.Import): if isinstance(d.parent, parsing.Import):
s = imports.ImportPath(d.parent(), direct_resolve=True) s = imports.ImportPath(d.parent, direct_resolve=True)
try: try:
new.add(s.follow(is_goto=True)[0]) new.add(s.follow(is_goto=True)[0])
except IndexError: except IndexError:

View File

@@ -17,7 +17,6 @@ from _compatibility import next, property, hasattr, is_py3k, use_metaclass, \
import sys import sys
import itertools import itertools
import copy import copy
import weakref
import parsing import parsing
import debug import debug
@@ -136,8 +135,9 @@ class Executable(parsing.Base):
def get_parent_until(self, *args, **kwargs): def get_parent_until(self, *args, **kwargs):
return self.base.get_parent_until(*args, **kwargs) return self.base.get_parent_until(*args, **kwargs)
@property
def parent(self): def parent(self):
return self.base.parent() return self.base.parent
class Instance(use_metaclass(CachedMetaClass, Executable)): class Instance(use_metaclass(CachedMetaClass, Executable)):
@@ -215,8 +215,8 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
if args is None: if args is None:
args = helpers.generate_param_array([]) args = helpers.generate_param_array([])
method = self.get_subscope_by_name(name) method = self.get_subscope_by_name(name)
if args.parent_stmt() is None: if args.parent_stmt is None:
args.parent_stmt = weakref.ref(method) args.parent_stmt = method
return Execution(method, args).get_return_types() return Execution(method, args).get_return_types()
def get_descriptor_return(self, obj): def get_descriptor_return(self, obj):
@@ -287,9 +287,10 @@ class InstanceElement(use_metaclass(CachedMetaClass)):
self.var = var self.var = var
self.is_class_var = is_class_var self.is_class_var = is_class_var
@property
@memoize_default() @memoize_default()
def parent(self): def parent(self):
par = self.var.parent() par = self.var.parent
if isinstance(par, Class) and par == self.instance.base \ if isinstance(par, Class) and par == self.instance.base \
or isinstance(par, parsing.Class) \ or isinstance(par, parsing.Class) \
and par == self.instance.base.base: and par == self.instance.base.base:
@@ -313,9 +314,9 @@ class InstanceElement(use_metaclass(CachedMetaClass)):
origin = self.var.get_assignment_calls() origin = self.var.get_assignment_calls()
# Delete parent, because it isn't used anymore. # Delete parent, because it isn't used anymore.
new = helpers.fast_parent_copy(origin) new = helpers.fast_parent_copy(origin)
par = InstanceElement(self.instance, origin.parent_stmt(), par = InstanceElement(self.instance, origin.parent_stmt,
self.is_class_var) self.is_class_var)
new.parent_stmt = weakref.ref(par) new.parent_stmt = par
faked_scopes.append(par) faked_scopes.append(par)
faked_scopes.append(new) faked_scopes.append(new)
return new return new
@@ -485,7 +486,7 @@ class Execution(Executable):
def get_return_types(self, evaluate_generator=False): def get_return_types(self, evaluate_generator=False):
""" Get the return types of a function. """ """ Get the return types of a function. """
stmts = [] stmts = []
if self.base.parent() == builtin.Builtin.scope \ if self.base.parent == builtin.Builtin.scope \
and not isinstance(self.base, (Generator, Array)): and not isinstance(self.base, (Generator, Array)):
func_name = str(self.base.name) func_name = str(self.base.name)
@@ -566,7 +567,7 @@ class Execution(Executable):
""" """
Create a param with the original scope (of varargs) as parent. Create a param with the original scope (of varargs) as parent.
""" """
parent_stmt = self.var_args.parent_stmt() parent_stmt = self.var_args.parent_stmt
pos = parent_stmt.start_pos if parent_stmt else None pos = parent_stmt.start_pos if parent_stmt else None
calls = parsing.Array(pos, parsing.Array.NOARRAY, parent_stmt) calls = parsing.Array(pos, parsing.Array.NOARRAY, parent_stmt)
calls.values = values calls.values = values
@@ -574,12 +575,12 @@ class Execution(Executable):
calls.type = array_type calls.type = array_type
new_param = copy.copy(param) new_param = copy.copy(param)
if parent_stmt is not None: if parent_stmt is not None:
new_param.parent = weakref.ref(parent_stmt) new_param.parent = parent_stmt
new_param._assignment_calls_calculated = True new_param._assignment_calls_calculated = True
new_param._assignment_calls = calls new_param._assignment_calls = calls
new_param.is_generated = True new_param.is_generated = True
name = copy.copy(param.get_name()) name = copy.copy(param.get_name())
name.parent = weakref.ref(new_param) name.parent = new_param
faked_scopes.append(new_param) faked_scopes.append(new_param)
return name return name
@@ -589,7 +590,7 @@ class Execution(Executable):
# Care for self -> just exclude it and add the instance # Care for self -> just exclude it and add the instance
start_offset = 1 start_offset = 1
self_name = copy.copy(self.base.params[0].get_name()) self_name = copy.copy(self.base.params[0].get_name())
self_name.parent = weakref.ref(self.base.instance) self_name.parent = self.base.instance
result.append(self_name) result.append(self_name)
param_dict = {} param_dict = {}
@@ -732,7 +733,7 @@ class Execution(Executable):
objects = [] objects = []
for element in attr: for element in attr:
copied = helpers.fast_parent_copy(element) copied = helpers.fast_parent_copy(element)
copied.parent = weakref.ref(self._scope_copy(copied.parent())) copied.parent = self._scope_copy(copied.parent)
if isinstance(copied, parsing.Function): if isinstance(copied, parsing.Function):
copied = Function(copied) copied = Function(copied)
objects.append(copied) objects.append(copied)
@@ -756,9 +757,7 @@ class Execution(Executable):
return self return self
else: else:
copied = helpers.fast_parent_copy(scope) copied = helpers.fast_parent_copy(scope)
#copied.parent = self._scope_copy(copied.parent()) copied.parent = self._scope_copy(copied.parent)
copied.parent = weakref.ref(self._scope_copy(copied.parent()))
#copied.parent = weakref.ref(self)
faked_scopes.append(copied) faked_scopes.append(copied)
return copied return copied
except AttributeError: except AttributeError:
@@ -810,7 +809,7 @@ class Generator(use_metaclass(CachedMetaClass, parsing.Base)):
for n in ('close', 'throw') + executes_generator: for n in ('close', 'throw') + executes_generator:
name = parsing.Name([(n, none_pos)], none_pos, none_pos) name = parsing.Name([(n, none_pos)], none_pos, none_pos)
if n in executes_generator: if n in executes_generator:
name.parent = weakref.ref(self) name.parent = self
names.append(name) names.append(name)
debug.dbg('generator names', names) debug.dbg('generator names', names)
return names return names
@@ -823,8 +822,9 @@ class Generator(use_metaclass(CachedMetaClass, parsing.Base)):
debug.warning('Tried to get array access on a generator', self) debug.warning('Tried to get array access on a generator', self)
return [] return []
@property
def parent(self): def parent(self):
return self.func.parent() return self.func.parent
def __repr__(self): def __repr__(self):
return "<%s of %s>" % (type(self).__name__, self.func) return "<%s of %s>" % (type(self).__name__, self.func)
@@ -906,6 +906,7 @@ class Array(use_metaclass(CachedMetaClass, parsing.Base)):
def get_contents(self): def get_contents(self):
return self._array return self._array
@property
def parent(self): def parent(self):
""" """
Return the builtin scope as parent, because the arrays are builtins Return the builtin scope as parent, because the arrays are builtins
@@ -998,7 +999,7 @@ def get_names_for_scope(scope, position=None, star_search=True,
# is a list comprehension # is a list comprehension
yield scope, scope.get_set_vars(is_internal_call=True) yield scope, scope.get_set_vars(is_internal_call=True)
scope = scope.parent() scope = scope.parent
# This is used, because subscopes (Flow scopes) would distort the # This is used, because subscopes (Flow scopes) would distort the
# results. # results.
if scope and scope.isinstance(Function, parsing.Function, Execution): if scope and scope.isinstance(Function, parsing.Function, Execution):
@@ -1047,14 +1048,14 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
if r.is_global(): if r.is_global():
for token_name in r.token_list[1:]: for token_name in r.token_list[1:]:
if isinstance(token_name, parsing.Name): if isinstance(token_name, parsing.Name):
add = get_scopes_for_name(r.parent(), add = get_scopes_for_name(r.parent,
str(token_name)) str(token_name))
else: else:
# generated objects are used within executions, but these # generated objects are used within executions, but these
# objects are in functions, and we have to dynamically # objects are in functions, and we have to dynamically
# execute first. # execute first.
if isinstance(r, parsing.Param): if isinstance(r, parsing.Param):
func = r.parent() func = r.parent
# Instances are typically faked, if the instance is not # Instances are typically faked, if the instance is not
# called from outside. Here we check it for __init__ # called from outside. Here we check it for __init__
# functions and return. # functions and return.
@@ -1124,7 +1125,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
""" """
result = [] result = []
no_break_scope = False no_break_scope = False
par = name.parent() par = name.parent
if par.isinstance(parsing.Flow): if par.isinstance(parsing.Flow):
if par.command == 'for': if par.command == 'for':
@@ -1132,8 +1133,8 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
else: else:
debug.warning('Flow: Why are you here? %s' % par.command) debug.warning('Flow: Why are you here? %s' % par.command)
elif par.isinstance(parsing.Param) \ elif par.isinstance(parsing.Param) \
and par.parent() is not None \ and par.parent is not None \
and par.parent().parent().isinstance(parsing.Class) \ and par.parent.parent.isinstance(parsing.Class) \
and par.position_nr == 0: and par.position_nr == 0:
# This is where self gets added - this happens at another # This is where self gets added - this happens at another
# place, if the var_args are clear. But sometimes the class is # place, if the var_args are clear. But sometimes the class is
@@ -1142,7 +1143,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
if isinstance(scope, InstanceElement): if isinstance(scope, InstanceElement):
inst = scope.instance inst = scope.instance
else: else:
inst = Instance(Class(par.parent().parent())) inst = Instance(Class(par.parent.parent))
inst.is_generated = True inst.is_generated = True
result.append(inst) result.append(inst)
elif par.isinstance(parsing.Statement): elif par.isinstance(parsing.Statement):
@@ -1188,7 +1189,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
break_scopes = [] break_scopes = []
# here is the position stuff happening (sorting of variables) # here is the position stuff happening (sorting of variables)
for name in sorted(name_list, key=comparison_func, reverse=True): for name in sorted(name_list, key=comparison_func, reverse=True):
p = name.parent().parent() if name.parent() else None p = name.parent.parent if name.parent else None
if isinstance(p, InstanceElement) \ if isinstance(p, InstanceElement) \
and isinstance(p.var, parsing.Class): and isinstance(p.var, parsing.Class):
p = p.var p = p.var
@@ -1206,7 +1207,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
# this means that a definition was found and is not e.g. # this means that a definition was found and is not e.g.
# in if/else. # in if/else.
if result and not no_break_scope: if result and not no_break_scope:
if not name.parent() or p == s: if not name.parent or p == s:
break break
break_scopes.append(p) break_scopes.append(p)
@@ -1222,7 +1223,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
break break
if flow_scope == nscope: if flow_scope == nscope:
break break
flow_scope = flow_scope.parent() flow_scope = flow_scope.parent
flow_scope = nscope flow_scope = nscope
if result: if result:
break break
@@ -1427,9 +1428,9 @@ def follow_call_list(call_list):
loop = parsing.ForFlow([input], lc.stmt.start_pos, loop = parsing.ForFlow([input], lc.stmt.start_pos,
lc.middle, True) lc.middle, True)
if parent is None: if parent is None:
loop.parent = weakref.ref(lc.stmt.parent()) loop.parent = lc.stmt.parent
else: else:
loop.parent = lambda: parent loop.parent = parent
if isinstance(nested_lc, parsing.ListComprehension): if isinstance(nested_lc, parsing.ListComprehension):
loop = evaluate_list_comprehension(nested_lc, loop) loop = evaluate_list_comprehension(nested_lc, loop)
@@ -1450,7 +1451,7 @@ def follow_call_list(call_list):
elif isinstance(call, parsing.ListComprehension): elif isinstance(call, parsing.ListComprehension):
loop = evaluate_list_comprehension(call) loop = evaluate_list_comprehension(call)
stmt = copy.copy(call.stmt) stmt = copy.copy(call.stmt)
stmt.parent = lambda: loop stmt.parent = loop
# create a for loop which does the same as list # create a for loop which does the same as list
# comprehensions # comprehensions
result += follow_statement(stmt) result += follow_statement(stmt)
@@ -1486,9 +1487,9 @@ def follow_call_list(call_list):
def follow_call(call): def follow_call(call):
""" Follow a call is following a function, variable, string, etc. """ """ Follow a call is following a function, variable, string, etc. """
scope = call.parent_stmt().parent() scope = call.parent_stmt.parent
path = call.generate_call_path() path = call.generate_call_path()
position = call.parent_stmt().start_pos position = call.parent_stmt.start_pos
return follow_call_path(path, scope, position) return follow_call_path(path, scope, position)
@@ -1596,7 +1597,7 @@ def goto(stmt, call_path=None):
call = arr.get_only_subelement() call = arr.get_only_subelement()
call_path = list(call.generate_call_path()) call_path = list(call.generate_call_path())
scope = stmt.parent() scope = stmt.parent
pos = stmt.start_pos pos = stmt.start_pos
call_path, search = call_path[:-1], call_path[-1] call_path, search = call_path[:-1], call_path[-1]
if call_path: if call_path:

View File

@@ -1,5 +1,4 @@
import copy import copy
import weakref
import contextlib import contextlib
import parsing import parsing
@@ -164,10 +163,10 @@ def fast_parent_copy(obj):
# parent can be a property # parent can be a property
continue continue
try: try:
setattr(new_obj, key, weakref.ref(new_elements[value()])) setattr(new_obj, key, new_elements[value])
except KeyError: except KeyError:
pass pass
elif key == 'parent_stmt': elif key in ['parent_stmt', 'parent_function']:
continue continue
elif isinstance(value, list): elif isinstance(value, list):
setattr(new_obj, key, list_rec(value)) setattr(new_obj, key, list_rec(value))

View File

@@ -4,7 +4,6 @@ import os
import pkgutil import pkgutil
import imp import imp
import sys import sys
import weakref
import time import time
import builtin import builtin
@@ -84,7 +83,7 @@ class ImportPath(parsing.Base):
zero = (0, 0) zero = (0, 0)
n = parsing.Name(i.namespace.names[1:], zero, zero, self.import_stmt) n = parsing.Name(i.namespace.names[1:], zero, zero, self.import_stmt)
new = parsing.Import(zero, zero, n) new = parsing.Import(zero, zero, n)
new.parent = weakref.ref(parent) new.parent = parent
evaluate.faked_scopes.append(new) evaluate.faked_scopes.append(new)
debug.dbg('Generated a nested import: %s' % new) debug.dbg('Generated a nested import: %s' % new)
return new return new

View File

@@ -36,11 +36,10 @@ class Keyword(object):
def __init__(self, name, pos): def __init__(self, name, pos):
self.name = name self.name = name
self.start_pos = pos self.start_pos = pos
self.parent = builtin.Builtin.scope
def parent(self): def get_parent_until(self):
return builtin.Builtin.scope return self.parent
get_parent_until = parent
@property @property
def names(self): def names(self):

View File

@@ -34,7 +34,6 @@ from _compatibility import (next, literal_eval, StringIO,
import tokenize import tokenize
import re import re
import keyword import keyword
import weakref
import os import os
import debug import debug
@@ -97,7 +96,7 @@ class Simple(Base):
def __init__(self, start_pos, end_pos=(None, None)): def __init__(self, start_pos, end_pos=(None, None)):
self.start_pos = start_pos self.start_pos = start_pos
self.end_pos = end_pos self.end_pos = end_pos
self.parent = lambda: None self.parent = None
@Python3Method @Python3Method
def get_parent_until(self, classes=(), reverse=False, def get_parent_until(self, classes=(), reverse=False,
@@ -106,12 +105,12 @@ class Simple(Base):
if type(classes) not in (tuple, list): if type(classes) not in (tuple, list):
classes = (classes,) classes = (classes,)
scope = self scope = self
while not scope.parent() is None: while scope.parent is not None:
if classes and reverse != scope.isinstance(*classes): if classes and reverse != scope.isinstance(*classes):
if include_current: if include_current:
return scope return scope
break break
scope = scope.parent() scope = scope.parent
return scope return scope
def __repr__(self): def __repr__(self):
@@ -142,7 +141,7 @@ class Scope(Simple):
self.asserts = [] self.asserts = []
def add_scope(self, sub, decorators): def add_scope(self, sub, decorators):
sub.parent = weakref.ref(self) sub.parent = self
sub.decorators = decorators sub.decorators = decorators
for d in decorators: for d in decorators:
# the parent is the same, because the decorator has not the scope # the parent is the same, because the decorator has not the scope
@@ -156,7 +155,7 @@ class Scope(Simple):
Used to add a Statement or a Scope. Used to add a Statement or a Scope.
A statement would be a normal command (Statement) or a Scope (Flow). A statement would be a normal command (Statement) or a Scope (Flow).
""" """
stmt.parent = weakref.ref(self) stmt.parent = self
self.statements.append(stmt) self.statements.append(stmt)
return stmt return stmt
@@ -166,7 +165,7 @@ class Scope(Simple):
def add_import(self, imp): def add_import(self, imp):
self.imports.append(imp) self.imports.append(imp)
imp.parent = weakref.ref(self) imp.parent = self
def get_imports(self): def get_imports(self):
""" Gets also the imports within flow statements """ """ Gets also the imports within flow statements """
@@ -330,10 +329,10 @@ class Class(Scope):
def __init__(self, name, supers, start_pos, docstr=''): def __init__(self, name, supers, start_pos, docstr=''):
super(Class, self).__init__(start_pos, docstr) super(Class, self).__init__(start_pos, docstr)
self.name = name self.name = name
name.parent = weakref.ref(self) name.parent = self
self.supers = supers self.supers = supers
for s in self.supers: for s in self.supers:
s.parent = weakref.ref(self) s.parent = self
self.decorators = [] self.decorators = []
def get_code(self, first_indent=False, indention=' '): def get_code(self, first_indent=False, indention=' '):
@@ -365,18 +364,18 @@ class Function(Scope):
def __init__(self, name, params, start_pos, annotation): def __init__(self, name, params, start_pos, annotation):
Scope.__init__(self, start_pos) Scope.__init__(self, start_pos)
self.name = name self.name = name
name.parent = weakref.ref(self) name.parent = self
self.params = params self.params = params
for p in params: for p in params:
p.parent = weakref.ref(self) p.parent = self
p.parent_function = weakref.ref(self) p.parent_function = self
self.decorators = [] self.decorators = []
self.returns = [] self.returns = []
self.is_generator = False self.is_generator = False
self.listeners = set() # not used here, but in evaluation. self.listeners = set() # not used here, but in evaluation.
if annotation is not None: if annotation is not None:
annotation.parent = weakref.ref(self) annotation.parent = self
self.annotation = annotation self.annotation = annotation
def get_code(self, first_indent=False, indention=' '): def get_code(self, first_indent=False, indention=' '):
@@ -459,14 +458,14 @@ class Flow(Scope):
# These have to be statements, because of with, which takes multiple. # These have to be statements, because of with, which takes multiple.
self.inits = inits self.inits = inits
for s in inits: for s in inits:
s.parent = weakref.ref(self) s.parent = self
if set_vars is None: if set_vars is None:
self.set_vars = [] self.set_vars = []
else: else:
self.set_vars = set_vars self.set_vars = set_vars
for s in self.set_vars: for s in self.set_vars:
s.parent().parent = lambda: self s.parent.parent = self
s.parent = weakref.ref(self) s.parent = self
@property @property
def parent(self): def parent(self):
@@ -573,7 +572,7 @@ class Import(Simple):
self.from_ns = from_ns self.from_ns = from_ns
for n in [namespace, alias, from_ns]: for n in [namespace, alias, from_ns]:
if n: if n:
n.parent = weakref.ref(self) n.parent = self
self.star = star self.star = star
self.relative_count = relative_count self.relative_count = relative_count
@@ -609,7 +608,7 @@ class Import(Simple):
if len(self.namespace) > 1: if len(self.namespace) > 1:
o = self.namespace o = self.namespace
n = Name([(o.names[0], o.start_pos)], o.start_pos, o.end_pos, n = Name([(o.names[0], o.start_pos)], o.start_pos, o.end_pos,
parent=o.parent()) parent=o.parent)
return [n] return [n]
else: else:
return [self.namespace] return [self.namespace]
@@ -656,7 +655,7 @@ class Statement(Simple):
self.used_vars = used_vars self.used_vars = used_vars
self.token_list = token_list self.token_list = token_list
for s in set_vars + used_funcs + used_vars: for s in set_vars + used_funcs + used_vars:
s.parent = weakref.ref(self) s.parent = self
self.set_vars = self._remove_executions_from_set_vars(set_vars) self.set_vars = self._remove_executions_from_set_vars(set_vars)
# cache # cache
@@ -793,10 +792,10 @@ class Statement(Simple):
close_brackets = False close_brackets = False
else: else:
if close_brackets: if close_brackets:
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
if type(result) == Call: if type(result) == Call:
result = result.parent() result = result.parent
call = Call(tok, c_type, start_pos, parent=result) call = Call(tok, c_type, start_pos, parent=result)
result.add_to_current_field(call) result.add_to_current_field(call)
result = call result = call
@@ -804,28 +803,28 @@ class Statement(Simple):
level += 1 level += 1
if is_call_or_close(): if is_call_or_close():
result = Array(start_pos, brackets[tok], parent=result) result = Array(start_pos, brackets[tok], parent=result)
result = result.parent().add_execution(result) result = result.parent.add_execution(result)
close_brackets = False close_brackets = False
else: else:
result = Array(start_pos, brackets[tok], parent=result) result = Array(start_pos, brackets[tok], parent=result)
result.parent().add_to_current_field(result) result.parent.add_to_current_field(result)
elif tok == ':': elif tok == ':':
while is_call_or_close(): while is_call_or_close():
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
if result.type == Array.LIST: # [:] lookups if result.type == Array.LIST: # [:] lookups
result.add_to_current_field(tok) result.add_to_current_field(tok)
else: else:
result.add_dictionary_key() result.add_dictionary_key()
elif tok == '.': elif tok == '.':
if close_brackets and result.parent() != top: if close_brackets and result.parent != top:
# only get out of the array, if it is a array execution # only get out of the array, if it is a array execution
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
is_chain = True is_chain = True
elif tok == ',': elif tok == ',':
while is_call_or_close(): while is_call_or_close():
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
result.add_field((start_pos[0], start_pos[1] + 1)) result.add_field((start_pos[0], start_pos[1] + 1))
# important - it cannot be empty anymore # important - it cannot be empty anymore
@@ -833,7 +832,7 @@ class Statement(Simple):
result.type = Array.TUPLE result.type = Array.TUPLE
elif tok in [')', '}', ']']: elif tok in [')', '}', ']']:
while is_call_or_close(): while is_call_or_close():
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
if tok == '}' and not len(result): if tok == '}' and not len(result):
# this is a really special case - empty brackets {} are # this is a really special case - empty brackets {} are
@@ -844,7 +843,7 @@ class Statement(Simple):
close_brackets = True close_brackets = True
else: else:
while is_call_or_close(): while is_call_or_close():
result = result.parent() result = result.parent
close_brackets = False close_brackets = False
if tok != '\n': if tok != '\n':
result.add_to_current_field(tok) result.add_to_current_field(tok)
@@ -876,7 +875,7 @@ class Param(Statement):
self.parent_function = None self.parent_function = None
def add_annotation(self, annotation_stmt): def add_annotation(self, annotation_stmt):
annotation_stmt.parent = weakref.ref(self) annotation_stmt.parent = self
self.annotation_stmt = annotation_stmt self.annotation_stmt = annotation_stmt
def get_name(self): def get_name(self):
@@ -900,22 +899,22 @@ class Call(Base):
self.name = name self.name = name
# parent is not the oposite of next. The parent of c: a = [b.c] would # parent is not the oposite of next. The parent of c: a = [b.c] would
# be an array. # be an array.
self.parent = weakref.ref(parent) if parent is not None else None self.parent = parent
self.type = type self.type = type
self.start_pos = start_pos self.start_pos = start_pos
self.next = None self.next = None
self.execution = None self.execution = None
self._parent_stmt = weakref.ref(parent_stmt) if parent_stmt else None self._parent_stmt = parent_stmt
@property @property
def parent_stmt(self): def parent_stmt(self):
if self._parent_stmt is not None: if self._parent_stmt is not None:
return self._parent_stmt return self._parent_stmt
elif self.parent: elif self.parent:
return self.parent().parent_stmt return self.parent.parent_stmt
else: else:
return lambda: None return None
@parent_stmt.setter @parent_stmt.setter
def parent_stmt(self, value): def parent_stmt(self, value):
@@ -935,10 +934,10 @@ class Call(Base):
self.execution = call self.execution = call
# there might be multiple executions, like a()[0], in that case, they # there might be multiple executions, like a()[0], in that case, they
# have the same parent. Otherwise it's not possible to parse proper. # have the same parent. Otherwise it's not possible to parse proper.
if self.parent().execution == self: if self.parent.execution == self:
call.parent = self.parent call.parent = self.parent
else: else:
call.parent = weakref.ref(self) call.parent = self
return call return call
def generate_call_path(self): def generate_call_path(self):
@@ -1126,7 +1125,7 @@ class Name(Simple):
self.names = tuple(n if isinstance(n, NamePart) else NamePart(*n) self.names = tuple(n if isinstance(n, NamePart) else NamePart(*n)
for n in names) for n in names)
if parent is not None: if parent is not None:
self.parent = weakref.ref(parent) self.parent = parent
def get_code(self): def get_code(self):
""" Returns the names in a full string format """ """ Returns the names in a full string format """
@@ -1497,7 +1496,7 @@ class PyFuzzyParser(object):
if middle is None: if middle is None:
level -= 1 level -= 1
else: else:
middle.parent = weakref.ref(self.scope) middle.parent = self.scope
debug.warning('list comprehension formatting @%s' % debug.warning('list comprehension formatting @%s' %
self.start_pos[0]) self.start_pos[0])
continue continue
@@ -1506,12 +1505,12 @@ class PyFuzzyParser(object):
in_clause, tok = self._parse_statement(added_breaks=b, in_clause, tok = self._parse_statement(added_breaks=b,
list_comp=True) list_comp=True)
if tok not in b or in_clause is None: if tok not in b or in_clause is None:
middle.parent = weakref.ref(self.scope) middle.parent = self.scope
if in_clause is None: if in_clause is None:
self.gen.push_back(self._current_full) self.gen.push_back(self._current_full)
else: else:
in_clause.parent = weakref.ref(self.scope) in_clause.parent = self.scope
in_clause.parent = weakref.ref(self.scope) in_clause.parent = self.scope
debug.warning('list comprehension in_clause %s@%s' debug.warning('list comprehension in_clause %s@%s'
% (tok, self.start_pos[0])) % (tok, self.start_pos[0]))
continue continue
@@ -1539,7 +1538,7 @@ class PyFuzzyParser(object):
toks, first_pos, self.end_pos) toks, first_pos, self.end_pos)
for s in [st, middle, in_clause]: for s in [st, middle, in_clause]:
s.parent = weakref.ref(self.scope) s.parent = self.scope
tok = ListComprehension(st, middle, in_clause) tok = ListComprehension(st, middle, in_clause)
tok_list.append(tok) tok_list.append(tok)
if list_comp: if list_comp:
@@ -1633,7 +1632,7 @@ class PyFuzzyParser(object):
s = self.scope s = self.scope
while s is not None: while s is not None:
s.end_pos = self.end_pos s.end_pos = self.end_pos
s = s.parent() s = s.parent
raise raise
type, tok, self._tokenize_start_pos, self._tokenize_end_pos, \ type, tok, self._tokenize_start_pos, self._tokenize_end_pos, \
@@ -1679,7 +1678,7 @@ class PyFuzzyParser(object):
token_type, tok = self.next() token_type, tok = self.next()
if self.start_pos[1] <= self.scope.start_pos[1]: if self.start_pos[1] <= self.scope.start_pos[1]:
self.scope.end_pos = self.start_pos self.scope.end_pos = self.start_pos
self.scope = self.scope.parent() self.scope = self.scope.parent
# check again for unindented stuff. this is true for syntax # check again for unindented stuff. this is true for syntax
# errors. only check for names, because thats relevant here. If # errors. only check for names, because thats relevant here. If
@@ -1688,7 +1687,7 @@ class PyFuzzyParser(object):
and (token_type == tokenize.NAME or tok in ['(', '['])\ and (token_type == tokenize.NAME or tok in ['(', '['])\
and self.scope != self.module: and self.scope != self.module:
self.scope.end_pos = self.start_pos self.scope.end_pos = self.start_pos
self.scope = self.scope.parent() self.scope = self.scope.parent
first_pos = self.start_pos first_pos = self.start_pos
if tok == 'def': if tok == 'def':
@@ -1763,14 +1762,14 @@ class PyFuzzyParser(object):
debug.warning('syntax err, for flow started @%s', debug.warning('syntax err, for flow started @%s',
self.start_pos[0]) self.start_pos[0])
if statement is not None: if statement is not None:
statement.parent = weakref.ref(self.scope) statement.parent = self.scope
if set_stmt is not None: if set_stmt is not None:
set_stmt.parent = weakref.ref(self.scope) set_stmt.parent = self.scope
else: else:
debug.warning('syntax err, for flow incomplete @%s', debug.warning('syntax err, for flow incomplete @%s',
self.start_pos[0]) self.start_pos[0])
if set_stmt is not None: if set_stmt is not None:
set_stmt.parent = weakref.ref(self.scope) set_stmt.parent = self.scope
elif tok in ['if', 'while', 'try', 'with'] + extended_flow: elif tok in ['if', 'while', 'try', 'with'] + extended_flow:
added_breaks = [] added_breaks = []
@@ -1811,7 +1810,7 @@ class PyFuzzyParser(object):
self.scope = s self.scope = s
else: else:
for i in inits: for i in inits:
i.parent = weakref.ref(self.scope) i.parent = self.scope
debug.warning('syntax err, flow started @%s', debug.warning('syntax err, flow started @%s',
self.start_pos[0]) self.start_pos[0])
# globals # globals
@@ -1831,7 +1830,7 @@ class PyFuzzyParser(object):
continue continue
elif tok == 'assert': elif tok == 'assert':
stmt, tok = self._parse_statement() stmt, tok = self._parse_statement()
stmt.parent = weakref.ref(self.scope) stmt.parent = self.scope
self.scope.asserts.append(stmt) self.scope.asserts.append(stmt)
# default # default
elif token_type in [tokenize.NAME, tokenize.STRING, elif token_type in [tokenize.NAME, tokenize.STRING,

View File

@@ -267,7 +267,6 @@ print('\nSummary: (%s fails)' % tests_fail)
for s in summary: for s in summary:
print(s) print(s)
exit_code = 1 if tests_fail else 0 exit_code = 1 if tests_fail else 0
if sys.hexversion < 0x02060000 and tests_fail <= 5: if sys.hexversion < 0x02060000 and tests_fail <= 5:
# Python 2.5 has major incompabillities (e.g. no property.setter), # Python 2.5 has major incompabillities (e.g. no property.setter),