cleanup accept and leave method on various visitable object (closes #89659)

The old code did: * forge a string * eval it as a lamba * monkey patch classes with the result

We may just drop the logic looping on multiple class by computing class name dynamically. But this have a different behavior for subclass.

authorPierre-Yves David <pierre-yves.david@logilab.fr>
changeset2a532f897388
branchstable
phasepublic
hiddenno
parent revision#9a61c1d4c3db Refactor an if: else: clause as elif
child revision#6b15ab059caa pkg: bump constraint depency version
files modified by this revision
base.py
nodes.py
stmts.py
utils.py
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@logilab.fr>
# Date 1331912840 -3600
# Fri Mar 16 16:47:20 2012 +0100
# Branch stable
# Node ID 2a532f897388a25326bcb877f156f007511714ea
# Parent 9a61c1d4c3dbbbfbbd6c8a55c43117688e808280
cleanup accept and leave method on various visitable object (closes #89659)

The old code did:
* forge a string
* eval it as a lamba
* monkey patch classes with the result

We may just drop the logic looping on multiple class by computing class name
dynamically. But this have a different behavior for subclass.

diff --git a/base.py b/base.py
@@ -20,12 +20,14 @@
1  Note: this module uses __slots__ to limit memory usage.
2  """
3 
4  __docformat__ = "restructuredtext en"
5 
6 +from rql.utils import VisitableMixIn
7 
8 -class BaseNode(object):
9 +
10 +class BaseNode(VisitableMixIn):
11      __slots__ = ('parent',)
12 
13      def __str__(self):
14          return self.as_string(encoding='utf-8')
15 
diff --git a/nodes.py b/nodes.py
@@ -30,12 +30,12 @@
16 
17  from logilab.database import DYNAMIC_RTYPE
18 
19  from rql import CoercionError, RQLException
20  from rql.base import BaseNode, Node, BinaryNode, LeafNode
21 -from rql.utils import (function_description, quote, uquote, build_visitor_stub,
22 -                       common_parent)
23 +from rql.utils import (function_description, quote, uquote, common_parent,
24 +                       VisitableMixIn)
25 
26  CONSTANT_TYPES = frozenset((None, 'Date', 'Datetime', 'Boolean', 'Float', 'Int',
27                              'String', 'Substitute', 'etype'))
28 
29 
@@ -899,11 +899,11 @@
30 
31 
32 
33  ###############################################################################
34 
35 -class Referenceable(object):
36 +class Referenceable(VisitableMixIn):
37      __slots__ = ('name', 'stinfo', 'stmt')
38 
39      def __init__(self, name):
40          self.name = name.strip().encode()
41          # used to collect some global information about the syntax tree
@@ -1131,8 +1131,5 @@
42          """
43          stinfo = self.stinfo
44          return len(stinfo['selected']) + len(stinfo['relations'])
45 
46 
47 -build_visitor_stub((SubQuery, And, Or, Not, Exists, Relation,
48 -                    Comparison, MathExpression, UnaryExpression, Function,
49 -                    Constant, VariableRef, SortTerm, ColumnAlias, Variable))
diff --git a/stmts.py b/stmts.py
@@ -29,11 +29,11 @@
50  from logilab.common.decorators import cached
51  from logilab.common.deprecation import deprecated
52 
53  from rql import BadRQLQuery, CoercionError, nodes
54  from rql.base import BaseNode, Node
55 -from rql.utils import rqlvar_maker, build_visitor_stub
56 +from rql.utils import rqlvar_maker
57 
58  _MARKER = object()
59 
60  def _check_references(defined, varrefs):
61      refs = {}
@@ -1111,6 +1111,5 @@
62          if self.having:
63              new.set_having([sq.copy(new) for sq in self.having])
64          return new
65 
66 
67 -build_visitor_stub((Union, Select, Insert, Delete, Set))
diff --git a/utils.py b/utils.py
@@ -154,18 +154,23 @@
68              res.append(u'\\')
69          res.append(char)
70      res.append(u'"')
71      return u''.join(res)
72 
73 -# Visitor #####################################################################
74 +
75 +
76 +class VisitableMixIn(object):
77 
78 -_accept = 'lambda self, visitor, *args, **kwargs: visitor.visit_%s(self, *args, **kwargs)'
79 -_leave = 'lambda self, visitor, *args, **kwargs: visitor.leave_%s(self, *args, **kwargs)'
80 -def build_visitor_stub(classes):
81 -    for cls in classes:
82 -        cls.accept = eval(_accept % (cls.__name__.lower()))
83 -        cls.leave = eval(_leave % (cls.__name__.lower()))
84 +    def accept(self, visitor, *args, **kwargs):
85 +        visit_id = self.__class__.__name__.lower()
86 +        visit_method = getattr(visitor, 'visit_%s' % visit_id)
87 +        return visit_method(self, *args, **kwargs)
88 +
89 +    def leave(self, visitor, *args, **kwargs):
90 +        visit_id = self.__class__.__name__.lower()
91 +        visit_method = getattr(visitor, 'leave_%s' % visit_id)
92 +        return visit_method(self, *args, **kwargs)
93 
94  class RQLVisitorHandler(object):
95      """Handler providing a dummy implementation of all callbacks necessary
96      to visit a RQL syntax tree.
97      """