From 079802cbd78a7d55290799359b99babe411b283f Mon Sep 17 00:00:00 2001 From: Jonathan Pompa Date: Thu, 15 Oct 2015 17:45:26 +0200 Subject: [PATCH 1/5] [mod] pre-compute _render node attribute --- CHANGELOG | 1 + redbaron.py | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5c84dfac..476ba06a 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 attribute 0.5.1 (2015-03-11) ------------------ diff --git a/redbaron.py b/redbaron.py index 1890cf61..8f22f185 100644 --- a/redbaron.py +++ b/redbaron.py @@ -147,9 +147,9 @@ 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) + 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) - 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 +271,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 +465,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)) @@ -642,7 +644,7 @@ 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: @@ -732,7 +734,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: @@ -976,10 +978,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 From 3ef4a9a4692a6c24f7dcbe595d0460770760ff7b Mon Sep 17 00:00:00 2001 From: Jonathan Pompa Date: Thu, 15 Oct 2015 17:46:23 +0200 Subject: [PATCH 2/5] [mod] pre-compute _identifiers node attribute --- CHANGELOG | 2 +- redbaron.py | 20 ++++++++++---------- tests/test_initial_parsing.py | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 476ba06a..e0d47c9d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,7 +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 attribute +- performance improvement: pre-compute ._render and ._identifiers attributes 0.5.1 (2015-03-11) ------------------ diff --git a/redbaron.py b/redbaron.py index 8f22f185..8c6f592a 100644 --- a/redbaron.py +++ b/redbaron.py @@ -488,6 +488,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" @@ -768,7 +776,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 @@ -831,14 +839,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', @@ -907,7 +907,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": 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_" ]) From b6d3c1976e0fd1de43dddf001e6557dbe6997364 Mon Sep 17 00:00:00 2001 From: Jonathan Pompa Date: Fri, 16 Oct 2015 15:24:15 +0200 Subject: [PATCH 3/5] [mod] use pattern matching for keyword argument This is the python standard way of doing it. --- redbaron.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/redbaron.py b/redbaron.py index 8c6f592a..3800a37f 100644 --- a/redbaron.py +++ b/redbaron.py @@ -637,13 +637,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): @@ -658,14 +653,14 @@ def find(self, identifier, *args, **kwargs): 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 From cd509b5fa394708311cdf18351e35d83a7eb5326 Mon Sep 17 00:00:00 2001 From: Jonathan Pompa Date: Mon, 19 Oct 2015 12:53:07 +0200 Subject: [PATCH 4/5] [fix] call find method in place of getattr in get_holdre_on_attribute --- redbaron.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/redbaron.py b/redbaron.py index 3800a37f..147f93b5 100644 --- a/redbaron.py +++ b/redbaron.py @@ -147,7 +147,12 @@ 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) return to_return From 33e78b50813e4a42c0bf4f961a3a95d375321897 Mon Sep 17 00:00:00 2001 From: Jonathan Pompa Date: Mon, 19 Oct 2015 12:54:51 +0200 Subject: [PATCH 5/5] [fix] don't raise exception for find method node --- redbaron.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/redbaron.py b/redbaron.py index 147f93b5..f7206411 100644 --- a/redbaron.py +++ b/redbaron.py @@ -668,10 +668,6 @@ def find(self, identifier, *args, recursive=None, **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])