summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py')
-rw-r--r--venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py1165
1 files changed, 0 insertions, 1165 deletions
diff --git a/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py b/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py
deleted file mode 100644
index d1cd7a9..0000000
--- a/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py
+++ /dev/null
@@ -1,1165 +0,0 @@
-# sql/visitors.py
-# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
-# <see AUTHORS file>
-#
-# This module is part of SQLAlchemy and is released under
-# the MIT License: https://www.opensource.org/licenses/mit-license.php
-
-"""Visitor/traversal interface and library functions.
-
-
-"""
-
-from __future__ import annotations
-
-from collections import deque
-from enum import Enum
-import itertools
-import operator
-import typing
-from typing import Any
-from typing import Callable
-from typing import cast
-from typing import ClassVar
-from typing import Dict
-from typing import Iterable
-from typing import Iterator
-from typing import List
-from typing import Mapping
-from typing import Optional
-from typing import overload
-from typing import Tuple
-from typing import Type
-from typing import TYPE_CHECKING
-from typing import TypeVar
-from typing import Union
-
-from .. import exc
-from .. import util
-from ..util import langhelpers
-from ..util._has_cy import HAS_CYEXTENSION
-from ..util.typing import Literal
-from ..util.typing import Protocol
-from ..util.typing import Self
-
-if TYPE_CHECKING:
- from .annotation import _AnnotationDict
- from .elements import ColumnElement
-
-if typing.TYPE_CHECKING or not HAS_CYEXTENSION:
- from ._py_util import prefix_anon_map as prefix_anon_map
- from ._py_util import cache_anon_map as anon_map
-else:
- from sqlalchemy.cyextension.util import ( # noqa: F401,E501
- prefix_anon_map as prefix_anon_map,
- )
- from sqlalchemy.cyextension.util import ( # noqa: F401,E501
- cache_anon_map as anon_map,
- )
-
-
-__all__ = [
- "iterate",
- "traverse_using",
- "traverse",
- "cloned_traverse",
- "replacement_traverse",
- "Visitable",
- "ExternalTraversal",
- "InternalTraversal",
- "anon_map",
-]
-
-
-class _CompilerDispatchType(Protocol):
- def __call__(_self, self: Visitable, visitor: Any, **kw: Any) -> Any: ...
-
-
-class Visitable:
- """Base class for visitable objects.
-
- :class:`.Visitable` is used to implement the SQL compiler dispatch
- functions. Other forms of traversal such as for cache key generation
- are implemented separately using the :class:`.HasTraverseInternals`
- interface.
-
- .. versionchanged:: 2.0 The :class:`.Visitable` class was named
- :class:`.Traversible` in the 1.4 series; the name is changed back
- to :class:`.Visitable` in 2.0 which is what it was prior to 1.4.
-
- Both names remain importable in both 1.4 and 2.0 versions.
-
- """
-
- __slots__ = ()
-
- __visit_name__: str
-
- _original_compiler_dispatch: _CompilerDispatchType
-
- if typing.TYPE_CHECKING:
-
- def _compiler_dispatch(self, visitor: Any, **kw: Any) -> str: ...
-
- def __init_subclass__(cls) -> None:
- if "__visit_name__" in cls.__dict__:
- cls._generate_compiler_dispatch()
- super().__init_subclass__()
-
- @classmethod
- def _generate_compiler_dispatch(cls) -> None:
- visit_name = cls.__visit_name__
-
- if "_compiler_dispatch" in cls.__dict__:
- # class has a fixed _compiler_dispatch() method.
- # copy it to "original" so that we can get it back if
- # sqlalchemy.ext.compiles overrides it.
- cls._original_compiler_dispatch = cls._compiler_dispatch
- return
-
- if not isinstance(visit_name, str):
- raise exc.InvalidRequestError(
- f"__visit_name__ on class {cls.__name__} must be a string "
- "at the class level"
- )
-
- name = "visit_%s" % visit_name
- getter = operator.attrgetter(name)
-
- def _compiler_dispatch(
- self: Visitable, visitor: Any, **kw: Any
- ) -> str:
- """Look for an attribute named "visit_<visit_name>" on the
- visitor, and call it with the same kw params.
-
- """
- try:
- meth = getter(visitor)
- except AttributeError as err:
- return visitor.visit_unsupported_compilation(self, err, **kw) # type: ignore # noqa: E501
- else:
- return meth(self, **kw) # type: ignore # noqa: E501
-
- cls._compiler_dispatch = ( # type: ignore
- cls._original_compiler_dispatch
- ) = _compiler_dispatch
-
- def __class_getitem__(cls, key: Any) -> Any:
- # allow generic classes in py3.9+
- return cls
-
-
-class InternalTraversal(Enum):
- r"""Defines visitor symbols used for internal traversal.
-
- The :class:`.InternalTraversal` class is used in two ways. One is that
- it can serve as the superclass for an object that implements the
- various visit methods of the class. The other is that the symbols
- themselves of :class:`.InternalTraversal` are used within
- the ``_traverse_internals`` collection. Such as, the :class:`.Case`
- object defines ``_traverse_internals`` as ::
-
- class Case(ColumnElement[_T]):
- _traverse_internals = [
- ("value", InternalTraversal.dp_clauseelement),
- ("whens", InternalTraversal.dp_clauseelement_tuples),
- ("else_", InternalTraversal.dp_clauseelement),
- ]
-
- Above, the :class:`.Case` class indicates its internal state as the
- attributes named ``value``, ``whens``, and ``else_``. They each
- link to an :class:`.InternalTraversal` method which indicates the type
- of datastructure to which each attribute refers.
-
- Using the ``_traverse_internals`` structure, objects of type
- :class:`.InternalTraversible` will have the following methods automatically
- implemented:
-
- * :meth:`.HasTraverseInternals.get_children`
-
- * :meth:`.HasTraverseInternals._copy_internals`
-
- * :meth:`.HasCacheKey._gen_cache_key`
-
- Subclasses can also implement these methods directly, particularly for the
- :meth:`.HasTraverseInternals._copy_internals` method, when special steps
- are needed.
-
- .. versionadded:: 1.4
-
- """
-
- dp_has_cache_key = "HC"
- """Visit a :class:`.HasCacheKey` object."""
-
- dp_has_cache_key_list = "HL"
- """Visit a list of :class:`.HasCacheKey` objects."""
-
- dp_clauseelement = "CE"
- """Visit a :class:`_expression.ClauseElement` object."""
-
- dp_fromclause_canonical_column_collection = "FC"
- """Visit a :class:`_expression.FromClause` object in the context of the
- ``columns`` attribute.
-
- The column collection is "canonical", meaning it is the originally
- defined location of the :class:`.ColumnClause` objects. Right now
- this means that the object being visited is a
- :class:`_expression.TableClause`
- or :class:`_schema.Table` object only.
-
- """
-
- dp_clauseelement_tuples = "CTS"
- """Visit a list of tuples which contain :class:`_expression.ClauseElement`
- objects.
-
- """
-
- dp_clauseelement_list = "CL"
- """Visit a list of :class:`_expression.ClauseElement` objects.
-
- """
-
- dp_clauseelement_tuple = "CT"
- """Visit a tuple of :class:`_expression.ClauseElement` objects.
-
- """
-
- dp_executable_options = "EO"
-
- dp_with_context_options = "WC"
-
- dp_fromclause_ordered_set = "CO"
- """Visit an ordered set of :class:`_expression.FromClause` objects. """
-
- dp_string = "S"
- """Visit a plain string value.
-
- Examples include table and column names, bound parameter keys, special
- keywords such as "UNION", "UNION ALL".
-
- The string value is considered to be significant for cache key
- generation.
-
- """
-
- dp_string_list = "SL"
- """Visit a list of strings."""
-
- dp_anon_name = "AN"
- """Visit a potentially "anonymized" string value.
-
- The string value is considered to be significant for cache key
- generation.
-
- """
-
- dp_boolean = "B"
- """Visit a boolean value.
-
- The boolean value is considered to be significant for cache key
- generation.
-
- """
-
- dp_operator = "O"
- """Visit an operator.
-
- The operator is a function from the :mod:`sqlalchemy.sql.operators`
- module.
-
- The operator value is considered to be significant for cache key
- generation.
-
- """
-
- dp_type = "T"
- """Visit a :class:`.TypeEngine` object
-
- The type object is considered to be significant for cache key
- generation.
-
- """
-
- dp_plain_dict = "PD"
- """Visit a dictionary with string keys.
-
- The keys of the dictionary should be strings, the values should
- be immutable and hashable. The dictionary is considered to be
- significant for cache key generation.
-
- """
-
- dp_dialect_options = "DO"
- """Visit a dialect options structure."""
-
- dp_string_clauseelement_dict = "CD"
- """Visit a dictionary of string keys to :class:`_expression.ClauseElement`
- objects.
-
- """
-
- dp_string_multi_dict = "MD"
- """Visit a dictionary of string keys to values which may either be
- plain immutable/hashable or :class:`.HasCacheKey` objects.
-
- """
-
- dp_annotations_key = "AK"
- """Visit the _annotations_cache_key element.
-
- This is a dictionary of additional information about a ClauseElement
- that modifies its role. It should be included when comparing or caching
- objects, however generating this key is relatively expensive. Visitors
- should check the "_annotations" dict for non-None first before creating
- this key.
-
- """
-
- dp_plain_obj = "PO"
- """Visit a plain python object.
-
- The value should be immutable and hashable, such as an integer.
- The value is considered to be significant for cache key generation.
-
- """
-
- dp_named_ddl_element = "DD"
- """Visit a simple named DDL element.
-
- The current object used by this method is the :class:`.Sequence`.
-
- The object is only considered to be important for cache key generation
- as far as its name, but not any other aspects of it.
-
- """
-
- dp_prefix_sequence = "PS"
- """Visit the sequence represented by :class:`_expression.HasPrefixes`
- or :class:`_expression.HasSuffixes`.
-
- """
-
- dp_table_hint_list = "TH"
- """Visit the ``_hints`` collection of a :class:`_expression.Select`
- object.
-
- """
-
- dp_setup_join_tuple = "SJ"
-
- dp_memoized_select_entities = "ME"
-
- dp_statement_hint_list = "SH"
- """Visit the ``_statement_hints`` collection of a
- :class:`_expression.Select`
- object.
-
- """
-
- dp_unknown_structure = "UK"
- """Visit an unknown structure.
-
- """
-
- dp_dml_ordered_values = "DML_OV"
- """Visit the values() ordered tuple list of an
- :class:`_expression.Update` object."""
-
- dp_dml_values = "DML_V"
- """Visit the values() dictionary of a :class:`.ValuesBase`
- (e.g. Insert or Update) object.
-
- """
-
- dp_dml_multi_values = "DML_MV"
- """Visit the values() multi-valued list of dictionaries of an
- :class:`_expression.Insert` object.
-
- """
-
- dp_propagate_attrs = "PA"
- """Visit the propagate attrs dict. This hardcodes to the particular
- elements we care about right now."""
-
- """Symbols that follow are additional symbols that are useful in
- caching applications.
-
- Traversals for :class:`_expression.ClauseElement` objects only need to use
- those symbols present in :class:`.InternalTraversal`. However, for
- additional caching use cases within the ORM, symbols dealing with the
- :class:`.HasCacheKey` class are added here.
-
- """
-
- dp_ignore = "IG"
- """Specify an object that should be ignored entirely.
-
- This currently applies function call argument caching where some
- arguments should not be considered to be part of a cache key.
-
- """
-
- dp_inspectable = "IS"
- """Visit an inspectable object where the return value is a
- :class:`.HasCacheKey` object."""
-
- dp_multi = "M"
- """Visit an object that may be a :class:`.HasCacheKey` or may be a
- plain hashable object."""
-
- dp_multi_list = "MT"
- """Visit a tuple containing elements that may be :class:`.HasCacheKey` or
- may be a plain hashable object."""
-
- dp_has_cache_key_tuples = "HT"
- """Visit a list of tuples which contain :class:`.HasCacheKey`
- objects.
-
- """
-
- dp_inspectable_list = "IL"
- """Visit a list of inspectable objects which upon inspection are
- HasCacheKey objects."""
-
-
-_TraverseInternalsType = List[Tuple[str, InternalTraversal]]
-"""a structure that defines how a HasTraverseInternals should be
-traversed.
-
-This structure consists of a list of (attributename, internaltraversal)
-tuples, where the "attributename" refers to the name of an attribute on an
-instance of the HasTraverseInternals object, and "internaltraversal" refers
-to an :class:`.InternalTraversal` enumeration symbol defining what kind
-of data this attribute stores, which indicates to the traverser how it should
-be handled.
-
-"""
-
-
-class HasTraverseInternals:
- """base for classes that have a "traverse internals" element,
- which defines all kinds of ways of traversing the elements of an object.
-
- Compared to :class:`.Visitable`, which relies upon an external visitor to
- define how the object is travered (i.e. the :class:`.SQLCompiler`), the
- :class:`.HasTraverseInternals` interface allows classes to define their own
- traversal, that is, what attributes are accessed and in what order.
-
- """
-
- __slots__ = ()
-
- _traverse_internals: _TraverseInternalsType
-
- _is_immutable: bool = False
-
- @util.preload_module("sqlalchemy.sql.traversals")
- def get_children(
- self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any
- ) -> Iterable[HasTraverseInternals]:
- r"""Return immediate child :class:`.visitors.HasTraverseInternals`
- elements of this :class:`.visitors.HasTraverseInternals`.
-
- This is used for visit traversal.
-
- \**kw may contain flags that change the collection that is
- returned, for example to return a subset of items in order to
- cut down on larger traversals, or to return child items from a
- different context (such as schema-level collections instead of
- clause-level).
-
- """
-
- traversals = util.preloaded.sql_traversals
-
- try:
- traverse_internals = self._traverse_internals
- except AttributeError:
- # user-defined classes may not have a _traverse_internals
- return []
-
- dispatch = traversals._get_children.run_generated_dispatch
- return itertools.chain.from_iterable(
- meth(obj, **kw)
- for attrname, obj, meth in dispatch(
- self, traverse_internals, "_generated_get_children_traversal"
- )
- if attrname not in omit_attrs and obj is not None
- )
-
-
-class _InternalTraversalDispatchType(Protocol):
- def __call__(s, self: object, visitor: HasTraversalDispatch) -> Any: ...
-
-
-class HasTraversalDispatch:
- r"""Define infrastructure for classes that perform internal traversals
-
- .. versionadded:: 2.0
-
- """
-
- __slots__ = ()
-
- _dispatch_lookup: ClassVar[Dict[Union[InternalTraversal, str], str]] = {}
-
- def dispatch(self, visit_symbol: InternalTraversal) -> Callable[..., Any]:
- """Given a method from :class:`.HasTraversalDispatch`, return the
- corresponding method on a subclass.
-
- """
- name = _dispatch_lookup[visit_symbol]
- return getattr(self, name, None) # type: ignore
-
- def run_generated_dispatch(
- self,
- target: object,
- internal_dispatch: _TraverseInternalsType,
- generate_dispatcher_name: str,
- ) -> Any:
- dispatcher: _InternalTraversalDispatchType
- try:
- dispatcher = target.__class__.__dict__[generate_dispatcher_name]
- except KeyError:
- # traversals.py -> _preconfigure_traversals()
- # may be used to run these ahead of time, but
- # is not enabled right now.
- # this block will generate any remaining dispatchers.
- dispatcher = self.generate_dispatch(
- target.__class__, internal_dispatch, generate_dispatcher_name
- )
- return dispatcher(target, self)
-
- def generate_dispatch(
- self,
- target_cls: Type[object],
- internal_dispatch: _TraverseInternalsType,
- generate_dispatcher_name: str,
- ) -> _InternalTraversalDispatchType:
- dispatcher = self._generate_dispatcher(
- internal_dispatch, generate_dispatcher_name
- )
- # assert isinstance(target_cls, type)
- setattr(target_cls, generate_dispatcher_name, dispatcher)
- return dispatcher
-
- def _generate_dispatcher(
- self, internal_dispatch: _TraverseInternalsType, method_name: str
- ) -> _InternalTraversalDispatchType:
- names = []
- for attrname, visit_sym in internal_dispatch:
- meth = self.dispatch(visit_sym)
- if meth is not None:
- visit_name = _dispatch_lookup[visit_sym]
- names.append((attrname, visit_name))
-
- code = (
- (" return [\n")
- + (
- ", \n".join(
- " (%r, self.%s, visitor.%s)"
- % (attrname, attrname, visit_name)
- for attrname, visit_name in names
- )
- )
- + ("\n ]\n")
- )
- meth_text = ("def %s(self, visitor):\n" % method_name) + code + "\n"
- return cast(
- _InternalTraversalDispatchType,
- langhelpers._exec_code_in_env(meth_text, {}, method_name),
- )
-
-
-ExtendedInternalTraversal = InternalTraversal
-
-
-def _generate_traversal_dispatch() -> None:
- lookup = _dispatch_lookup
-
- for sym in InternalTraversal:
- key = sym.name
- if key.startswith("dp_"):
- visit_key = key.replace("dp_", "visit_")
- sym_name = sym.value
- assert sym_name not in lookup, sym_name
- lookup[sym] = lookup[sym_name] = visit_key
-
-
-_dispatch_lookup = HasTraversalDispatch._dispatch_lookup
-_generate_traversal_dispatch()
-
-
-class ExternallyTraversible(HasTraverseInternals, Visitable):
- __slots__ = ()
-
- _annotations: Mapping[Any, Any] = util.EMPTY_DICT
-
- if typing.TYPE_CHECKING:
-
- def _annotate(self, values: _AnnotationDict) -> Self: ...
-
- def get_children(
- self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any
- ) -> Iterable[ExternallyTraversible]: ...
-
- def _clone(self, **kw: Any) -> Self:
- """clone this element"""
- raise NotImplementedError()
-
- def _copy_internals(
- self, *, omit_attrs: Tuple[str, ...] = (), **kw: Any
- ) -> None:
- """Reassign internal elements to be clones of themselves.
-
- Called during a copy-and-traverse operation on newly
- shallow-copied elements to create a deep copy.
-
- The given clone function should be used, which may be applying
- additional transformations to the element (i.e. replacement
- traversal, cloned traversal, annotations).
-
- """
- raise NotImplementedError()
-
-
-_ET = TypeVar("_ET", bound=ExternallyTraversible)
-
-_CE = TypeVar("_CE", bound="ColumnElement[Any]")
-
-_TraverseCallableType = Callable[[_ET], None]
-
-
-class _CloneCallableType(Protocol):
- def __call__(self, element: _ET, **kw: Any) -> _ET: ...
-
-
-class _TraverseTransformCallableType(Protocol[_ET]):
- def __call__(self, element: _ET, **kw: Any) -> Optional[_ET]: ...
-
-
-_ExtT = TypeVar("_ExtT", bound="ExternalTraversal")
-
-
-class ExternalTraversal(util.MemoizedSlots):
- """Base class for visitor objects which can traverse externally using
- the :func:`.visitors.traverse` function.
-
- Direct usage of the :func:`.visitors.traverse` function is usually
- preferred.
-
- """
-
- __slots__ = ("_visitor_dict", "_next")
-
- __traverse_options__: Dict[str, Any] = {}
- _next: Optional[ExternalTraversal]
-
- def traverse_single(self, obj: Visitable, **kw: Any) -> Any:
- for v in self.visitor_iterator:
- meth = getattr(v, "visit_%s" % obj.__visit_name__, None)
- if meth:
- return meth(obj, **kw)
-
- def iterate(
- self, obj: Optional[ExternallyTraversible]
- ) -> Iterator[ExternallyTraversible]:
- """Traverse the given expression structure, returning an iterator
- of all elements.
-
- """
- return iterate(obj, self.__traverse_options__)
-
- @overload
- def traverse(self, obj: Literal[None]) -> None: ...
-
- @overload
- def traverse(
- self, obj: ExternallyTraversible
- ) -> ExternallyTraversible: ...
-
- def traverse(
- self, obj: Optional[ExternallyTraversible]
- ) -> Optional[ExternallyTraversible]:
- """Traverse and visit the given expression structure."""
-
- return traverse(obj, self.__traverse_options__, self._visitor_dict)
-
- def _memoized_attr__visitor_dict(
- self,
- ) -> Dict[str, _TraverseCallableType[Any]]:
- visitors = {}
-
- for name in dir(self):
- if name.startswith("visit_"):
- visitors[name[6:]] = getattr(self, name)
- return visitors
-
- @property
- def visitor_iterator(self) -> Iterator[ExternalTraversal]:
- """Iterate through this visitor and each 'chained' visitor."""
-
- v: Optional[ExternalTraversal] = self
- while v:
- yield v
- v = getattr(v, "_next", None)
-
- def chain(self: _ExtT, visitor: ExternalTraversal) -> _ExtT:
- """'Chain' an additional ExternalTraversal onto this ExternalTraversal
-
- The chained visitor will receive all visit events after this one.
-
- """
- tail = list(self.visitor_iterator)[-1]
- tail._next = visitor
- return self
-
-
-class CloningExternalTraversal(ExternalTraversal):
- """Base class for visitor objects which can traverse using
- the :func:`.visitors.cloned_traverse` function.
-
- Direct usage of the :func:`.visitors.cloned_traverse` function is usually
- preferred.
-
-
- """
-
- __slots__ = ()
-
- def copy_and_process(
- self, list_: List[ExternallyTraversible]
- ) -> List[ExternallyTraversible]:
- """Apply cloned traversal to the given list of elements, and return
- the new list.
-
- """
- return [self.traverse(x) for x in list_]
-
- @overload
- def traverse(self, obj: Literal[None]) -> None: ...
-
- @overload
- def traverse(
- self, obj: ExternallyTraversible
- ) -> ExternallyTraversible: ...
-
- def traverse(
- self, obj: Optional[ExternallyTraversible]
- ) -> Optional[ExternallyTraversible]:
- """Traverse and visit the given expression structure."""
-
- return cloned_traverse(
- obj, self.__traverse_options__, self._visitor_dict
- )
-
-
-class ReplacingExternalTraversal(CloningExternalTraversal):
- """Base class for visitor objects which can traverse using
- the :func:`.visitors.replacement_traverse` function.
-
- Direct usage of the :func:`.visitors.replacement_traverse` function is
- usually preferred.
-
- """
-
- __slots__ = ()
-
- def replace(
- self, elem: ExternallyTraversible
- ) -> Optional[ExternallyTraversible]:
- """Receive pre-copied elements during a cloning traversal.
-
- If the method returns a new element, the element is used
- instead of creating a simple copy of the element. Traversal
- will halt on the newly returned element if it is re-encountered.
- """
- return None
-
- @overload
- def traverse(self, obj: Literal[None]) -> None: ...
-
- @overload
- def traverse(
- self, obj: ExternallyTraversible
- ) -> ExternallyTraversible: ...
-
- def traverse(
- self, obj: Optional[ExternallyTraversible]
- ) -> Optional[ExternallyTraversible]:
- """Traverse and visit the given expression structure."""
-
- def replace(
- element: ExternallyTraversible,
- **kw: Any,
- ) -> Optional[ExternallyTraversible]:
- for v in self.visitor_iterator:
- e = cast(ReplacingExternalTraversal, v).replace(element)
- if e is not None:
- return e
-
- return None
-
- return replacement_traverse(obj, self.__traverse_options__, replace)
-
-
-# backwards compatibility
-Traversible = Visitable
-
-ClauseVisitor = ExternalTraversal
-CloningVisitor = CloningExternalTraversal
-ReplacingCloningVisitor = ReplacingExternalTraversal
-
-
-def iterate(
- obj: Optional[ExternallyTraversible],
- opts: Mapping[str, Any] = util.EMPTY_DICT,
-) -> Iterator[ExternallyTraversible]:
- r"""Traverse the given expression structure, returning an iterator.
-
- Traversal is configured to be breadth-first.
-
- The central API feature used by the :func:`.visitors.iterate`
- function is the
- :meth:`_expression.ClauseElement.get_children` method of
- :class:`_expression.ClauseElement` objects. This method should return all
- the :class:`_expression.ClauseElement` objects which are associated with a
- particular :class:`_expression.ClauseElement` object. For example, a
- :class:`.Case` structure will refer to a series of
- :class:`_expression.ColumnElement` objects within its "whens" and "else\_"
- member variables.
-
- :param obj: :class:`_expression.ClauseElement` structure to be traversed
-
- :param opts: dictionary of iteration options. This dictionary is usually
- empty in modern usage.
-
- """
- if obj is None:
- return
-
- yield obj
- children = obj.get_children(**opts)
-
- if not children:
- return
-
- stack = deque([children])
- while stack:
- t_iterator = stack.popleft()
- for t in t_iterator:
- yield t
- stack.append(t.get_children(**opts))
-
-
-@overload
-def traverse_using(
- iterator: Iterable[ExternallyTraversible],
- obj: Literal[None],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> None: ...
-
-
-@overload
-def traverse_using(
- iterator: Iterable[ExternallyTraversible],
- obj: ExternallyTraversible,
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> ExternallyTraversible: ...
-
-
-def traverse_using(
- iterator: Iterable[ExternallyTraversible],
- obj: Optional[ExternallyTraversible],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> Optional[ExternallyTraversible]:
- """Visit the given expression structure using the given iterator of
- objects.
-
- :func:`.visitors.traverse_using` is usually called internally as the result
- of the :func:`.visitors.traverse` function.
-
- :param iterator: an iterable or sequence which will yield
- :class:`_expression.ClauseElement`
- structures; the iterator is assumed to be the
- product of the :func:`.visitors.iterate` function.
-
- :param obj: the :class:`_expression.ClauseElement`
- that was used as the target of the
- :func:`.iterate` function.
-
- :param visitors: dictionary of visit functions. See :func:`.traverse`
- for details on this dictionary.
-
- .. seealso::
-
- :func:`.traverse`
-
-
- """
- for target in iterator:
- meth = visitors.get(target.__visit_name__, None)
- if meth:
- meth(target)
- return obj
-
-
-@overload
-def traverse(
- obj: Literal[None],
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> None: ...
-
-
-@overload
-def traverse(
- obj: ExternallyTraversible,
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> ExternallyTraversible: ...
-
-
-def traverse(
- obj: Optional[ExternallyTraversible],
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> Optional[ExternallyTraversible]:
- """Traverse and visit the given expression structure using the default
- iterator.
-
- e.g.::
-
- from sqlalchemy.sql import visitors
-
- stmt = select(some_table).where(some_table.c.foo == 'bar')
-
- def visit_bindparam(bind_param):
- print("found bound value: %s" % bind_param.value)
-
- visitors.traverse(stmt, {}, {"bindparam": visit_bindparam})
-
- The iteration of objects uses the :func:`.visitors.iterate` function,
- which does a breadth-first traversal using a stack.
-
- :param obj: :class:`_expression.ClauseElement` structure to be traversed
-
- :param opts: dictionary of iteration options. This dictionary is usually
- empty in modern usage.
-
- :param visitors: dictionary of visit functions. The dictionary should
- have strings as keys, each of which would correspond to the
- ``__visit_name__`` of a particular kind of SQL expression object, and
- callable functions as values, each of which represents a visitor function
- for that kind of object.
-
- """
- return traverse_using(iterate(obj, opts), obj, visitors)
-
-
-@overload
-def cloned_traverse(
- obj: Literal[None],
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> None: ...
-
-
-# a bit of controversy here, as the clone of the lead element
-# *could* in theory replace with an entirely different kind of element.
-# however this is really not how cloned_traverse is ever used internally
-# at least.
-@overload
-def cloned_traverse(
- obj: _ET,
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> _ET: ...
-
-
-def cloned_traverse(
- obj: Optional[ExternallyTraversible],
- opts: Mapping[str, Any],
- visitors: Mapping[str, _TraverseCallableType[Any]],
-) -> Optional[ExternallyTraversible]:
- """Clone the given expression structure, allowing modifications by
- visitors for mutable objects.
-
- Traversal usage is the same as that of :func:`.visitors.traverse`.
- The visitor functions present in the ``visitors`` dictionary may also
- modify the internals of the given structure as the traversal proceeds.
-
- The :func:`.cloned_traverse` function does **not** provide objects that are
- part of the :class:`.Immutable` interface to the visit methods (this
- primarily includes :class:`.ColumnClause`, :class:`.Column`,
- :class:`.TableClause` and :class:`.Table` objects). As this traversal is
- only intended to allow in-place mutation of objects, :class:`.Immutable`
- objects are skipped. The :meth:`.Immutable._clone` method is still called
- on each object to allow for objects to replace themselves with a different
- object based on a clone of their sub-internals (e.g. a
- :class:`.ColumnClause` that clones its subquery to return a new
- :class:`.ColumnClause`).
-
- .. versionchanged:: 2.0 The :func:`.cloned_traverse` function omits
- objects that are part of the :class:`.Immutable` interface.
-
- The central API feature used by the :func:`.visitors.cloned_traverse`
- and :func:`.visitors.replacement_traverse` functions, in addition to the
- :meth:`_expression.ClauseElement.get_children`
- function that is used to achieve
- the iteration, is the :meth:`_expression.ClauseElement._copy_internals`
- method.
- For a :class:`_expression.ClauseElement`
- structure to support cloning and replacement
- traversals correctly, it needs to be able to pass a cloning function into
- its internal members in order to make copies of them.
-
- .. seealso::
-
- :func:`.visitors.traverse`
-
- :func:`.visitors.replacement_traverse`
-
- """
-
- cloned: Dict[int, ExternallyTraversible] = {}
- stop_on = set(opts.get("stop_on", []))
-
- def deferred_copy_internals(
- obj: ExternallyTraversible,
- ) -> ExternallyTraversible:
- return cloned_traverse(obj, opts, visitors)
-
- def clone(elem: ExternallyTraversible, **kw: Any) -> ExternallyTraversible:
- if elem in stop_on:
- return elem
- else:
- if id(elem) not in cloned:
- if "replace" in kw:
- newelem = cast(
- Optional[ExternallyTraversible], kw["replace"](elem)
- )
- if newelem is not None:
- cloned[id(elem)] = newelem
- return newelem
-
- # the _clone method for immutable normally returns "self".
- # however, the method is still allowed to return a
- # different object altogether; ColumnClause._clone() will
- # based on options clone the subquery to which it is associated
- # and return the new corresponding column.
- cloned[id(elem)] = newelem = elem._clone(clone=clone, **kw)
- newelem._copy_internals(clone=clone, **kw)
-
- # however, visit methods which are tasked with in-place
- # mutation of the object should not get access to the immutable
- # object.
- if not elem._is_immutable:
- meth = visitors.get(newelem.__visit_name__, None)
- if meth:
- meth(newelem)
- return cloned[id(elem)]
-
- if obj is not None:
- obj = clone(
- obj, deferred_copy_internals=deferred_copy_internals, **opts
- )
- clone = None # type: ignore[assignment] # remove gc cycles
- return obj
-
-
-@overload
-def replacement_traverse(
- obj: Literal[None],
- opts: Mapping[str, Any],
- replace: _TraverseTransformCallableType[Any],
-) -> None: ...
-
-
-@overload
-def replacement_traverse(
- obj: _CE,
- opts: Mapping[str, Any],
- replace: _TraverseTransformCallableType[Any],
-) -> _CE: ...
-
-
-@overload
-def replacement_traverse(
- obj: ExternallyTraversible,
- opts: Mapping[str, Any],
- replace: _TraverseTransformCallableType[Any],
-) -> ExternallyTraversible: ...
-
-
-def replacement_traverse(
- obj: Optional[ExternallyTraversible],
- opts: Mapping[str, Any],
- replace: _TraverseTransformCallableType[Any],
-) -> Optional[ExternallyTraversible]:
- """Clone the given expression structure, allowing element
- replacement by a given replacement function.
-
- This function is very similar to the :func:`.visitors.cloned_traverse`
- function, except instead of being passed a dictionary of visitors, all
- elements are unconditionally passed into the given replace function.
- The replace function then has the option to return an entirely new object
- which will replace the one given. If it returns ``None``, then the object
- is kept in place.
-
- The difference in usage between :func:`.visitors.cloned_traverse` and
- :func:`.visitors.replacement_traverse` is that in the former case, an
- already-cloned object is passed to the visitor function, and the visitor
- function can then manipulate the internal state of the object.
- In the case of the latter, the visitor function should only return an
- entirely different object, or do nothing.
-
- The use case for :func:`.visitors.replacement_traverse` is that of
- replacing a FROM clause inside of a SQL structure with a different one,
- as is a common use case within the ORM.
-
- """
-
- cloned = {}
- stop_on = {id(x) for x in opts.get("stop_on", [])}
-
- def deferred_copy_internals(
- obj: ExternallyTraversible,
- ) -> ExternallyTraversible:
- return replacement_traverse(obj, opts, replace)
-
- def clone(elem: ExternallyTraversible, **kw: Any) -> ExternallyTraversible:
- if (
- id(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(id(newelem))
- return newelem # type: ignore
- else:
- # base "already seen" on id(), not hash, so that we don't
- # replace an Annotated element with its non-annotated one, and
- # vice versa
- id_elem = id(elem)
- if id_elem not in cloned:
- if "replace" in kw:
- newelem = kw["replace"](elem)
- if newelem is not None:
- cloned[id_elem] = newelem
- return newelem # type: ignore
-
- cloned[id_elem] = newelem = elem._clone(**kw)
- newelem._copy_internals(clone=clone, **kw)
- return cloned[id_elem] # type: ignore
-
- if obj is not None:
- obj = clone(
- obj, deferred_copy_internals=deferred_copy_internals, **opts
- )
- clone = None # type: ignore[assignment] # remove gc cycles
- return obj