diff --git a/CHANGELOG b/CHANGELOG index 5c84dfac..e0d47c9d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ Changelog - fix: inconsistencies when inserting lines around code blocks - inserting a blank lines inserts effectively a \n in a LineProxyList - new helper methods: .next_recursive and .previous_recursive https://redbaron.readthedocs.org/en/latest/other.html +- performance improvement: pre-compute ._render and ._identifiers attributes 0.5.1 (2015-03-11) ------------------ diff --git a/redbaron.py b/redbaron.py index 1890cf61..f7206411 100644 --- a/redbaron.py +++ b/redbaron.py @@ -147,9 +147,14 @@ def get_holder_on_attribute(class_, node): return pos if isinstance(node, NodeList): - return next((key for (_, key, _) in parent._render() if getattr(parent, key) is node or getattr(getattr(parent, key), "node_list", None) is node), None) + for (_, key, _) in parent._render: + child = parent.find(key, recursive=False) + if child is node \ + or getattr(child, "node_list", None) is node: + return key - to_return = next((key for (_, key, _) in parent._render() if key == node.on_attribute), None) + + to_return = next((key for (_, key, _) in parent._render if key == node.on_attribute), None) return to_return @@ -271,7 +276,7 @@ def _iter_in_rendering_order(self, node): return if not (isinstance(node, Node) and node.type == "endl"): yield node - for kind, key, display in node._render(): + for kind, key, display in node._render: if kind == "constant": yield node elif kind == "string": @@ -465,7 +470,9 @@ def __init__(self, node, parent=None, on_attribute=None): self._list_keys = [] self._dict_keys = [] self.type = node["type"] - for kind, key, _ in filter(lambda x: x[0] != "constant", self._render()): + self._render = nodes_rendering_order[self.type] + + for kind, key, _ in filter(lambda x: x[0] != "constant", self._render): if kind == "key": if node[key]: setattr(self, key, Node.from_fst(node[key], parent=self, on_attribute=key)) @@ -486,6 +493,14 @@ def __init__(self, node, parent=None, on_attribute=None): self.init = False + self._identifiers = [x.lower() for x in [ + self.type, + self.__class__.__name__, + self.__class__.__name__.replace("Node", ""), + self.type + "_" + ] + self._other_identifiers] + + @classmethod def from_fst(klass, node, parent=None, on_attribute=None): class_name = "".join(map(lambda x: x.capitalize(), node["type"].split("_"))) + "Node" @@ -627,13 +642,8 @@ def _get_list_attribute_is_member_off(self): return in_list - - def find(self, identifier, *args, **kwargs): - if "recursive" in kwargs: - recursive = kwargs["recursive"] - kwargs = kwargs.copy() - del kwargs["recursive"] - else: + def find(self, identifier, *args, recursive=None, **kwargs): + if recursive is None: recursive = True if self._node_match_query(self, identifier, *args, **kwargs): @@ -642,26 +652,22 @@ def find(self, identifier, *args, **kwargs): if not recursive: return None - for kind, key, _ in filter(lambda x: x[0] in ("list", "key"), self._render()): + for kind, key, _ in filter(lambda x: x[0] in ("list", "key"), self._render): if kind == "key": i = getattr(self, key) if not i: continue - found = i.find(identifier, *args, **kwargs) + found = i.find(identifier, *args, recursive=recursive, **kwargs) if found: return found elif kind == "list": attr = getattr(self, key).node_list if isinstance(getattr(self, key), ProxyList) else getattr(self, key) for i in attr: - found = i.find(identifier, *args, **kwargs) + found = i.find(identifier, *args, recursive=recursive, **kwargs) if found: return found - - else: - raise Exception() - def __getattr__(self, key): if key.endswith("_") and key[:-1] in self._dict_keys + self._list_keys + self._str_keys: return getattr(self, key[:-1]) @@ -732,7 +738,7 @@ def find_all(self, identifier, *args, **kwargs): if not recursive: return to_return - for kind, key, _ in filter(lambda x: x[0] in ("list", "formatting") or (x[0] == "key" and isinstance(getattr(self, x[1]), Node)), self._render()): + for kind, key, _ in filter(lambda x: x[0] in ("list", "formatting") or (x[0] == "key" and isinstance(getattr(self, x[1]), Node)), self._render): if kind == "key": i = getattr(self, key) if not i: @@ -766,7 +772,7 @@ def parent_find(self, identifier, *args, **kwargs): return None def _node_match_query(self, node, identifier, *args, **kwargs): - if not self._attribute_match_query(node._generate_identifiers(), identifier.lower() if isinstance(identifier, string_instance) and not identifier.startswith("re:") else identifier): + if not self._attribute_match_query(node._identifiers, identifier.lower() if isinstance(identifier, string_instance) and not identifier.startswith("re:") else identifier): return False all_my_keys = node._str_keys + node._list_keys + node._dict_keys @@ -829,14 +835,6 @@ def find_by_path(self, path): def path(self): return Path(self) - def _generate_identifiers(self): - return sorted(set(map(lambda x: x.lower(), [ - self.type, - self.__class__.__name__, - self.__class__.__name__.replace("Node", ""), - self.type + "_" - ] + self._other_identifiers))) - def _get_helpers(self): not_helpers = set([ 'copy', @@ -905,7 +903,7 @@ def __help__(self, deep=2, with_formatting=False): if not deep: to_join[-1] += " ..." else: - to_join.append("# identifiers: %s" % ", ".join(self._generate_identifiers())) + to_join.append("# identifiers: %s" % ", ".join(self._identifiers)) if self._get_helpers(): to_join.append("# helpers: %s" % ", ".join(self._get_helpers())) if self._default_test_value != "value": @@ -976,10 +974,6 @@ def __setattr__(self, name, value): return super(Node, self).__setattr__(name, value) - - def _render(self): - return nodes_rendering_order[self.type] - def replace(self, new_node): new_node = self._convert_input_to_node_object(new_node, parent=None, on_attribute=None, generic=True) self.__class__ = new_node.__class__ # YOLO diff --git a/tests/test_initial_parsing.py b/tests/test_initial_parsing.py index 890156d7..db21a337 100644 --- a/tests/test_initial_parsing.py +++ b/tests/test_initial_parsing.py @@ -129,7 +129,7 @@ def test_assign_on_object_value_fst(): def test_generate_helpers(): red = RedBaron("def a(): pass") - assert set(red[0]._generate_identifiers()) == set([ + assert set(red[0]._identifiers) == set([ "funcdef", "funcdef_", "defnode", "def", "def_" ])