root/galaxy-central/eggs/SQLAlchemy-0.5.6_dev_r6498-py2.6.egg/sqlalchemy/sql/visitors.py @ 3

リビジョン 3, 7.9 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""Visitor/traversal interface and library functions.
2
3SQLAlchemy schema and expression constructs rely on a Python-centric
4version of the classic "visitor" pattern as the primary way in which
5they apply functionality.  The most common use of this pattern
6is statement compilation, where individual expression classes match
7up to rendering methods that produce a string result.   Beyond this,
8the visitor system is also used to inspect expressions for various
9information and patterns, as well as for usage in
10some kinds of expression transformation.  Other kinds of transformation
11use a non-visitor traversal system.
12
13For many examples of how the visit system is used, see the
14sqlalchemy.sql.util and the sqlalchemy.sql.compiler modules.
15For an introduction to clause adaption, see
16http://techspot.zzzeek.org/?p=19 .
17
18"""
19
20from collections import deque
21import re
22from sqlalchemy import util
23import operator
24
25__all__ = ['VisitableType', 'Visitable', 'ClauseVisitor',
26    'CloningVisitor', 'ReplacingCloningVisitor', 'iterate',
27    'iterate_depthfirst', 'traverse_using', 'traverse',
28    'cloned_traverse', 'replacement_traverse']
29   
30class VisitableType(type):
31    """Metaclass which checks for a `__visit_name__` attribute and
32    applies `_compiler_dispatch` method to classes.
33   
34    """
35   
36    def __init__(cls, clsname, bases, clsdict):
37        if cls.__name__ == 'Visitable':
38            super(VisitableType, cls).__init__(clsname, bases, clsdict)
39            return
40       
41        assert hasattr(cls, '__visit_name__'), "`Visitable` descendants " \
42                                               "should define `__visit_name__`"
43       
44        # set up an optimized visit dispatch function
45        # for use by the compiler
46        visit_name = cls.__visit_name__
47        if isinstance(visit_name, str):
48            getter = operator.attrgetter("visit_%s" % visit_name)
49            def _compiler_dispatch(self, visitor, **kw):
50                return getter(visitor)(self, **kw)
51        else:
52            def _compiler_dispatch(self, visitor, **kw):
53                return getattr(visitor, 'visit_%s' % self.__visit_name__)(self, **kw)
54   
55        cls._compiler_dispatch = _compiler_dispatch
56       
57        super(VisitableType, cls).__init__(clsname, bases, clsdict)
58
59class Visitable(object):
60    """Base class for visitable objects, applies the
61    ``VisitableType`` metaclass.
62   
63    """
64
65    __metaclass__ = VisitableType
66
67class ClauseVisitor(object):
68    """Base class for visitor objects which can traverse using
69    the traverse() function.
70   
71    """
72   
73    __traverse_options__ = {}
74   
75    def traverse_single(self, obj):
76        for v in self._visitor_iterator:
77            meth = getattr(v, "visit_%s" % obj.__visit_name__, None)
78            if meth:
79                return meth(obj)
80   
81    def iterate(self, obj):
82        """traverse the given expression structure, returning an iterator of all elements."""
83
84        return iterate(obj, self.__traverse_options__)
85       
86    def traverse(self, obj):
87        """traverse and visit the given expression structure."""
88
89        return traverse(obj, self.__traverse_options__, self._visitor_dict)
90   
91    @util.memoized_property
92    def _visitor_dict(self):
93        visitors = {}
94
95        for name in dir(self):
96            if name.startswith('visit_'):
97                visitors[name[6:]] = getattr(self, name)
98        return visitors
99       
100    @property
101    def _visitor_iterator(self):
102        """iterate through this visitor and each 'chained' visitor."""
103       
104        v = self
105        while v:
106            yield v
107            v = getattr(v, '_next', None)
108
109    def chain(self, visitor):
110        """'chain' an additional ClauseVisitor onto this ClauseVisitor.
111       
112        the chained visitor will receive all visit events after this one.
113       
114        """
115        tail = list(self._visitor_iterator)[-1]
116        tail._next = visitor
117        return self
118
119class CloningVisitor(ClauseVisitor):
120    """Base class for visitor objects which can traverse using
121    the cloned_traverse() function.
122   
123    """
124
125    def copy_and_process(self, list_):
126        """Apply cloned traversal to the given list of elements, and return the new list."""
127
128        return [self.traverse(x) for x in list_]
129
130    def traverse(self, obj):
131        """traverse and visit the given expression structure."""
132
133        return cloned_traverse(obj, self.__traverse_options__, self._visitor_dict)
134
135class ReplacingCloningVisitor(CloningVisitor):
136    """Base class for visitor objects which can traverse using
137    the replacement_traverse() function.
138   
139    """
140
141    def replace(self, elem):
142        """receive pre-copied elements during a cloning traversal.
143       
144        If the method returns a new element, the element is used
145        instead of creating a simple copy of the element.  Traversal
146        will halt on the newly returned element if it is re-encountered.
147        """
148        return None
149
150    def traverse(self, obj):
151        """traverse and visit the given expression structure."""
152
153        def replace(elem):
154            for v in self._visitor_iterator:
155                e = v.replace(elem)
156                if e:
157                    return e
158        return replacement_traverse(obj, self.__traverse_options__, replace)
159
160def iterate(obj, opts):
161    """traverse the given expression structure, returning an iterator.
162   
163    traversal is configured to be breadth-first.
164   
165    """
166    stack = deque([obj])
167    while stack:
168        t = stack.popleft()
169        yield t
170        for c in t.get_children(**opts):
171            stack.append(c)
172
173def iterate_depthfirst(obj, opts):
174    """traverse the given expression structure, returning an iterator.
175   
176    traversal is configured to be depth-first.
177   
178    """
179    stack = deque([obj])
180    traversal = deque()
181    while stack:
182        t = stack.pop()
183        traversal.appendleft(t)
184        for c in t.get_children(**opts):
185            stack.append(c)
186    return iter(traversal)
187
188def traverse_using(iterator, obj, visitors):
189    """visit the given expression structure using the given iterator of objects."""
190
191    for target in iterator:
192        meth = visitors.get(target.__visit_name__, None)
193        if meth:
194            meth(target)
195    return obj
196   
197def traverse(obj, opts, visitors):
198    """traverse and visit the given expression structure using the default iterator."""
199
200    return traverse_using(iterate(obj, opts), obj, visitors)
201
202def traverse_depthfirst(obj, opts, visitors):
203    """traverse and visit the given expression structure using the depth-first iterator."""
204
205    return traverse_using(iterate_depthfirst(obj, opts), obj, visitors)
206
207def cloned_traverse(obj, opts, visitors):
208    """clone the given expression structure, allowing modifications by visitors."""
209   
210    cloned = util.column_dict()
211
212    def clone(element):
213        if element not in cloned:
214            cloned[element] = element._clone()
215        return cloned[element]
216
217    obj = clone(obj)
218    stack = [obj]
219
220    while stack:
221        t = stack.pop()
222        if t in cloned:
223            continue
224        t._copy_internals(clone=clone)
225
226        meth = visitors.get(t.__visit_name__, None)
227        if meth:
228            meth(t)
229
230        for c in t.get_children(**opts):
231            stack.append(c)
232    return obj
233
234def replacement_traverse(obj, opts, replace):
235    """clone the given expression structure, allowing element replacement by a given replacement function."""
236   
237    cloned = util.column_dict()
238    stop_on = util.column_set(opts.get('stop_on', []))
239
240    def clone(element):
241        newelem = replace(element)
242        if newelem:
243            stop_on.add(newelem)
244            return newelem
245
246        if element not in cloned:
247            cloned[element] = element._clone()
248        return cloned[element]
249
250    obj = clone(obj)
251    stack = [obj]
252    while stack:
253        t = stack.pop()
254        if t in stop_on:
255            continue
256        t._copy_internals(clone=clone)
257        for c in t.get_children(**opts):
258            stack.append(c)
259    return obj
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。