Packages update

This commit is contained in:
Ruud
2012-02-11 16:28:06 +01:00
parent 3bbf1126c3
commit 02e01fb2d6
217 changed files with 26395 additions and 21194 deletions
+5 -1
View File
@@ -1,5 +1,5 @@
# sql/__init__.py
# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -34,6 +34,7 @@ from sqlalchemy.sql.expression import (
except_all,
exists,
extract,
false,
func,
insert,
intersect,
@@ -48,10 +49,12 @@ from sqlalchemy.sql.expression import (
or_,
outerjoin,
outparam,
over,
select,
subquery,
table,
text,
true,
tuple_,
type_coerce,
union,
@@ -63,3 +66,4 @@ from sqlalchemy.sql.visitors import ClauseVisitor
__tmp = locals().keys()
__all__ = sorted([i for i in __tmp if not i.startswith('__')])
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+26 -2
View File
@@ -1,10 +1,10 @@
# sql/functions.py
# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from sqlalchemy import types as sqltypes
from sqlalchemy import types as sqltypes, schema
from sqlalchemy.sql.expression import (
ClauseList, Function, _literal_as_binds, text, _type_from_args
)
@@ -29,6 +29,29 @@ class GenericFunction(Function):
self.type = sqltypes.to_instance(
type_ or getattr(self, '__return_type__', None))
class next_value(Function):
"""Represent the 'next value', given a :class:`.Sequence`
as it's single argument.
Compiles into the appropriate function on each backend,
or will raise NotImplementedError if used on a backend
that does not provide support for sequences.
"""
type = sqltypes.Integer()
name = "next_value"
def __init__(self, seq, **kw):
assert isinstance(seq, schema.Sequence), \
"next_value() accepts a Sequence object as input."
self._bind = kw.get('bind', None)
self.sequence = seq
@property
def _from_objects(self):
return []
class AnsiFunction(GenericFunction):
def __init__(self, **kwargs):
GenericFunction.__init__(self, **kwargs)
@@ -52,6 +75,7 @@ class min(ReturnTypeFromArgs):
class sum(ReturnTypeFromArgs):
pass
class now(GenericFunction):
__return_type__ = sqltypes.DateTime
+441 -7
View File
@@ -1,5 +1,5 @@
# sql/operators.py
# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -19,6 +19,430 @@ from operator import (div,)
from sqlalchemy.util import symbol
class Operators(object):
"""Base of comparison and logical operators.
Implements base methods :meth:`operate` and :meth:`reverse_operate`,
as well as :meth:`__and__`, :meth:`__or__`, :meth:`__invert__`.
Usually is used via its most common subclass
:class:`.ColumnOperators`.
"""
def __and__(self, other):
"""Implement the ``&`` operator.
When used with SQL expressions, results in an
AND operation, equivalent to
:func:`~.expression.and_`, that is::
a & b
is equivalent to::
from sqlalchemy import and_
and_(a, b)
Care should be taken when using ``&`` regarding
operator precedence; the ``&`` operator has the highest precedence.
The operands should be enclosed in parenthesis if they contain
further sub expressions::
(a == 2) & (b == 4)
"""
return self.operate(and_, other)
def __or__(self, other):
"""Implement the ``|`` operator.
When used with SQL expressions, results in an
OR operation, equivalent to
:func:`~.expression.or_`, that is::
a | b
is equivalent to::
from sqlalchemy import or_
or_(a, b)
Care should be taken when using ``|`` regarding
operator precedence; the ``|`` operator has the highest precedence.
The operands should be enclosed in parenthesis if they contain
further sub expressions::
(a == 2) | (b == 4)
"""
return self.operate(or_, other)
def __invert__(self):
"""Implement the ``~`` operator.
When used with SQL expressions, results in a
NOT operation, equivalent to
:func:`~.expression.not_`, that is::
~a
is equivalent to::
from sqlalchemy import not_
not_(a)
"""
return self.operate(inv)
def op(self, opstring):
"""produce a generic operator function.
e.g.::
somecolumn.op("*")(5)
produces::
somecolumn * 5
:param operator: a string which will be output as the infix operator
between this :class:`.ClauseElement` and the expression passed to the
generated function.
This function can also be used to make bitwise operators explicit. For
example::
somecolumn.op('&')(0xff)
is a bitwise AND of the value in somecolumn.
"""
def _op(b):
return self.operate(op, opstring, b)
return _op
def operate(self, op, *other, **kwargs):
"""Operate on an argument.
This is the lowest level of operation, raises
:class:`NotImplementedError` by default.
Overriding this on a subclass can allow common
behavior to be applied to all operations.
For example, overriding :class:`.ColumnOperators`
to apply ``func.lower()`` to the left and right
side::
class MyComparator(ColumnOperators):
def operate(self, op, other):
return op(func.lower(self), func.lower(other))
:param op: Operator callable.
:param \*other: the 'other' side of the operation. Will
be a single scalar for most operations.
:param \**kwargs: modifiers. These may be passed by special
operators such as :meth:`ColumnOperators.contains`.
"""
raise NotImplementedError(str(op))
def reverse_operate(self, op, other, **kwargs):
"""Reverse operate on an argument.
Usage is the same as :meth:`operate`.
"""
raise NotImplementedError(str(op))
class ColumnOperators(Operators):
"""Defines comparison and math operations.
By default all methods call down to
:meth:`Operators.operate` or :meth:`Operators.reverse_operate`
passing in the appropriate operator function from the
Python builtin ``operator`` module or
a SQLAlchemy-specific operator function from
:mod:`sqlalchemy.expression.operators`. For example
the ``__eq__`` function::
def __eq__(self, other):
return self.operate(operators.eq, other)
Where ``operators.eq`` is essentially::
def eq(a, b):
return a == b
A SQLAlchemy construct like :class:`.ColumnElement` ultimately
overrides :meth:`.Operators.operate` and others
to return further :class:`.ClauseElement` constructs,
so that the ``==`` operation above is replaced by a clause
construct.
The docstrings here will describe column-oriented
behavior of each operator. For ORM-based operators
on related objects and collections, see :class:`.RelationshipProperty.Comparator`.
"""
timetuple = None
"""Hack, allows datetime objects to be compared on the LHS."""
def __lt__(self, other):
"""Implement the ``<`` operator.
In a column context, produces the clause ``a < b``.
"""
return self.operate(lt, other)
def __le__(self, other):
"""Implement the ``<=`` operator.
In a column context, produces the clause ``a <= b``.
"""
return self.operate(le, other)
__hash__ = Operators.__hash__
def __eq__(self, other):
"""Implement the ``==`` operator.
In a column context, produces the clause ``a = b``.
If the target is ``None``, produces ``a IS NULL``.
"""
return self.operate(eq, other)
def __ne__(self, other):
"""Implement the ``!=`` operator.
In a column context, produces the clause ``a != b``.
If the target is ``None``, produces ``a IS NOT NULL``.
"""
return self.operate(ne, other)
def __gt__(self, other):
"""Implement the ``>`` operator.
In a column context, produces the clause ``a > b``.
"""
return self.operate(gt, other)
def __ge__(self, other):
"""Implement the ``>=`` operator.
In a column context, produces the clause ``a >= b``.
"""
return self.operate(ge, other)
def __neg__(self):
"""Implement the ``-`` operator.
In a column context, produces the clause ``-a``.
"""
return self.operate(neg)
def concat(self, other):
"""Implement the 'concat' operator.
In a column context, produces the clause ``a || b``,
or uses the ``concat()`` operator on MySQL.
"""
return self.operate(concat_op, other)
def like(self, other, escape=None):
"""Implement the ``like`` operator.
In a column context, produces the clause ``a LIKE other``.
"""
return self.operate(like_op, other, escape=escape)
def ilike(self, other, escape=None):
"""Implement the ``ilike`` operator.
In a column context, produces the clause ``a ILIKE other``.
"""
return self.operate(ilike_op, other, escape=escape)
def in_(self, other):
"""Implement the ``in`` operator.
In a column context, produces the clause ``a IN other``.
"other" may be a tuple/list of column expressions,
or a :func:`~.expression.select` construct.
"""
return self.operate(in_op, other)
def startswith(self, other, **kwargs):
"""Implement the ``startwith`` operator.
In a column context, produces the clause ``LIKE '<other>%'``
"""
return self.operate(startswith_op, other, **kwargs)
def endswith(self, other, **kwargs):
"""Implement the 'endswith' operator.
In a column context, produces the clause ``LIKE '%<other>'``
"""
return self.operate(endswith_op, other, **kwargs)
def contains(self, other, **kwargs):
"""Implement the 'contains' operator.
In a column context, produces the clause ``LIKE '%<other>%'``
"""
return self.operate(contains_op, other, **kwargs)
def match(self, other, **kwargs):
"""Implements the 'match' operator.
In a column context, this produces a MATCH clause, i.e.
``MATCH '<other>'``. The allowed contents of ``other``
are database backend specific.
"""
return self.operate(match_op, other, **kwargs)
def desc(self):
"""Produce a :func:`~.expression.desc` clause against the
parent object."""
return self.operate(desc_op)
def asc(self):
"""Produce a :func:`~.expression.asc` clause against the
parent object."""
return self.operate(asc_op)
def nullsfirst(self):
"""Produce a :func:`~.expression.nullsfirst` clause against the
parent object."""
return self.operate(nullsfirst_op)
def nullslast(self):
"""Produce a :func:`~.expression.nullslast` clause against the
parent object."""
return self.operate(nullslast_op)
def collate(self, collation):
"""Produce a :func:`~.expression.collate` clause against
the parent object, given the collation string."""
return self.operate(collate, collation)
def __radd__(self, other):
"""Implement the ``+`` operator in reverse.
See :meth:`__add__`.
"""
return self.reverse_operate(add, other)
def __rsub__(self, other):
"""Implement the ``-`` operator in reverse.
See :meth:`__sub__`.
"""
return self.reverse_operate(sub, other)
def __rmul__(self, other):
"""Implement the ``*`` operator in reverse.
See :meth:`__mul__`.
"""
return self.reverse_operate(mul, other)
def __rdiv__(self, other):
"""Implement the ``/`` operator in reverse.
See :meth:`__div__`.
"""
return self.reverse_operate(div, other)
def between(self, cleft, cright):
"""Produce a :func:`~.expression.between` clause against
the parent object, given the lower and upper range."""
return self.operate(between_op, cleft, cright)
def distinct(self):
"""Produce a :func:`~.expression.distinct` clause against the parent object."""
return self.operate(distinct_op)
def __add__(self, other):
"""Implement the ``+`` operator.
In a column context, produces the clause ``a + b``
if the parent object has non-string affinity.
If the parent object has a string affinity,
produces the concatenation operator, ``a || b`` -
see :meth:`concat`.
"""
return self.operate(add, other)
def __sub__(self, other):
"""Implement the ``-`` operator.
In a column context, produces the clause ``a - b``.
"""
return self.operate(sub, other)
def __mul__(self, other):
"""Implement the ``*`` operator.
In a column context, produces the clause ``a * b``.
"""
return self.operate(mul, other)
def __div__(self, other):
"""Implement the ``/`` operator.
In a column context, produces the clause ``a / b``.
"""
return self.operate(div, other)
def __mod__(self, other):
"""Implement the ``%`` operator.
In a column context, produces the clause ``a % b``.
"""
return self.operate(mod, other)
def __truediv__(self, other):
"""Implement the ``//`` operator.
In a column context, produces the clause ``a / b``.
"""
return self.operate(truediv, other)
def __rtruediv__(self, other):
"""Implement the ``//`` operator in reverse.
See :meth:`__truediv__`.
"""
return self.reverse_operate(truediv, other)
def from_():
raise NotImplementedError()
@@ -29,14 +453,14 @@ def as_():
def exists():
raise NotImplementedError()
def is_():
raise NotImplementedError()
def is_(a, b):
return a.is_(b)
def isnot():
raise NotImplementedError()
def isnot(a, b):
return a.isnot(b)
def collate():
raise NotImplementedError()
def collate(a, b):
return a.collate(b)
def op(a, opstring, b):
return a.op(opstring)(b)
@@ -89,11 +513,21 @@ def desc_op(a):
def asc_op(a):
return a.asc()
def nullsfirst_op(a):
return a.nullsfirst()
def nullslast_op(a):
return a.nullslast()
_commutative = set([eq, ne, add, mul])
def is_commutative(op):
return op in _commutative
def is_ordering_modifier(op):
return op in (asc_op, desc_op,
nullsfirst_op, nullslast_op)
_associative = _commutative.union([concat_op, and_, or_])
+100 -36
View File
@@ -1,12 +1,14 @@
# sql/util.py
# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from sqlalchemy import exc, schema, topological, util, sql, types as sqltypes
from sqlalchemy import exc, schema, util, sql, types as sqltypes
from sqlalchemy.util import topological
from sqlalchemy.sql import expression, operators, visitors
from itertools import chain
from collections import deque
"""Utility functions that build upon SQL and Schema constructs."""
@@ -98,6 +100,25 @@ def find_columns(clause):
visitors.traverse(clause, {}, {'column':cols.add})
return cols
def unwrap_order_by(clause):
"""Break up an 'order by' expression into individual column-expressions,
without DESC/ASC/NULLS FIRST/NULLS LAST"""
cols = util.column_set()
stack = deque([clause])
while stack:
t = stack.popleft()
if isinstance(t, expression.ColumnElement) and \
(
not isinstance(t, expression._UnaryExpression) or \
not operators.is_ordering_modifier(t.modifier)
):
cols.add(t)
else:
for c in t.get_children():
stack.append(c)
return cols
def clause_is_present(clause, search):
"""Given a target clause and a second to search within, return True
if the target is plainly present in the search without any
@@ -131,13 +152,7 @@ def bind_values(clause):
v = []
def visit_bindparam(bind):
value = bind.value
# evaluate callables
if callable(value):
value = value()
v.append(value)
v.append(bind.effective_value)
visitors.traverse(clause, {}, {'bindparam':visit_bindparam})
return v
@@ -149,6 +164,28 @@ def _quote_ddl_expr(element):
else:
return repr(element)
class _repr_params(object):
"""A string view of bound parameters, truncating
display to the given number of 'multi' parameter sets.
"""
def __init__(self, params, batches):
self.params = params
self.batches = batches
def __repr__(self):
if isinstance(self.params, (list, tuple)) and \
len(self.params) > self.batches and \
isinstance(self.params[0], (list, dict, tuple)):
return ' '.join((
repr(self.params[:self.batches - 2])[0:-1],
" ... displaying %i of %i total bound parameter sets ... " % (self.batches, len(self.params)),
repr(self.params[-2:])[1:]
))
else:
return repr(self.params)
def expression_as_ddl(clause):
"""Given a SQL expression, convert for usage in DDL, such as
CREATE INDEX and CHECK CONSTRAINT.
@@ -173,20 +210,21 @@ def adapt_criterion_to_null(crit, nulls):
"""given criterion containing bind params, convert selected elements to IS NULL."""
def visit_binary(binary):
if isinstance(binary.left, expression._BindParamClause) and binary.left.key in nulls:
if isinstance(binary.left, expression._BindParamClause) \
and binary.left._identifying_key in nulls:
# reverse order if the NULL is on the left side
binary.left = binary.right
binary.right = expression.null()
binary.operator = operators.is_
binary.negate = operators.isnot
elif isinstance(binary.right, expression._BindParamClause) and binary.right.key in nulls:
elif isinstance(binary.right, expression._BindParamClause) \
and binary.right._identifying_key in nulls:
binary.right = expression.null()
binary.operator = operators.is_
binary.negate = operators.isnot
return visitors.cloned_traverse(crit, {}, {'binary':visit_binary})
def join_condition(a, b, ignore_nonexistent_tables=False, a_subset=None):
"""create a join condition between two tables or selectables.
@@ -202,11 +240,9 @@ def join_condition(a, b, ignore_nonexistent_tables=False, a_subset=None):
between the two selectables. If there are multiple ways
to join, or no way to join, an error is raised.
:param ignore_nonexistent_tables: This flag will cause the
function to silently skip over foreign key resolution errors
due to nonexistent tables - the assumption is that these
tables have not yet been defined within an initialization process
and are not significant to the operation.
:param ignore_nonexistent_tables: Deprecated - this
flag is no longer used. Only resolution errors regarding
the two given tables are propagated.
:param a_subset: An optional expression that is a sub-component
of ``a``. An attempt will be made to join to just this sub-component
@@ -222,27 +258,33 @@ def join_condition(a, b, ignore_nonexistent_tables=False, a_subset=None):
for left in (a_subset, a):
if left is None:
continue
for fk in b.foreign_keys:
for fk in sorted(
b.foreign_keys,
key=lambda fk:fk.parent._creation_order):
try:
col = fk.get_referent(left)
except exc.NoReferencedTableError:
if ignore_nonexistent_tables:
continue
else:
except exc.NoReferenceError, nrte:
if nrte.table_name == left.name:
raise
else:
continue
if col is not None:
crit.append(col == fk.parent)
constraints.add(fk.constraint)
if left is not b:
for fk in left.foreign_keys:
for fk in sorted(
left.foreign_keys,
key=lambda fk:fk.parent._creation_order):
try:
col = fk.get_referent(b)
except exc.NoReferencedTableError:
if ignore_nonexistent_tables:
continue
else:
except exc.NoReferenceError, nrte:
if nrte.table_name == b.name:
raise
else:
# this is totally covered. can't get
# coverage to mark it.
continue
if col is not None:
crit.append(col == fk.parent)
@@ -252,7 +294,8 @@ def join_condition(a, b, ignore_nonexistent_tables=False, a_subset=None):
if len(crit) == 0:
if isinstance(b, expression._FromGrouping):
hint = " Perhaps you meant to convert the right side to a subquery using alias()?"
hint = " Perhaps you meant to convert the right side to a "\
"subquery using alias()?"
else:
hint = ""
raise exc.ArgumentError(
@@ -334,7 +377,7 @@ class Annotated(object):
# detect immutable, don't change anything
return self
else:
# update the clone with any changes that have occured
# update the clone with any changes that have occurred
# to this object's __dict__.
clone.__dict__.update(self.__dict__)
return Annotated(clone, self._annotations)
@@ -342,8 +385,12 @@ class Annotated(object):
def __hash__(self):
return hash(self.__element)
def __cmp__(self, other):
return cmp(hash(self.__element), hash(other))
def __eq__(self, other):
if isinstance(self.__element, expression.ColumnOperators):
return self.__element.__class__.__eq__(self, other)
else:
return hash(other) == hash(self)
# hard-generate Annotated subclasses. this technique
# is used instead of on-the-fly types (i.e. type.__new__())
@@ -390,6 +437,17 @@ def _deep_deannotate(element):
element = clone(element)
return element
def _shallow_annotate(element, annotations):
"""Annotate the given ClauseElement and copy its internals so that
internal objects refer to the new annotated object.
Basically used to apply a "dont traverse" annotation to a
selectable, without digging throughout the whole
structure wasting time.
"""
element = element._annotate(annotations)
element._copy_internals()
return element
def splice_joins(left, right, stop_on=None):
if left is None:
@@ -611,21 +669,27 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor):
s.c.col1 == table2.c.col1
"""
def __init__(self, selectable, equivalents=None, include=None, exclude=None):
self.__traverse_options__ = {'column_collections':False, 'stop_on':[selectable]}
def __init__(self, selectable, equivalents=None, include=None, exclude=None, adapt_on_names=False):
self.__traverse_options__ = {'stop_on':[selectable]}
self.selectable = selectable
self.include = include
self.exclude = exclude
self.equivalents = util.column_dict(equivalents or {})
self.adapt_on_names = adapt_on_names
def _corresponding_column(self, col, require_embedded, _seen=util.EMPTY_SET):
newcol = self.selectable.corresponding_column(col, require_embedded=require_embedded)
newcol = self.selectable.corresponding_column(
col,
require_embedded=require_embedded)
if newcol is None and col in self.equivalents and col not in _seen:
for equiv in self.equivalents[col]:
newcol = self._corresponding_column(equiv, require_embedded=require_embedded, _seen=_seen.union([col]))
newcol = self._corresponding_column(equiv,
require_embedded=require_embedded,
_seen=_seen.union([col]))
if newcol is not None:
return newcol
if self.adapt_on_names and newcol is None:
newcol = self.selectable.c.get(col.name)
return newcol
def replace(self, col):
+60 -61
View File
@@ -1,5 +1,5 @@
# sql/visitors.py
# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -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/
"""
@@ -44,22 +44,25 @@ class VisitableType(type):
super(VisitableType, cls).__init__(clsname, bases, clsdict)
return
# set up an optimized visit dispatch function
# for use by the compiler
if '__visit_name__' in cls.__dict__:
visit_name = cls.__visit_name__
if isinstance(visit_name, str):
getter = operator.attrgetter("visit_%s" % visit_name)
def _compiler_dispatch(self, visitor, **kw):
return getter(visitor)(self, **kw)
else:
def _compiler_dispatch(self, visitor, **kw):
return getattr(visitor, 'visit_%s' % self.__visit_name__)(self, **kw)
cls._compiler_dispatch = _compiler_dispatch
_generate_dispatch(cls)
super(VisitableType, cls).__init__(clsname, bases, clsdict)
def _generate_dispatch(cls):
# set up an optimized visit dispatch function
# for use by the compiler
if '__visit_name__' in cls.__dict__:
visit_name = cls.__visit_name__
if isinstance(visit_name, str):
getter = operator.attrgetter("visit_%s" % visit_name)
def _compiler_dispatch(self, visitor, **kw):
return getter(visitor)(self, **kw)
else:
def _compiler_dispatch(self, visitor, **kw):
return getattr(visitor, 'visit_%s' % self.__visit_name__)(self, **kw)
cls._compiler_dispatch = _compiler_dispatch
class Visitable(object):
"""Base class for visitable objects, applies the
``VisitableType`` metaclass.
@@ -209,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."""
cloned = util.column_dict()
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)
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
modifications by visitors."""
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
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 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)
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."""
cloned = util.column_dict()
stop_on = util.column_set(opts.get('stop_on', []))
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