diff --git a/evaluate.py b/evaluate.py index 95ad9a71..e509e18b 100644 --- a/evaluate.py +++ b/evaluate.py @@ -114,10 +114,8 @@ class CachedMetaClass(type): class Executable(object): """ An instance is also an executable - because __init__ is called """ def __init__(self, base, var_args=parsing.Array(None, None)): - #if var_args == []: - # raise NotImplementedError() self.base = base - # the param input array + # The param input array. self.var_args = var_args def get_parent_until(self, *args): @@ -134,7 +132,6 @@ class Instance(Executable): @memoize_default() def get_init_execution(self, func): if isinstance(func, parsing.Function): - #self.set_param_cb(InstanceElement(self, Function(sub))) instance_el = InstanceElement(self, Function(func)) return Execution(instance_el, self.var_args) else: @@ -163,13 +160,13 @@ class Instance(Executable): names.append(InstanceElement(self, n)) names = [] - # this loop adds the names of the self object, copies them and removes + # This loop adds the names of the self object, copies them and removes # the self. for sub in self.base.subscopes: - # get the self name, if there's one + # Get the self name, if there's one. self_name = self.get_func_self_name(sub) if self_name: - # check the __init__ function + # Check the __init__ function. if self.var_args and sub.name.get_code() == '__init__': sub = self.get_init_execution(sub) for n in sub.get_set_vars(): @@ -193,7 +190,7 @@ class Instance(Executable): class_names = self.base.get_defined_names() for var in class_names: - # functions are also instance elements + # Functions are also instance elements. if isinstance(var.parent, (Function, parsing.Function)): var = InstanceElement(self, var) names.append(var) @@ -202,7 +199,7 @@ class Instance(Executable): def get_descriptor_return(self, obj): """ Throws an error if there's no method. """ method = self.get_subscope_by_name('__get__') - # arguments in __set__ descriptors are obj, class. + # Arguments in __set__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. args = parsing.Array('tuple', method, values=[[obj], [obj.base]]) method = InstanceElement(self, method) @@ -212,7 +209,7 @@ class Instance(Executable): def __getattr__(self, name): if name == 'get_index_types': - # todo call __getitem__ in such cases? + # TODO Call __getitem__ in such cases? return lambda: [] if name not in ['line_nr', 'indent', 'name', 'get_imports']: raise AttributeError("Instance %s: Don't touch this (%s)!" @@ -245,13 +242,12 @@ class InstanceElement(object): return InstanceElement(self.instance, scope) def get_assignment_calls(self): - # copy and modify the array + # Copy and modify the array. origin = self.var.get_assignment_calls() origin.parent_stmt, temp = None, origin.parent_stmt new = copy.deepcopy(origin) origin.parent_stmt = temp new.parent_stmt = InstanceElement(self.instance, temp) - #print 'gac', new, new.parent_stmt, new.parent_stmt.instance return new def __getattr__(self, name): @@ -270,13 +266,13 @@ class Class(object): @memoize_default(default=[]) def get_super_classes(self): supers = [] - # TODO care for mro stuff (multiple super classes) + # TODO care for mro stuff (multiple super classes). for s in self.base.supers: - # super classes are statements + # Super classes are statements. for cls in follow_statement(s): if not isinstance(cls, Class): debug.warning('Received non class, as a super class') - continue # just ignore other stuff (user input error) + continue # Just ignore other stuff (user input error). supers.append(cls) return supers @@ -285,7 +281,7 @@ class Class(object): def in_iterable(name, iterable): """ checks if the name is in the variable 'iterable'. """ for i in iterable: - # only the last name is important, because these names have a + # Only the last name is important, because these names have a # maximal length of 2, with the first one being `self`. if i.names[-1] == name.names[-1]: return True @@ -294,7 +290,7 @@ class Class(object): result = self.base.get_defined_names() super_result = [] for cls in self.get_super_classes(): - # get the inherited names + # Get the inherited names. for i in cls.get_defined_names(): if not in_iterable(i, result): super_result.append(i) @@ -334,7 +330,7 @@ class Function(object): """ f = self.base_func - # only enter it, if has not already been processed + # Only enter it, if has not already been processed. if not self.is_decorated: for dec in reversed(self.base_func.decorators): debug.dbg('decorator:', dec, f) @@ -347,7 +343,7 @@ class Function(object): debug.warning('multiple decorators found', self.base_func, dec_results) decorator = dec_results.pop() - # create param array + # Create param array. old_func = Function(f, is_decorated=True) params = parsing.Array(parsing.Array.NOARRAY, old_func) params.values = [[old_func]] @@ -359,7 +355,7 @@ class Function(object): if len(wrappers) > 1: debug.warning('multiple wrappers found', self.base_func, wrappers) - # this is here, that the wrapper gets executed + # This is here, that the wrapper gets executed. f = wrappers[0] debug.dbg('decorator end', f) @@ -394,21 +390,20 @@ class Execution(Executable): """ Get the return vars of a function. """ - #a = self.var_args; print '\n\n', a, a.values, a.parent_stmt stmts = [] if isinstance(self.base, Class): - # there maybe executions of executions + # There maybe executions of executions. stmts = [Instance(self.base, self.var_args)] elif isinstance(self.base, Generator): return self.base.execute() else: - # 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. if hasattr(self.base, 'returns'): stmts = self._get_function_returns(evaluate_generator) else: try: - # if it is an instance, we try to execute the __call__(). + # If it is an instance, we try to execute the __call__(). call_method = self.base.get_subscope_by_name('__call__') except (AttributeError, KeyError, DecoratorNotFound): debug.warning("no execution possible", self.base) @@ -458,14 +453,12 @@ class Execution(Executable): new_param._assignment_calls = calls name = copy.copy(param.get_name()) name.parent = new_param - #print 'insert', i, name, calls.values, value, self.base.params return name result = [] start_offset = 0 - #print '\n\nfunc_params', self.base, self.base.parent, self.base if isinstance(self.base, InstanceElement): - # care for self -> just exclude it and add the instance + # Care for self -> just exclude it and add the instance start_offset = 1 self_name = copy.copy(self.base.params[0].get_name()) self_name.parent = self.base.instance @@ -483,6 +476,9 @@ class Execution(Executable): for param in self.base.params[start_offset:]: # The value and key can both be null. There, the defaults apply. # args / kwargs will just be empty arrays / dicts, respectively. + # Wrong value count is just ignored. If you try to test cases which + # are not allowed in Python, Jedi will maybe not show any + # completions. key, value = next(var_arg_iterator, (None, None)) while key: try: @@ -495,8 +491,6 @@ class Execution(Executable): key, value = next(var_arg_iterator, (None, None)) keys_only = True - #debug.warning('Too many arguments given.', value) - assignments = param.get_assignment_calls().values assignment = assignments[0] keys = [] @@ -508,7 +502,7 @@ class Execution(Executable): if value: values.append(value) for key, value in var_arg_iterator: - # iterate until a key argument is found + # Iterate until a key argument is found. if key: var_arg_iterator.push_back(key, value) break @@ -523,11 +517,10 @@ class Execution(Executable): if value: values = [value] else: - # just give it the default values (if there's something - # there) + # No value: return the default values. values = assignments - # just ignore all the params that are without a key, after one + # Just ignore all the params that are without a key, after one # keyword argument was set. if not keys_only or assignment[0] == '**': result.append(gen_param_name_copy(param, keys=keys, @@ -539,7 +532,7 @@ class Execution(Executable): Yields a key/value pair, the key is None, if its not a named arg. """ def iterate(): - # var_args is typically an Array, and not a list + # `var_args` is typically an Array, and not a list. for var_arg in self.var_args: # *args if var_arg[0] == '*': @@ -552,17 +545,17 @@ class Execution(Executable): arrays = follow_call_list([var_arg[1:]]) for array in arrays: for key, field in array.get_contents(): - # take the first index + # Take the first index. if isinstance(key, parsing.Name): name = key else: - # parsing.[Call|Function|Class] lookup + # `parsing`.[Call|Function|Class] lookup. name = key[0].name yield name, field - # normal arguments (including key arguments) + # Normal arguments (including key arguments). else: if len(var_arg) > 1 and var_arg[1] == '=': - # this is a named parameter (var_arg[0] is a Call) + # This is a named parameter (var_arg[0] is a Call). yield var_arg[0].name, var_arg[2:] else: yield None, var_arg @@ -601,7 +594,7 @@ class Execution(Executable): return self.get_params() + parsing.Scope._get_set_vars(self) def copy_properties(self, prop): - # copy all these lists into this local function. + # Copy all these lists into this local function. attr = getattr(self.base, prop) objects = [] for element in attr: @@ -652,12 +645,11 @@ class Generator(object): """ names = [] for n in ['__next__', 'send']: - # the name for the `next` function + # The name for the `next` function. name = parsing.Name([n], 0, 0, 0) name.parent = self names.append(name) for n in ['close', 'throw']: - # the name for the `next` function name = parsing.Name([n], 0, 0, 0) name.parent = None names.append(name) @@ -695,9 +687,9 @@ class Array(object): return [self] else: # This is indexing only one element, with a fixed index number, - # otherwise it just ignores the index (e.g. [1+1]) + # otherwise it just ignores the index (e.g. [1+1]). try: - # multiple elements in the array + # Multiple elements in the array. i = index.get_only_subelement().name except AttributeError: pass @@ -713,7 +705,7 @@ class Array(object): old_index = index index = None for i, key_elements in enumerate(self._array.keys): - # because we only want the key to be a string + # Because we only want the key to be a string. if len(key_elements) == 1: try: str_key = key_elements.get_code() @@ -739,7 +731,7 @@ class Array(object): This method generates all ArrayElements for one parsing.Array. It returns e.g. for a list: append, pop, ... """ - # array.type is a string with the type, e.g. 'list' + # `array.type` is a string with the type, e.g. 'list'. scope = get_scopes_for_name(builtin.Builtin.scope, self._array.type)[0] names = scope.get_defined_names() return [ArrayElement(n) for n in names] @@ -769,7 +761,7 @@ class ArrayElement(object): self.name = name def __getattr__(self, name): - # set access rights: + # Set access privileges: if name not in ['parent', 'names', 'line_nr', 'indent']: raise AttributeError('Strange access: %s.' % name) return getattr(self.name, name) @@ -783,7 +775,7 @@ def get_defined_names_for_position(obj, position=None, start_scope=None): :param position: the position as a row/column tuple, default is infinity. """ 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. if not position or isinstance(obj, Instance) or isinstance(obj, Function) \ and isinstance(obj.decorated_func, Instance) \ @@ -806,7 +798,7 @@ def get_names_for_scope(scope, position=None, star_search=True): start_scope = scope while scope: # `parsing.Class` is used, because the parent is never `Class`. - # ignore the Flows, because the classes and functions care for that. + # Ignore the Flows, because the classes and functions care for that. if not (scope != start_scope and isinstance(scope, parsing.Class) or isinstance(scope, parsing.Flow) or isinstance(scope, InstanceElement) @@ -818,13 +810,13 @@ def get_names_for_scope(scope, position=None, star_search=True): raise MultiLevelStopIteration('StopIteration raised somewhere') scope = scope.parent - # add star imports + # Add star imports. if star_search: for s in remove_star_imports(start_scope.get_parent_until()): for g in get_names_for_scope(s, star_search=False): yield g - # add builtins to the global scope + # Add builtins to the global scope. builtin_scope = builtin.Builtin.scope yield builtin_scope, builtin_scope.get_defined_names() @@ -847,7 +839,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): 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(): for token_name in r.token_list[1:]: if isinstance(token_name, parsing.Name): @@ -871,9 +863,9 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): par = name.parent if isinstance(par, parsing.Flow): if par.command == 'for': - # take the first statement (for has always only + # Take the first statement (for has always only # one, remember `in`). And follow it. After that, - # get the types which are in the array + # get the types which are in the array. arrays = follow_statement(par.inits[0]) for array in arrays: in_vars = array.get_index_types() @@ -887,8 +879,8 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): elif isinstance(par, parsing.Param) \ and isinstance(par.parent.parent, parsing.Class) \ and par.position == 0: - # this is where self gets added - this happens at another - # place, if the var_args are clear. But some times the class is + # This is where self gets added - this happens at another + # place, if the var_args are clear. But sometimes the class is # not known. Therefore add a new instance for self. Otherwise # take the existing. if isinstance(scope, InstanceElement): @@ -899,10 +891,6 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): elif isinstance(par, (InstanceElement)) \ and hasattr(par, 'get_descriptor_return'): try: - #print '\n\n' - #print name, par - #print par.get_descriptor_return(scope) - #raise KeyError() result += par.get_descriptor_return(scope) except KeyError: result.append(par) @@ -914,7 +902,6 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): # compare func uses the tuple of line/indent = row/column comparison_func = lambda name: (name.line_nr, name.indent) for scope, name_list in scope_generator: - #print scope, name_list[:9] break_scopes = [] # here is the position stuff happening (sorting of variables) for name in sorted(name_list, key=comparison_func, reverse=True): @@ -956,7 +943,6 @@ def strip_imports(scopes): result = [] for s in scopes: if isinstance(s, parsing.Import): - #print 'dini mueter, steile griech!' try: result += follow_import(s) except modules.ModuleNotFound: @@ -991,20 +977,20 @@ def assign_tuples(tup, results, seek_name): result = [] if tup.type == parsing.Array.NOARRAY: - # here we have unnessecary braces, which we just remove + # Here we have unnessecary braces, which we just remove. arr = tup.get_only_subelement() result = assign_tuples(arr, results, seek_name) else: for i, t in enumerate(tup): - # used in assignments. there is just one call and no other things, - # therefor we can just assume, that the first part is important. + # Used in assignments. There is just one call and no other things, + # therefore we can just assume, that the first part is important. if len(t) != 1: raise AttributeError('Array length should be 1') t = t[0] - # check the left part, if it's still tuples in it or a Call + # Check the left part, if there are still tuples in it or a Call. if isinstance(t, parsing.Array): - # these are "sub" tuples + # These are "sub"-tuples. result += assign_tuples(t, eval_results(i), seek_name) else: if t.name.names[-1] == seek_name: @@ -1030,10 +1016,10 @@ def follow_statement(stmt, seek_name=None): # errors here must not be catched, because they shouldn't exist. raise MultiLevelAttributeError(sys.exc_info()) - # assignment checking is only important if the statement defines multiple - # variables + # Assignment checking is only important if the statement defines multiple + # variables. if len(stmt.get_set_vars()) > 1 and seek_name and stmt.assignment_details: - # TODO this should have its own call_list, because call_list can also + # TODO This should have its own call_list, because call_list can also # return 3 results for 2 variables. new_result = [] for op, set_vars in stmt.assignment_details: @@ -1062,13 +1048,13 @@ def follow_call_list(call_list): if parsing.Array.is_type(call, parsing.Array.NOARRAY): result += follow_call_list(call) else: - # with things like params, these can also be functions, etc + # With things like params, these can also be functions... if isinstance(call, (Function, parsing.Class, Instance)): result.append(call) # The string tokens are just operations (+, -, etc.) elif not isinstance(call, str): - # ternary operators - #if str(call.name) == 'for': + # Ternary operators. + #if str(call.name) == 'for': <--- list comprehensions # print '\n\ndini mueter' if str(call.name) == 'if': while True: @@ -1101,16 +1087,16 @@ def follow_call(call): else: debug.warning('unknown type:', current.type, current) scopes = [] - # make instances of those number/string objects + # Make instances of those number/string objects. scopes = [Instance(s) for s in scopes] else: - # this is the first global lookup + # This is the first global lookup. scopes = get_scopes_for_name(scope, current, position=position, search_global=True) result = strip_imports(scopes) if result != scopes: - # reset the position, when imports where stripped + # Reset the position, when imports where stripped. position = None debug.dbg('before next follow %s, current "%s", scope %s' @@ -1133,7 +1119,7 @@ def follow_paths(path, results, position=None): if fp is not None: results_new += fp else: - # this means stop iteration + # This means stop iteration. return results return results_new @@ -1142,7 +1128,7 @@ def follow_path(path, scope, position=None): """ Takes a generator and tries to complete the path. """ - # current is either an Array or a Scope + # Current is either an Array or a Scope. try: current = next(path) except StopIteration: @@ -1151,25 +1137,25 @@ def follow_path(path, scope, position=None): result = [] if isinstance(current, parsing.Array): - # this must be an execution, either () or [] + # This must be an execution, either () or []. if current.type == parsing.Array.LIST: result = scope.get_index_types(current) elif current.type not in [parsing.Array.DICT]: - # scope must be a class or func - make an instance or execution + # Scope must be a class or func - make an instance or execution. debug.dbg('exe', scope) result = Execution(scope, current).get_return_types() 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) else: - # the function must not be decorated with something else + # The function must not be decorated with something else. if isinstance(scope, Function) and \ isinstance(scope.decorated_func, Function): - # TODO check default function methods and return them + # TODO Check default function methods and return them. result = [] else: - # TODO check magic class methods and return them also - # this is the typical lookup while chaining things + # TODO Check magic class methods and return them also. + # This is the typical lookup while chaining things. result = strip_imports(get_scopes_for_name(scope, current, position=position)) return follow_paths(path, result, position=position) @@ -1181,7 +1167,7 @@ def follow_import(_import): :param _import: The import statement. :type _import: parsing.Import """ - # set path together + # Set path together. ns_list = [] if _import.from_ns: ns_list += _import.from_ns.names @@ -1214,5 +1200,5 @@ def remove_star_imports(scope): new += remove_star_imports(m) modules += new - # filter duplicate modules + # Filter duplicate modules. return set(modules)