1# sql/visitors.py 
    2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 
    3# <see AUTHORS file> 
    4# 
    5# This module is part of SQLAlchemy and is released under 
    6# the MIT License: https://www.opensource.org/licenses/mit-license.php 
    7 
    8"""Visitor/traversal interface and library functions.""" 
    9 
    10from __future__ import annotations 
    11 
    12from collections import deque 
    13from enum import Enum 
    14import itertools 
    15import operator 
    16import typing 
    17from typing import Any 
    18from typing import Callable 
    19from typing import cast 
    20from typing import ClassVar 
    21from typing import Dict 
    22from typing import Iterable 
    23from typing import Iterator 
    24from typing import List 
    25from typing import Literal 
    26from typing import Mapping 
    27from typing import Optional 
    28from typing import overload 
    29from typing import Protocol 
    30from typing import Tuple 
    31from typing import Type 
    32from typing import TYPE_CHECKING 
    33from typing import TypeVar 
    34from typing import Union 
    35 
    36from ._util_cy import anon_map as anon_map 
    37from ._util_cy import prefix_anon_map as prefix_anon_map  # noqa: F401 
    38from .. import exc 
    39from .. import util 
    40from ..util import langhelpers 
    41from ..util.typing import Self 
    42 
    43if TYPE_CHECKING: 
    44    from .annotation import _AnnotationDict 
    45    from .elements import ColumnElement 
    46 
    47 
    48__all__ = [ 
    49    "iterate", 
    50    "traverse_using", 
    51    "traverse", 
    52    "cloned_traverse", 
    53    "replacement_traverse", 
    54    "Visitable", 
    55    "ExternalTraversal", 
    56    "InternalTraversal", 
    57    "anon_map", 
    58] 
    59 
    60 
    61class _CompilerDispatchType(Protocol): 
    62    def __call__(_self, self: Visitable, visitor: Any, **kw: Any) -> Any: ... 
    63 
    64 
    65class Visitable: 
    66    """Base class for visitable objects. 
    67 
    68    :class:`.Visitable` is used to implement the SQL compiler dispatch 
    69    functions.    Other forms of traversal such as for cache key generation 
    70    are implemented separately using the :class:`.HasTraverseInternals` 
    71    interface. 
    72 
    73    .. versionchanged:: 2.0  The :class:`.Visitable` class was named 
    74       :class:`.Traversible` in the 1.4 series; the name is changed back 
    75       to :class:`.Visitable` in 2.0 which is what it was prior to 1.4. 
    76 
    77       Both names remain importable in both 1.4 and 2.0 versions. 
    78 
    79    """ 
    80 
    81    __slots__ = () 
    82 
    83    __visit_name__: str 
    84 
    85    _original_compiler_dispatch: _CompilerDispatchType 
    86 
    87    if typing.TYPE_CHECKING: 
    88 
    89        def _compiler_dispatch(self, visitor: Any, **kw: Any) -> str: ... 
    90 
    91    def __init_subclass__(cls) -> None: 
    92        if "__visit_name__" in cls.__dict__: 
    93            cls._generate_compiler_dispatch() 
    94        super().__init_subclass__() 
    95 
    96    @classmethod 
    97    def _generate_compiler_dispatch(cls) -> None: 
    98        visit_name = cls.__visit_name__ 
    99 
    100        if "_compiler_dispatch" in cls.__dict__: 
    101            # class has a fixed _compiler_dispatch() method. 
    102            # copy it to "original" so that we can get it back if 
    103            # sqlalchemy.ext.compiles overrides it. 
    104            cls._original_compiler_dispatch = cls._compiler_dispatch 
    105            return 
    106 
    107        if not isinstance(visit_name, str): 
    108            raise exc.InvalidRequestError( 
    109                f"__visit_name__ on class {cls.__name__} must be a string " 
    110                "at the class level" 
    111            ) 
    112 
    113        name = "visit_%s" % visit_name 
    114        getter = operator.attrgetter(name) 
    115 
    116        def _compiler_dispatch( 
    117            self: Visitable, visitor: Any, **kw: Any 
    118        ) -> str: 
    119            """Look for an attribute named "visit_<visit_name>" on the 
    120            visitor, and call it with the same kw params. 
    121 
    122            """ 
    123            try: 
    124                meth = getter(visitor) 
    125            except AttributeError as err: 
    126                return visitor.visit_unsupported_compilation(self, err, **kw)  # type: ignore  # noqa: E501 
    127            else: 
    128                return meth(self, **kw)  # type: ignore  # noqa: E501 
    129 
    130        cls._compiler_dispatch = (  # type: ignore 
    131            cls._original_compiler_dispatch 
    132        ) = _compiler_dispatch 
    133 
    134    def __class_getitem__(cls, key: Any) -> Any: 
    135        # allow generic classes in py3.9+ 
    136        return cls 
    137 
    138 
    139class InternalTraversal(Enum): 
    140    r"""Defines visitor symbols used for internal traversal. 
    141 
    142    The :class:`.InternalTraversal` class is used in two ways.  One is that 
    143    it can serve as the superclass for an object that implements the 
    144    various visit methods of the class.   The other is that the symbols 
    145    themselves of :class:`.InternalTraversal` are used within 
    146    the ``_traverse_internals`` collection.   Such as, the :class:`.Case` 
    147    object defines ``_traverse_internals`` as :: 
    148 
    149        class Case(ColumnElement[_T]): 
    150            _traverse_internals = [ 
    151                ("value", InternalTraversal.dp_clauseelement), 
    152                ("whens", InternalTraversal.dp_clauseelement_tuples), 
    153                ("else_", InternalTraversal.dp_clauseelement), 
    154            ] 
    155 
    156    Above, the :class:`.Case` class indicates its internal state as the 
    157    attributes named ``value``, ``whens``, and ``else_``.    They each 
    158    link to an :class:`.InternalTraversal` method which indicates the type 
    159    of datastructure to which each attribute refers. 
    160 
    161    Using the ``_traverse_internals`` structure, objects of type 
    162    :class:`.InternalTraversible` will have the following methods automatically 
    163    implemented: 
    164 
    165    * :meth:`.HasTraverseInternals.get_children` 
    166 
    167    * :meth:`.HasTraverseInternals._copy_internals` 
    168 
    169    * :meth:`.HasCacheKey._gen_cache_key` 
    170 
    171    Subclasses can also implement these methods directly, particularly for the 
    172    :meth:`.HasTraverseInternals._copy_internals` method, when special steps 
    173    are needed. 
    174 
    175    .. versionadded:: 1.4 
    176 
    177    """ 
    178 
    179    dp_has_cache_key = "HC" 
    180    """Visit a :class:`.HasCacheKey` object.""" 
    181 
    182    dp_has_cache_key_list = "HL" 
    183    """Visit a list of :class:`.HasCacheKey` objects.""" 
    184 
    185    dp_clauseelement = "CE" 
    186    """Visit a :class:`_expression.ClauseElement` object.""" 
    187 
    188    dp_fromclause_canonical_column_collection = "FC" 
    189    """Visit a :class:`_expression.FromClause` object in the context of the 
    190    ``columns`` attribute. 
    191 
    192    The column collection is "canonical", meaning it is the originally 
    193    defined location of the :class:`.ColumnClause` objects.   Right now 
    194    this means that the object being visited is a 
    195    :class:`_expression.TableClause` 
    196    or :class:`_schema.Table` object only. 
    197 
    198    """ 
    199 
    200    dp_clauseelement_tuples = "CTS" 
    201    """Visit a list of tuples which contain :class:`_expression.ClauseElement` 
    202    objects. 
    203 
    204    """ 
    205 
    206    dp_clauseelement_list = "CL" 
    207    """Visit a list of :class:`_expression.ClauseElement` objects. 
    208 
    209    """ 
    210 
    211    dp_clauseelement_tuple = "CT" 
    212    """Visit a tuple of :class:`_expression.ClauseElement` objects. 
    213 
    214    """ 
    215 
    216    dp_executable_options = "EO" 
    217 
    218    dp_compile_state_funcs = "WC" 
    219 
    220    dp_fromclause_ordered_set = "CO" 
    221    """Visit an ordered set of :class:`_expression.FromClause` objects. """ 
    222 
    223    dp_string = "S" 
    224    """Visit a plain string value. 
    225 
    226    Examples include table and column names, bound parameter keys, special 
    227    keywords such as "UNION", "UNION ALL". 
    228 
    229    The string value is considered to be significant for cache key 
    230    generation. 
    231 
    232    """ 
    233 
    234    dp_string_list = "SL" 
    235    """Visit a list of strings.""" 
    236 
    237    dp_anon_name = "AN" 
    238    """Visit a potentially "anonymized" string value. 
    239 
    240    The string value is considered to be significant for cache key 
    241    generation. 
    242 
    243    """ 
    244 
    245    dp_boolean = "B" 
    246    """Visit a boolean value. 
    247 
    248    The boolean value is considered to be significant for cache key 
    249    generation. 
    250 
    251    """ 
    252 
    253    dp_operator = "O" 
    254    """Visit an operator. 
    255 
    256    The operator is a function from the :mod:`sqlalchemy.sql.operators` 
    257    module. 
    258 
    259    The operator value is considered to be significant for cache key 
    260    generation. 
    261 
    262    """ 
    263 
    264    dp_type = "T" 
    265    """Visit a :class:`.TypeEngine` object 
    266 
    267    The type object is considered to be significant for cache key 
    268    generation. 
    269 
    270    """ 
    271 
    272    dp_plain_dict = "PD" 
    273    """Visit a dictionary with string keys. 
    274 
    275    The keys of the dictionary should be strings, the values should 
    276    be immutable and hashable.   The dictionary is considered to be 
    277    significant for cache key generation. 
    278 
    279    """ 
    280 
    281    dp_dialect_options = "DO" 
    282    """Visit a dialect options structure.""" 
    283 
    284    dp_string_clauseelement_dict = "CD" 
    285    """Visit a dictionary of string keys to :class:`_expression.ClauseElement` 
    286    objects. 
    287 
    288    """ 
    289 
    290    dp_string_multi_dict = "MD" 
    291    """Visit a dictionary of string keys to values which may either be 
    292    plain immutable/hashable or :class:`.HasCacheKey` objects. 
    293 
    294    """ 
    295 
    296    dp_annotations_key = "AK" 
    297    """Visit the _annotations_cache_key element. 
    298 
    299    This is a dictionary of additional information about a ClauseElement 
    300    that modifies its role.  It should be included when comparing or caching 
    301    objects, however generating this key is relatively expensive.   Visitors 
    302    should check the "_annotations" dict for non-None first before creating 
    303    this key. 
    304 
    305    """ 
    306 
    307    dp_plain_obj = "PO" 
    308    """Visit a plain python object. 
    309 
    310    The value should be immutable and hashable, such as an integer. 
    311    The value is considered to be significant for cache key generation. 
    312 
    313    """ 
    314 
    315    dp_named_ddl_element = "DD" 
    316    """Visit a simple named DDL element. 
    317 
    318    The current object used by this method is the :class:`.Sequence`. 
    319 
    320    The object is only considered to be important for cache key generation 
    321    as far as its name, but not any other aspects of it. 
    322 
    323    """ 
    324 
    325    dp_prefix_sequence = "PS" 
    326    """Visit the sequence represented by :class:`_expression.HasPrefixes` 
    327    or :class:`_expression.HasSuffixes`. 
    328 
    329    """ 
    330 
    331    dp_table_hint_list = "TH" 
    332    """Visit the ``_hints`` collection of a :class:`_expression.Select` 
    333    object. 
    334 
    335    """ 
    336 
    337    dp_setup_join_tuple = "SJ" 
    338 
    339    dp_memoized_select_entities = "ME" 
    340 
    341    dp_statement_hint_list = "SH" 
    342    """Visit the ``_statement_hints`` collection of a 
    343    :class:`_expression.Select` 
    344    object. 
    345 
    346    """ 
    347 
    348    dp_unknown_structure = "UK" 
    349    """Visit an unknown structure. 
    350 
    351    """ 
    352 
    353    dp_dml_ordered_values = "DML_OV" 
    354    """Visit the values() ordered tuple list of an 
    355    :class:`_expression.Update` object.""" 
    356 
    357    dp_dml_values = "DML_V" 
    358    """Visit the values() dictionary of a :class:`.ValuesBase` 
    359    (e.g. Insert or Update) object. 
    360 
    361    """ 
    362 
    363    dp_dml_multi_values = "DML_MV" 
    364    """Visit the values() multi-valued list of dictionaries of an 
    365    :class:`_expression.Insert` object. 
    366 
    367    """ 
    368 
    369    dp_propagate_attrs = "PA" 
    370    """Visit the propagate attrs dict.  This hardcodes to the particular 
    371    elements we care about right now.""" 
    372 
    373    """Symbols that follow are additional symbols that are useful in 
    374    caching applications. 
    375 
    376    Traversals for :class:`_expression.ClauseElement` objects only need to use 
    377    those symbols present in :class:`.InternalTraversal`.  However, for 
    378    additional caching use cases within the ORM, symbols dealing with the 
    379    :class:`.HasCacheKey` class are added here. 
    380 
    381    """ 
    382 
    383    dp_ignore = "IG" 
    384    """Specify an object that should be ignored entirely. 
    385 
    386    This currently applies function call argument caching where some 
    387    arguments should not be considered to be part of a cache key. 
    388 
    389    """ 
    390 
    391    dp_inspectable = "IS" 
    392    """Visit an inspectable object where the return value is a 
    393    :class:`.HasCacheKey` object.""" 
    394 
    395    dp_multi = "M" 
    396    """Visit an object that may be a :class:`.HasCacheKey` or may be a 
    397    plain hashable object.""" 
    398 
    399    dp_multi_list = "MT" 
    400    """Visit a tuple containing elements that may be :class:`.HasCacheKey` or 
    401    may be a plain hashable object.""" 
    402 
    403    dp_has_cache_key_tuples = "HT" 
    404    """Visit a list of tuples which contain :class:`.HasCacheKey` 
    405    objects. 
    406 
    407    """ 
    408 
    409    dp_inspectable_list = "IL" 
    410    """Visit a list of inspectable objects which upon inspection are 
    411    HasCacheKey objects.""" 
    412 
    413 
    414_TraverseInternalsType = List[Tuple[str, InternalTraversal]] 
    415"""a structure that defines how a HasTraverseInternals should be 
    416traversed. 
    417 
    418This structure consists of a list of (attributename, internaltraversal) 
    419tuples, where the "attributename" refers to the name of an attribute on an 
    420instance of the HasTraverseInternals object, and "internaltraversal" refers 
    421to an :class:`.InternalTraversal` enumeration symbol defining what kind 
    422of data this attribute stores, which indicates to the traverser how it should 
    423be handled. 
    424 
    425""" 
    426 
    427 
    428class HasTraverseInternals: 
    429    """base for classes that have a "traverse internals" element, 
    430    which defines all kinds of ways of traversing the elements of an object. 
    431 
    432    Compared to :class:`.Visitable`, which relies upon an external visitor to 
    433    define how the object is travered (i.e. the :class:`.SQLCompiler`), the 
    434    :class:`.HasTraverseInternals` interface allows classes to define their own 
    435    traversal, that is, what attributes are accessed and in what order. 
    436 
    437    """ 
    438 
    439    __slots__ = () 
    440 
    441    _traverse_internals: _TraverseInternalsType 
    442 
    443    _is_immutable: bool = False 
    444 
    445    @util.preload_module("sqlalchemy.sql.traversals") 
    446    def get_children( 
    447        self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any 
    448    ) -> Iterable[HasTraverseInternals]: 
    449        r"""Return immediate child :class:`.visitors.HasTraverseInternals` 
    450        elements of this :class:`.visitors.HasTraverseInternals`. 
    451 
    452        This is used for visit traversal. 
    453 
    454        \**kw may contain flags that change the collection that is 
    455        returned, for example to return a subset of items in order to 
    456        cut down on larger traversals, or to return child items from a 
    457        different context (such as schema-level collections instead of 
    458        clause-level). 
    459 
    460        """ 
    461 
    462        traversals = util.preloaded.sql_traversals 
    463 
    464        try: 
    465            traverse_internals = self._traverse_internals 
    466        except AttributeError: 
    467            # user-defined classes may not have a _traverse_internals 
    468            return [] 
    469 
    470        dispatch = traversals._get_children.run_generated_dispatch 
    471        return itertools.chain.from_iterable( 
    472            meth(obj, **kw) 
    473            for attrname, obj, meth in dispatch( 
    474                self, traverse_internals, "_generated_get_children_traversal" 
    475            ) 
    476            if attrname not in omit_attrs and obj is not None 
    477        ) 
    478 
    479 
    480class _InternalTraversalDispatchType(Protocol): 
    481    def __call__(s, self: object, visitor: HasTraversalDispatch) -> Any: ... 
    482 
    483 
    484class HasTraversalDispatch: 
    485    r"""Define infrastructure for classes that perform internal traversals 
    486 
    487    .. versionadded:: 2.0 
    488 
    489    """ 
    490 
    491    __slots__ = () 
    492 
    493    _dispatch_lookup: ClassVar[Dict[Union[InternalTraversal, str], str]] = {} 
    494 
    495    def dispatch(self, visit_symbol: InternalTraversal) -> Callable[..., Any]: 
    496        """Given a method from :class:`.HasTraversalDispatch`, return the 
    497        corresponding method on a subclass. 
    498 
    499        """ 
    500        name = _dispatch_lookup[visit_symbol] 
    501        return getattr(self, name, None)  # type: ignore 
    502 
    503    def run_generated_dispatch( 
    504        self, 
    505        target: object, 
    506        internal_dispatch: _TraverseInternalsType, 
    507        generate_dispatcher_name: str, 
    508    ) -> Any: 
    509        dispatcher: _InternalTraversalDispatchType 
    510        try: 
    511            dispatcher = target.__class__.__dict__[generate_dispatcher_name] 
    512        except KeyError: 
    513            # traversals.py -> _preconfigure_traversals() 
    514            # may be used to run these ahead of time, but 
    515            # is not enabled right now. 
    516            # this block will generate any remaining dispatchers. 
    517            dispatcher = self.generate_dispatch( 
    518                target.__class__, internal_dispatch, generate_dispatcher_name 
    519            ) 
    520        return dispatcher(target, self) 
    521 
    522    def generate_dispatch( 
    523        self, 
    524        target_cls: Type[object], 
    525        internal_dispatch: _TraverseInternalsType, 
    526        generate_dispatcher_name: str, 
    527    ) -> _InternalTraversalDispatchType: 
    528        dispatcher = self._generate_dispatcher( 
    529            internal_dispatch, generate_dispatcher_name 
    530        ) 
    531        # assert isinstance(target_cls, type) 
    532        setattr(target_cls, generate_dispatcher_name, dispatcher) 
    533        return dispatcher 
    534 
    535    def _generate_dispatcher( 
    536        self, internal_dispatch: _TraverseInternalsType, method_name: str 
    537    ) -> _InternalTraversalDispatchType: 
    538        names = [] 
    539        for attrname, visit_sym in internal_dispatch: 
    540            meth = self.dispatch(visit_sym) 
    541            if meth is not None: 
    542                visit_name = _dispatch_lookup[visit_sym] 
    543                names.append((attrname, visit_name)) 
    544 
    545        code = ( 
    546            ("    return [\n") 
    547            + ( 
    548                ", \n".join( 
    549                    "        (%r, self.%s, visitor.%s)" 
    550                    % (attrname, attrname, visit_name) 
    551                    for attrname, visit_name in names 
    552                ) 
    553            ) 
    554            + ("\n    ]\n") 
    555        ) 
    556        meth_text = ("def %s(self, visitor):\n" % method_name) + code + "\n" 
    557        return cast( 
    558            _InternalTraversalDispatchType, 
    559            langhelpers._exec_code_in_env(meth_text, {}, method_name), 
    560        ) 
    561 
    562 
    563ExtendedInternalTraversal = InternalTraversal 
    564 
    565 
    566def _generate_traversal_dispatch() -> None: 
    567    lookup = _dispatch_lookup 
    568 
    569    for sym in InternalTraversal: 
    570        key = sym.name 
    571        if key.startswith("dp_"): 
    572            visit_key = key.replace("dp_", "visit_") 
    573            sym_name = sym.value 
    574            assert sym_name not in lookup, sym_name 
    575            lookup[sym] = lookup[sym_name] = visit_key 
    576 
    577 
    578_dispatch_lookup = HasTraversalDispatch._dispatch_lookup 
    579_generate_traversal_dispatch() 
    580 
    581 
    582class ExternallyTraversible(HasTraverseInternals, Visitable): 
    583    __slots__ = () 
    584 
    585    _annotations: Mapping[Any, Any] = util.EMPTY_DICT 
    586 
    587    if typing.TYPE_CHECKING: 
    588 
    589        def _annotate(self, values: _AnnotationDict) -> Self: ... 
    590 
    591        def get_children( 
    592            self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any 
    593        ) -> Iterable[ExternallyTraversible]: ... 
    594 
    595    def _clone(self, **kw: Any) -> Self: 
    596        """clone this element""" 
    597        raise NotImplementedError() 
    598 
    599    def _copy_internals( 
    600        self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any 
    601    ) -> None: 
    602        """Reassign internal elements to be clones of themselves. 
    603 
    604        Called during a copy-and-traverse operation on newly 
    605        shallow-copied elements to create a deep copy. 
    606 
    607        The given clone function should be used, which may be applying 
    608        additional transformations to the element (i.e. replacement 
    609        traversal, cloned traversal, annotations). 
    610 
    611        """ 
    612        raise NotImplementedError() 
    613 
    614 
    615_ET = TypeVar("_ET", bound=ExternallyTraversible) 
    616 
    617_CE = TypeVar("_CE", bound="ColumnElement[Any]") 
    618 
    619_TraverseCallableType = Callable[[_ET], None] 
    620 
    621 
    622class _CloneCallableType(Protocol): 
    623    def __call__(self, element: _ET, **kw: Any) -> _ET: ... 
    624 
    625 
    626class _TraverseTransformCallableType(Protocol[_ET]): 
    627    def __call__(self, element: _ET, **kw: Any) -> Optional[_ET]: ... 
    628 
    629 
    630_ExtT = TypeVar("_ExtT", bound="ExternalTraversal") 
    631 
    632 
    633class ExternalTraversal(util.MemoizedSlots): 
    634    """Base class for visitor objects which can traverse externally using 
    635    the :func:`.visitors.traverse` function. 
    636 
    637    Direct usage of the :func:`.visitors.traverse` function is usually 
    638    preferred. 
    639 
    640    """ 
    641 
    642    __slots__ = ("_visitor_dict", "_next") 
    643 
    644    __traverse_options__: Dict[str, Any] = {} 
    645    _next: Optional[ExternalTraversal] 
    646 
    647    def traverse_single(self, obj: Visitable, **kw: Any) -> Any: 
    648        for v in self.visitor_iterator: 
    649            meth = getattr(v, "visit_%s" % obj.__visit_name__, None) 
    650            if meth: 
    651                return meth(obj, **kw) 
    652 
    653    def iterate( 
    654        self, obj: Optional[ExternallyTraversible] 
    655    ) -> Iterator[ExternallyTraversible]: 
    656        """Traverse the given expression structure, returning an iterator 
    657        of all elements. 
    658 
    659        """ 
    660        return iterate(obj, self.__traverse_options__) 
    661 
    662    @overload 
    663    def traverse(self, obj: Literal[None]) -> None: ... 
    664 
    665    @overload 
    666    def traverse( 
    667        self, obj: ExternallyTraversible 
    668    ) -> ExternallyTraversible: ... 
    669 
    670    def traverse( 
    671        self, obj: Optional[ExternallyTraversible] 
    672    ) -> Optional[ExternallyTraversible]: 
    673        """Traverse and visit the given expression structure.""" 
    674 
    675        return traverse(obj, self.__traverse_options__, self._visitor_dict) 
    676 
    677    def _memoized_attr__visitor_dict( 
    678        self, 
    679    ) -> Dict[str, _TraverseCallableType[Any]]: 
    680        visitors = {} 
    681 
    682        for name in dir(self): 
    683            if name.startswith("visit_"): 
    684                visitors[name[6:]] = getattr(self, name) 
    685        return visitors 
    686 
    687    @property 
    688    def visitor_iterator(self) -> Iterator[ExternalTraversal]: 
    689        """Iterate through this visitor and each 'chained' visitor.""" 
    690 
    691        v: Optional[ExternalTraversal] = self 
    692        while v: 
    693            yield v 
    694            v = getattr(v, "_next", None) 
    695 
    696    def chain(self: _ExtT, visitor: ExternalTraversal) -> _ExtT: 
    697        """'Chain' an additional ExternalTraversal onto this ExternalTraversal 
    698 
    699        The chained visitor will receive all visit events after this one. 
    700 
    701        """ 
    702        tail = list(self.visitor_iterator)[-1] 
    703        tail._next = visitor 
    704        return self 
    705 
    706 
    707class CloningExternalTraversal(ExternalTraversal): 
    708    """Base class for visitor objects which can traverse using 
    709    the :func:`.visitors.cloned_traverse` function. 
    710 
    711    Direct usage of the :func:`.visitors.cloned_traverse` function is usually 
    712    preferred. 
    713 
    714 
    715    """ 
    716 
    717    __slots__ = () 
    718 
    719    def copy_and_process( 
    720        self, list_: List[ExternallyTraversible] 
    721    ) -> List[ExternallyTraversible]: 
    722        """Apply cloned traversal to the given list of elements, and return 
    723        the new list. 
    724 
    725        """ 
    726        return [self.traverse(x) for x in list_] 
    727 
    728    @overload 
    729    def traverse(self, obj: Literal[None]) -> None: ... 
    730 
    731    @overload 
    732    def traverse( 
    733        self, obj: ExternallyTraversible 
    734    ) -> ExternallyTraversible: ... 
    735 
    736    def traverse( 
    737        self, obj: Optional[ExternallyTraversible] 
    738    ) -> Optional[ExternallyTraversible]: 
    739        """Traverse and visit the given expression structure.""" 
    740 
    741        return cloned_traverse( 
    742            obj, self.__traverse_options__, self._visitor_dict 
    743        ) 
    744 
    745 
    746class ReplacingExternalTraversal(CloningExternalTraversal): 
    747    """Base class for visitor objects which can traverse using 
    748    the :func:`.visitors.replacement_traverse` function. 
    749 
    750    Direct usage of the :func:`.visitors.replacement_traverse` function is 
    751    usually preferred. 
    752 
    753    """ 
    754 
    755    __slots__ = () 
    756 
    757    def replace( 
    758        self, elem: ExternallyTraversible 
    759    ) -> Optional[ExternallyTraversible]: 
    760        """Receive pre-copied elements during a cloning traversal. 
    761 
    762        If the method returns a new element, the element is used 
    763        instead of creating a simple copy of the element.  Traversal 
    764        will halt on the newly returned element if it is re-encountered. 
    765        """ 
    766        return None 
    767 
    768    @overload 
    769    def traverse(self, obj: Literal[None]) -> None: ... 
    770 
    771    @overload 
    772    def traverse( 
    773        self, obj: ExternallyTraversible 
    774    ) -> ExternallyTraversible: ... 
    775 
    776    def traverse( 
    777        self, obj: Optional[ExternallyTraversible] 
    778    ) -> Optional[ExternallyTraversible]: 
    779        """Traverse and visit the given expression structure.""" 
    780 
    781        def replace( 
    782            element: ExternallyTraversible, 
    783            **kw: Any, 
    784        ) -> Optional[ExternallyTraversible]: 
    785            for v in self.visitor_iterator: 
    786                e = cast(ReplacingExternalTraversal, v).replace(element) 
    787                if e is not None: 
    788                    return e 
    789 
    790            return None 
    791 
    792        return replacement_traverse(obj, self.__traverse_options__, replace) 
    793 
    794 
    795# backwards compatibility 
    796Traversible = Visitable 
    797 
    798ClauseVisitor = ExternalTraversal 
    799CloningVisitor = CloningExternalTraversal 
    800ReplacingCloningVisitor = ReplacingExternalTraversal 
    801 
    802 
    803def iterate( 
    804    obj: Optional[ExternallyTraversible], 
    805    opts: Mapping[str, Any] = util.EMPTY_DICT, 
    806) -> Iterator[ExternallyTraversible]: 
    807    r"""Traverse the given expression structure, returning an iterator. 
    808 
    809    Traversal is configured to be breadth-first. 
    810 
    811    The central API feature used by the :func:`.visitors.iterate` 
    812    function is the 
    813    :meth:`_expression.ClauseElement.get_children` method of 
    814    :class:`_expression.ClauseElement` objects.  This method should return all 
    815    the :class:`_expression.ClauseElement` objects which are associated with a 
    816    particular :class:`_expression.ClauseElement` object. For example, a 
    817    :class:`.Case` structure will refer to a series of 
    818    :class:`_expression.ColumnElement` objects within its "whens" and "else\_" 
    819    member variables. 
    820 
    821    :param obj: :class:`_expression.ClauseElement` structure to be traversed 
    822 
    823    :param opts: dictionary of iteration options.   This dictionary is usually 
    824     empty in modern usage. 
    825 
    826    """ 
    827    if obj is None: 
    828        return 
    829 
    830    yield obj 
    831    children = obj.get_children(**opts) 
    832 
    833    if not children: 
    834        return 
    835 
    836    stack = deque([children]) 
    837    while stack: 
    838        t_iterator = stack.popleft() 
    839        for t in t_iterator: 
    840            yield t 
    841            stack.append(t.get_children(**opts)) 
    842 
    843 
    844@overload 
    845def traverse_using( 
    846    iterator: Iterable[ExternallyTraversible], 
    847    obj: Literal[None], 
    848    visitors: Mapping[str, _TraverseCallableType[Any]], 
    849) -> None: ... 
    850 
    851 
    852@overload 
    853def traverse_using( 
    854    iterator: Iterable[ExternallyTraversible], 
    855    obj: ExternallyTraversible, 
    856    visitors: Mapping[str, _TraverseCallableType[Any]], 
    857) -> ExternallyTraversible: ... 
    858 
    859 
    860def traverse_using( 
    861    iterator: Iterable[ExternallyTraversible], 
    862    obj: Optional[ExternallyTraversible], 
    863    visitors: Mapping[str, _TraverseCallableType[Any]], 
    864) -> Optional[ExternallyTraversible]: 
    865    """Visit the given expression structure using the given iterator of 
    866    objects. 
    867 
    868    :func:`.visitors.traverse_using` is usually called internally as the result 
    869    of the :func:`.visitors.traverse` function. 
    870 
    871    :param iterator: an iterable or sequence which will yield 
    872     :class:`_expression.ClauseElement` 
    873     structures; the iterator is assumed to be the 
    874     product of the :func:`.visitors.iterate` function. 
    875 
    876    :param obj: the :class:`_expression.ClauseElement` 
    877     that was used as the target of the 
    878     :func:`.iterate` function. 
    879 
    880    :param visitors: dictionary of visit functions.  See :func:`.traverse` 
    881     for details on this dictionary. 
    882 
    883    .. seealso:: 
    884 
    885        :func:`.traverse` 
    886 
    887 
    888    """ 
    889    for target in iterator: 
    890        meth = visitors.get(target.__visit_name__, None) 
    891        if meth: 
    892            meth(target) 
    893    return obj 
    894 
    895 
    896@overload 
    897def traverse( 
    898    obj: Literal[None], 
    899    opts: Mapping[str, Any], 
    900    visitors: Mapping[str, _TraverseCallableType[Any]], 
    901) -> None: ... 
    902 
    903 
    904@overload 
    905def traverse( 
    906    obj: ExternallyTraversible, 
    907    opts: Mapping[str, Any], 
    908    visitors: Mapping[str, _TraverseCallableType[Any]], 
    909) -> ExternallyTraversible: ... 
    910 
    911 
    912def traverse( 
    913    obj: Optional[ExternallyTraversible], 
    914    opts: Mapping[str, Any], 
    915    visitors: Mapping[str, _TraverseCallableType[Any]], 
    916) -> Optional[ExternallyTraversible]: 
    917    """Traverse and visit the given expression structure using the default 
    918    iterator. 
    919 
    920     e.g.:: 
    921 
    922        from sqlalchemy.sql import visitors 
    923 
    924        stmt = select(some_table).where(some_table.c.foo == "bar") 
    925 
    926 
    927        def visit_bindparam(bind_param): 
    928            print("found bound value: %s" % bind_param.value) 
    929 
    930 
    931        visitors.traverse(stmt, {}, {"bindparam": visit_bindparam}) 
    932 
    933    The iteration of objects uses the :func:`.visitors.iterate` function, 
    934    which does a breadth-first traversal using a stack. 
    935 
    936    :param obj: :class:`_expression.ClauseElement` structure to be traversed 
    937 
    938    :param opts: dictionary of iteration options.   This dictionary is usually 
    939     empty in modern usage. 
    940 
    941    :param visitors: dictionary of visit functions.   The dictionary should 
    942     have strings as keys, each of which would correspond to the 
    943     ``__visit_name__`` of a particular kind of SQL expression object, and 
    944     callable functions  as values, each of which represents a visitor function 
    945     for that kind of object. 
    946 
    947    """ 
    948    return traverse_using(iterate(obj, opts), obj, visitors) 
    949 
    950 
    951@overload 
    952def cloned_traverse( 
    953    obj: Literal[None], 
    954    opts: Mapping[str, Any], 
    955    visitors: Mapping[str, _TraverseCallableType[Any]], 
    956) -> None: ... 
    957 
    958 
    959# a bit of controversy here, as the clone of the lead element 
    960# *could* in theory replace with an entirely different kind of element. 
    961# however this is really not how cloned_traverse is ever used internally 
    962# at least. 
    963@overload 
    964def cloned_traverse( 
    965    obj: _ET, 
    966    opts: Mapping[str, Any], 
    967    visitors: Mapping[str, _TraverseCallableType[Any]], 
    968) -> _ET: ... 
    969 
    970 
    971def cloned_traverse( 
    972    obj: Optional[ExternallyTraversible], 
    973    opts: Mapping[str, Any], 
    974    visitors: Mapping[str, _TraverseCallableType[Any]], 
    975) -> Optional[ExternallyTraversible]: 
    976    """Clone the given expression structure, allowing modifications by 
    977    visitors for mutable objects. 
    978 
    979    Traversal usage is the same as that of :func:`.visitors.traverse`. 
    980    The visitor functions present in the ``visitors`` dictionary may also 
    981    modify the internals of the given structure as the traversal proceeds. 
    982 
    983    The :func:`.cloned_traverse` function does **not** provide objects that are 
    984    part of the :class:`.Immutable` interface to the visit methods (this 
    985    primarily includes :class:`.ColumnClause`, :class:`.Column`, 
    986    :class:`.TableClause` and :class:`.Table` objects). As this traversal is 
    987    only intended to allow in-place mutation of objects, :class:`.Immutable` 
    988    objects are skipped. The :meth:`.Immutable._clone` method is still called 
    989    on each object to allow for objects to replace themselves with a different 
    990    object based on a clone of their sub-internals (e.g. a 
    991    :class:`.ColumnClause` that clones its subquery to return a new 
    992    :class:`.ColumnClause`). 
    993 
    994    .. versionchanged:: 2.0  The :func:`.cloned_traverse` function omits 
    995       objects that are part of the :class:`.Immutable` interface. 
    996 
    997    The central API feature used by the :func:`.visitors.cloned_traverse` 
    998    and :func:`.visitors.replacement_traverse` functions, in addition to the 
    999    :meth:`_expression.ClauseElement.get_children` 
    1000    function that is used to achieve 
    1001    the iteration, is the :meth:`_expression.ClauseElement._copy_internals` 
    1002    method. 
    1003    For a :class:`_expression.ClauseElement` 
    1004    structure to support cloning and replacement 
    1005    traversals correctly, it needs to be able to pass a cloning function into 
    1006    its internal members in order to make copies of them. 
    1007 
    1008    .. seealso:: 
    1009 
    1010        :func:`.visitors.traverse` 
    1011 
    1012        :func:`.visitors.replacement_traverse` 
    1013 
    1014    """ 
    1015 
    1016    cloned: Dict[int, ExternallyTraversible] = {} 
    1017    stop_on = set(opts.get("stop_on", [])) 
    1018 
    1019    def deferred_copy_internals( 
    1020        obj: ExternallyTraversible, 
    1021    ) -> ExternallyTraversible: 
    1022        return cloned_traverse(obj, opts, visitors) 
    1023 
    1024    def clone(elem: ExternallyTraversible, **kw: Any) -> ExternallyTraversible: 
    1025        if elem in stop_on: 
    1026            return elem 
    1027        else: 
    1028            if id(elem) not in cloned: 
    1029                if "replace" in kw: 
    1030                    newelem = cast( 
    1031                        Optional[ExternallyTraversible], kw["replace"](elem) 
    1032                    ) 
    1033                    if newelem is not None: 
    1034                        cloned[id(elem)] = newelem 
    1035                        return newelem 
    1036 
    1037                # the _clone method for immutable normally returns "self". 
    1038                # however, the method is still allowed to return a 
    1039                # different object altogether; ColumnClause._clone() will 
    1040                # based on options clone the subquery to which it is associated 
    1041                # and return the new corresponding column. 
    1042                cloned[id(elem)] = newelem = elem._clone(clone=clone, **kw) 
    1043                newelem._copy_internals(clone=clone, **kw) 
    1044 
    1045                # however, visit methods which are tasked with in-place 
    1046                # mutation of the object should not get access to the immutable 
    1047                # object. 
    1048                if not elem._is_immutable: 
    1049                    meth = visitors.get(newelem.__visit_name__, None) 
    1050                    if meth: 
    1051                        meth(newelem) 
    1052            return cloned[id(elem)] 
    1053 
    1054    if obj is not None: 
    1055        obj = clone( 
    1056            obj, deferred_copy_internals=deferred_copy_internals, **opts 
    1057        ) 
    1058    clone = None  # type: ignore[assignment]  # remove gc cycles 
    1059    return obj 
    1060 
    1061 
    1062@overload 
    1063def replacement_traverse( 
    1064    obj: Literal[None], 
    1065    opts: Mapping[str, Any], 
    1066    replace: _TraverseTransformCallableType[Any], 
    1067) -> None: ... 
    1068 
    1069 
    1070@overload 
    1071def replacement_traverse( 
    1072    obj: _CE, 
    1073    opts: Mapping[str, Any], 
    1074    replace: _TraverseTransformCallableType[Any], 
    1075) -> _CE: ... 
    1076 
    1077 
    1078@overload 
    1079def replacement_traverse( 
    1080    obj: ExternallyTraversible, 
    1081    opts: Mapping[str, Any], 
    1082    replace: _TraverseTransformCallableType[Any], 
    1083) -> ExternallyTraversible: ... 
    1084 
    1085 
    1086def replacement_traverse( 
    1087    obj: Optional[ExternallyTraversible], 
    1088    opts: Mapping[str, Any], 
    1089    replace: _TraverseTransformCallableType[Any], 
    1090) -> Optional[ExternallyTraversible]: 
    1091    """Clone the given expression structure, allowing element 
    1092    replacement by a given replacement function. 
    1093 
    1094    This function is very similar to the :func:`.visitors.cloned_traverse` 
    1095    function, except instead of being passed a dictionary of visitors, all 
    1096    elements are unconditionally passed into the given replace function. 
    1097    The replace function then has the option to return an entirely new object 
    1098    which will replace the one given.  If it returns ``None``, then the object 
    1099    is kept in place. 
    1100 
    1101    The difference in usage between :func:`.visitors.cloned_traverse` and 
    1102    :func:`.visitors.replacement_traverse` is that in the former case, an 
    1103    already-cloned object is passed to the visitor function, and the visitor 
    1104    function can then manipulate the internal state of the object. 
    1105    In the case of the latter, the visitor function should only return an 
    1106    entirely different object, or do nothing. 
    1107 
    1108    The use case for :func:`.visitors.replacement_traverse` is that of 
    1109    replacing a FROM clause inside of a SQL structure with a different one, 
    1110    as is a common use case within the ORM. 
    1111 
    1112    """ 
    1113 
    1114    cloned = {} 
    1115    stop_on = {id(x) for x in opts.get("stop_on", [])} 
    1116 
    1117    def deferred_copy_internals( 
    1118        obj: ExternallyTraversible, 
    1119    ) -> ExternallyTraversible: 
    1120        return replacement_traverse(obj, opts, replace) 
    1121 
    1122    def clone(elem: ExternallyTraversible, **kw: Any) -> ExternallyTraversible: 
    1123        if ( 
    1124            id(elem) in stop_on 
    1125            or "no_replacement_traverse" in elem._annotations 
    1126        ): 
    1127            return elem 
    1128        else: 
    1129            newelem = replace(elem) 
    1130            if newelem is not None: 
    1131                stop_on.add(id(newelem)) 
    1132                return newelem  # type: ignore 
    1133            else: 
    1134                # base "already seen" on id(), not hash, so that we don't 
    1135                # replace an Annotated element with its non-annotated one, and 
    1136                # vice versa 
    1137                id_elem = id(elem) 
    1138                if id_elem not in cloned: 
    1139                    if "replace" in kw: 
    1140                        newelem = kw["replace"](elem) 
    1141                        if newelem is not None: 
    1142                            cloned[id_elem] = newelem 
    1143                            return newelem  # type: ignore 
    1144 
    1145                    cloned[id_elem] = newelem = elem._clone(**kw) 
    1146                    newelem._copy_internals(clone=clone, **kw) 
    1147                return cloned[id_elem]  # type: ignore 
    1148 
    1149    if obj is not None: 
    1150        obj = clone( 
    1151            obj, deferred_copy_internals=deferred_copy_internals, **opts 
    1152        ) 
    1153    clone = None  # type: ignore[assignment]  # remove gc cycles 
    1154    return obj