From cdbe26786a29a557685c0b81cd133dcadead1d2e Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 10 Feb 2015 15:49:26 +0100 Subject: [PATCH] Trying to get ird of the weird param generation in the parser tree. --- jedi/api/classes.py | 2 +- jedi/cache.py | 2 +- jedi/evaluate/docstrings.py | 2 +- jedi/evaluate/dynamic.py | 2 +- jedi/evaluate/finder.py | 5 +- jedi/evaluate/helpers.py | 2 +- jedi/evaluate/param.py | 4 +- jedi/evaluate/representation.py | 2 +- jedi/parser/tree.py | 122 ++++++++++++++++---------------- 9 files changed, 71 insertions(+), 72 deletions(-) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 293d2b34..4910200c 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -339,7 +339,7 @@ class BaseDefinition(object): params = sub.params[1:] # ignore self except KeyError: return [] - return [_Param(self._evaluator, p.get_name()) for p in params] + return [_Param(self._evaluator, p.name) for p in params] def parent(self): scope = self._definition.get_parent_scope() diff --git a/jedi/cache.py b/jedi/cache.py index c0b1a986..023f31e0 100644 --- a/jedi/cache.py +++ b/jedi/cache.py @@ -230,7 +230,7 @@ def save_parser(path, name, parser, pickling=True): class ParserPickling(object): - version = 23 + version = 24 """ Version number (integer) for file system cache. diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index d7a00016..96f1886a 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -176,7 +176,7 @@ def follow_param(evaluator, param): return [p for param_str in _search_param_in_docstr(func.raw_doc, - str(param.get_name())) + str(param.name)) for p in _evaluate_for_statement_string(evaluator, param_str, param.get_parent_until())] diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 80f947b3..eec2856c 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -59,7 +59,7 @@ def search_params(evaluator, param): """ for params in get_posibilities(evaluator, module, func_name): for p in params: - if str(p) == str(param.get_name()): + if str(p) == str(param.name): result += p.parent.eval(evaluator) """ # Compare the param names. diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 85a1329f..45b6cdf9 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -82,6 +82,7 @@ class NameFinder(object): @debug.increase_indent def find(self, scopes, search_global=False): + # TODO rename scopes to names_dicts names = self.filter_name(scopes) types = self._names_to_types(names, search_global) @@ -109,7 +110,7 @@ class NameFinder(object): def names_dict_lookup(self, names_dict, position): def get_param(scope, el): - if isinstance(el.parent, pr.Param) or isinstance(el.parent.parent, pr.Param): + if isinstance(el.get_parent_until(pr.Param), pr.Param): return scope.param_by_name(str(el)) return el @@ -331,7 +332,7 @@ def _remove_statements(evaluator, stmt, name): def _eval_param(evaluator, param, scope): res_new = [] - func = param.parent + func = param.get_parent_scope() cls = func.parent.get_parent_until((pr.Class, pr.Function)) diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index e71b1853..290251e6 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -70,7 +70,7 @@ def deep_ast_copy(obj, new_elements_default=None, check_first=False): setattr(new_obj, key, new_elements[value]) except KeyError: unfinished_parents.append(new_obj) - elif key in ['parent_function', 'use_as_parent', '_sub_module']: + elif key == 'position_modifier': continue elif key == 'names_dict': d = dict((k, sequence_recursion(v)) for k, v in value.items()) diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 1b96dd8d..d3e5f774 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -199,7 +199,7 @@ def get_params(evaluator, func, var_args): param_names = [] param_dict = {} for param in func.params: - param_dict[str(param.get_name())] = param + param_dict[str(param.name)] = param unpacked_va = list(var_args.unpack(func)) from jedi.evaluate.representation import InstanceElement if isinstance(func, InstanceElement): @@ -279,7 +279,7 @@ def get_params(evaluator, func, var_args): # Now add to result if it's not one of the previously covered cases. if (not keys_only or param.stars == 2): param_names.append(ExecutedParam(param, var_args, values).name) - keys_used[unicode(param.get_name())] = param_names[-1] + keys_used[unicode(param.name)] = param_names[-1] if keys_only: # All arguments should be handed over to the next function. It's not diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 8b3dfbfa..5ef26df5 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -140,7 +140,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)): normally self. """ try: - return str(func.params[0].get_name()) + return str(func.params[0].name) except IndexError: return None diff --git a/jedi/parser/tree.py b/jedi/parser/tree.py index 0532c297..e2eba949 100644 --- a/jedi/parser/tree.py +++ b/jedi/parser/tree.py @@ -281,12 +281,10 @@ class Name(Leaf): def is_definition(self): stmt = self.get_definition() - if stmt.type in ('funcdef', 'classdef', 'file_input'): + if stmt.type in ('funcdef', 'classdef', 'file_input', 'param'): return self == stmt.name elif stmt.type == 'for_stmt': return self.start_pos < stmt.children[2].start_pos - elif stmt.type == 'param': - return self == stmt.get_name() elif stmt.type == 'try_stmt': return self.prev_sibling() == 'as' else: @@ -704,40 +702,32 @@ class Class(ClassOrFunc): return docstr -def _create_params(function, lst): - if not lst: +def _create_params(parent, argslist_list): + """ + TODO DOC + This is a function to hack the general parser structure. + Preparing the replacement of *argslist with a list of Params. + """ + if not argslist_list: return [] - if is_node(lst[0], 'typedargslist', 'varargslist'): - params = [] - iterator = iter(lst[0].children) - for n in iterator: - stars = 0 - if n in ('*', '**'): - stars = len(n.value) - n = next(iterator) - op = next(iterator, None) - if op == '=': - default = next(iterator) - next(iterator, None) - else: - default = None - params.append(Param(n, function, default, stars)) + if argslist_list[0].type == 'name': + return [Param([argslist_list[0]], parent)] + else: # argslist is a `typedargslist` or a `varargslist`. + children = argslist_list[0].children + params = [] + start = 0 + # Start with offset 1, because the end is higher. + for end, child in enumerate(children + [None], 1): + if child is None or child == ',': + params.append(Param(children[start:end], parent)) + start = end return params - else: - return [Param(lst[0], function)] class Function(ClassOrFunc): """ Used to store the parsed contents of a python function. - - :param name: The Function name. - :type name: str - :param params: The parameters (Statement) of a Function. - :type params: list - :param start_pos: The start position (line, column) the Function. - :type start_pos: tuple(int, int) """ __slots__ = ('listeners', 'params') type = 'funcdef' @@ -745,8 +735,12 @@ class Function(ClassOrFunc): def __init__(self, children): super(Function, self).__init__(children) self.listeners = set() # not used here, but in evaluation. - lst = self.children[2].children[1:-1] # After `def foo` - self.params = _create_params(self, lst) + parameters = self.children[2] # After `def foo` + parameters.children[1:-1] = _create_params(parameters, parameters.children[1:-1]) + + @property + def params(self): + return self.children[2].children[1:-1] @property def name(self): @@ -796,10 +790,11 @@ class Lambda(Function): __slots__ = () def __init__(self, children): + # We don't want to call the Function constructor, call its parent. super(Function, self).__init__(children) self.listeners = set() # not used here, but in evaluation. lst = self.children[1:-2] # After `def foo` - self.params = _create_params(self, lst) + self.children[1:-2] = _create_params(self, lst) def is_generator(self): return False @@ -1119,48 +1114,51 @@ class ExprStmt(BaseNode, DocstringMixin): return None -class Param(Base): +class Param(BaseNode): """ - The class which shows definitions of params of classes and functions. - But this is not to define function calls. - - A helper class for functions. Read only. + It's a helper class that makes business logic with params much easier. The + Python grammar defines no ``param`` node. It defines it in a different way + that is not really suited to working with parameters. """ - __slots__ = ('tfpdef', 'default', 'stars', 'parent') - # Even though it's not not an official node, just give it one, because that - # makes checking more consistent. type = 'param' - def __init__(self, tfpdef, parent, default=None, stars=0): - self.tfpdef = tfpdef # tfpdef: see grammar.txt - self.default = default - self.stars = stars + def __init__(self, children, parent): + super(Param, self).__init__(children) self.parent = parent - # Here we reset the parent of our name. IMHO this is ok. - self.get_name().parent = self + for child in children: + child.parent = self + + @property + def stars(self): + first = self.children[0] + if first in ('*', '**'): + return len(first.value) + return 0 + + @property + def default(self): + try: + return self.children[int(self.children[0] in ('*', '**')) + 1] + except IndexError: + return None def annotation(self): # Generate from tfpdef. raise NotImplementedError - @property - def children(self): - return [] - - @property - def start_pos(self): - return self.tfpdef.start_pos - - def get_name(self): - # TODO remove! - return self.name + def _tfpdef(self): + """ + tfpdef: see grammar.txt. + """ + offset = int(self.children[0] in ('*', '**')) + return self.children[offset] @property def name(self): - if is_node(self.tfpdef, 'tfpdef'): - return self.tfpdef.children[0] + if is_node(self._tfpdef(), 'tfpdef'): + return self._tfpdef().children[0] else: - return self.tfpdef + return self._tfpdef() @property def position_nr(self): @@ -1172,11 +1170,11 @@ class Param(Base): def get_code(self): df = '' if self.default is None else '=' + self.default.get_code() - return self.tfpdef.get_code() + df + return self._tfpdef().get_code() + df def __repr__(self): default = '' if self.default is None else '=%s' % self.default - return '<%s: %s>' % (type(self).__name__, str(self.tfpdef) + default) + return '<%s: %s>' % (type(self).__name__, str(self._tfpdef()) + default) class CompFor(BaseNode):