summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/visitors.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/visitors.py')
-rw-r--r--lib/sqlalchemy/sql/visitors.py80
1 files changed, 38 insertions, 42 deletions
diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py
index 0c6be97d7..b94f07f58 100644
--- a/lib/sqlalchemy/sql/visitors.py
+++ b/lib/sqlalchemy/sql/visitors.py
@@ -19,7 +19,7 @@ use a non-visitor traversal system.
For many examples of how the visit system is used, see the
sqlalchemy.sql.util and the sqlalchemy.sql.compiler modules.
For an introduction to clause adaption, see
-http://techspot.zzzeek.org/?p=19 .
+http://techspot.zzzeek.org/2008/01/23/expression-transformations/
"""
@@ -212,55 +212,51 @@ def traverse_depthfirst(obj, opts, visitors):
return traverse_using(iterate_depthfirst(obj, opts), obj, visitors)
def cloned_traverse(obj, opts, visitors):
- """clone the given expression structure, allowing modifications by visitors."""
+ """clone the given expression structure, allowing
+ modifications by visitors."""
cloned = util.column_dict()
+ stop_on = util.column_set(opts.get('stop_on', []))
- def clone(element):
- if element not in cloned:
- cloned[element] = element._clone()
- return cloned[element]
-
- obj = clone(obj)
- stack = [obj]
-
- while stack:
- t = stack.pop()
- if t in cloned:
- continue
- t._copy_internals(clone=clone)
-
- meth = visitors.get(t.__visit_name__, None)
- if meth:
- meth(t)
-
- for c in t.get_children(**opts):
- stack.append(c)
+ def clone(elem):
+ if elem in stop_on:
+ return elem
+ else:
+ if elem not in cloned:
+ cloned[elem] = newelem = elem._clone()
+ newelem._copy_internals(clone=clone)
+ meth = visitors.get(newelem.__visit_name__, None)
+ if meth:
+ meth(newelem)
+ return cloned[elem]
+
+ if obj is not None:
+ obj = clone(obj)
return obj
+
def replacement_traverse(obj, opts, replace):
- """clone the given expression structure, allowing element replacement by a given replacement function."""
+ """clone the given expression structure, allowing element
+ replacement by a given replacement function."""
cloned = util.column_dict()
stop_on = util.column_set(opts.get('stop_on', []))
- def clone(element):
- newelem = replace(element)
- if newelem is not None:
- stop_on.add(newelem)
- return newelem
-
- if element not in cloned:
- cloned[element] = element._clone()
- return cloned[element]
-
- obj = clone(obj)
- stack = [obj]
- while stack:
- t = stack.pop()
- if t in stop_on:
- continue
- t._copy_internals(clone=clone)
- for c in t.get_children(**opts):
- stack.append(c)
+ def clone(elem, **kw):
+ if elem in stop_on or \
+ 'no_replacement_traverse' in elem._annotations:
+ return elem
+ else:
+ newelem = replace(elem)
+ if newelem is not None:
+ stop_on.add(newelem)
+ return newelem
+ else:
+ if elem not in cloned:
+ cloned[elem] = newelem = elem._clone()
+ newelem._copy_internals(clone=clone, **kw)
+ return cloned[elem]
+
+ if obj is not None:
+ obj = clone(obj, **opts)
return obj