Загрузить файлы в «venv/Lib/site-packages/sqlalchemy/sql»
This commit is contained in:
@@ -0,0 +1,763 @@
|
|||||||
|
# sql/_selectable_constructors.py
|
||||||
|
# Copyright (C) 2005-2026 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
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from . import coercions
|
||||||
|
from . import roles
|
||||||
|
from ._typing import _ColumnsClauseArgument
|
||||||
|
from ._typing import _no_kw
|
||||||
|
from .elements import ColumnClause
|
||||||
|
from .selectable import Alias
|
||||||
|
from .selectable import CompoundSelect
|
||||||
|
from .selectable import Exists
|
||||||
|
from .selectable import FromClause
|
||||||
|
from .selectable import Join
|
||||||
|
from .selectable import Lateral
|
||||||
|
from .selectable import LateralFromClause
|
||||||
|
from .selectable import NamedFromClause
|
||||||
|
from .selectable import Select
|
||||||
|
from .selectable import TableClause
|
||||||
|
from .selectable import TableSample
|
||||||
|
from .selectable import Values
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ._typing import _FromClauseArgument
|
||||||
|
from ._typing import _OnClauseArgument
|
||||||
|
from ._typing import _OnlyColumnArgument
|
||||||
|
from ._typing import _SelectStatementForCompoundArgument
|
||||||
|
from ._typing import _T0
|
||||||
|
from ._typing import _T1
|
||||||
|
from ._typing import _T2
|
||||||
|
from ._typing import _T3
|
||||||
|
from ._typing import _T4
|
||||||
|
from ._typing import _T5
|
||||||
|
from ._typing import _T6
|
||||||
|
from ._typing import _T7
|
||||||
|
from ._typing import _T8
|
||||||
|
from ._typing import _T9
|
||||||
|
from ._typing import _TP
|
||||||
|
from ._typing import _TypedColumnClauseArgument as _TCCA
|
||||||
|
from .functions import Function
|
||||||
|
from .selectable import CTE
|
||||||
|
from .selectable import HasCTE
|
||||||
|
from .selectable import ScalarSelect
|
||||||
|
from .selectable import SelectBase
|
||||||
|
|
||||||
|
|
||||||
|
def alias(
|
||||||
|
selectable: FromClause, name: Optional[str] = None, flat: bool = False
|
||||||
|
) -> NamedFromClause:
|
||||||
|
"""Return a named alias of the given :class:`.FromClause`.
|
||||||
|
|
||||||
|
For :class:`.Table` and :class:`.Join` objects, the return type is the
|
||||||
|
:class:`_expression.Alias` object. Other kinds of :class:`.NamedFromClause`
|
||||||
|
objects may be returned for other kinds of :class:`.FromClause` objects.
|
||||||
|
|
||||||
|
The named alias represents any :class:`_expression.FromClause` with an
|
||||||
|
alternate name assigned within SQL, typically using the ``AS`` clause when
|
||||||
|
generated, e.g. ``SELECT * FROM table AS aliasname``.
|
||||||
|
|
||||||
|
Equivalent functionality is available via the
|
||||||
|
:meth:`_expression.FromClause.alias`
|
||||||
|
method available on all :class:`_expression.FromClause` objects.
|
||||||
|
|
||||||
|
:param selectable: any :class:`_expression.FromClause` subclass,
|
||||||
|
such as a table, select statement, etc.
|
||||||
|
|
||||||
|
:param name: string name to be assigned as the alias.
|
||||||
|
If ``None``, a name will be deterministically generated at compile
|
||||||
|
time. Deterministic means the name is guaranteed to be unique against
|
||||||
|
other constructs used in the same statement, and will also be the same
|
||||||
|
name for each successive compilation of the same statement object.
|
||||||
|
|
||||||
|
:param flat: Will be passed through to if the given selectable
|
||||||
|
is an instance of :class:`_expression.Join` - see
|
||||||
|
:meth:`_expression.Join.alias` for details.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return Alias._factory(selectable, name=name, flat=flat)
|
||||||
|
|
||||||
|
|
||||||
|
def cte(
|
||||||
|
selectable: HasCTE, name: Optional[str] = None, recursive: bool = False
|
||||||
|
) -> CTE:
|
||||||
|
r"""Return a new :class:`_expression.CTE`,
|
||||||
|
or Common Table Expression instance.
|
||||||
|
|
||||||
|
Please see :meth:`_expression.HasCTE.cte` for detail on CTE usage.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return coercions.expect(roles.HasCTERole, selectable).cte(
|
||||||
|
name=name, recursive=recursive
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: mypy requires the _TypedSelectable overloads in all compound select
|
||||||
|
# constructors since _SelectStatementForCompoundArgument includes
|
||||||
|
# untyped args that make it return CompoundSelect[Unpack[tuple[Never, ...]]]
|
||||||
|
# pyright does not have this issue
|
||||||
|
_TypedSelectable = Union["Select[_TP]", "CompoundSelect[_TP]"]
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def except_(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def except_(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def except_(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return an ``EXCEPT`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_except(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def except_all(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def except_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def except_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return an ``EXCEPT ALL`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_except_all(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
def exists(
|
||||||
|
__argument: Optional[
|
||||||
|
Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]]
|
||||||
|
] = None,
|
||||||
|
) -> Exists:
|
||||||
|
"""Construct a new :class:`_expression.Exists` construct.
|
||||||
|
|
||||||
|
The :func:`_sql.exists` can be invoked by itself to produce an
|
||||||
|
:class:`_sql.Exists` construct, which will accept simple WHERE
|
||||||
|
criteria::
|
||||||
|
|
||||||
|
exists_criteria = exists().where(table1.c.col1 == table2.c.col2)
|
||||||
|
|
||||||
|
However, for greater flexibility in constructing the SELECT, an
|
||||||
|
existing :class:`_sql.Select` construct may be converted to an
|
||||||
|
:class:`_sql.Exists`, most conveniently by making use of the
|
||||||
|
:meth:`_sql.SelectBase.exists` method::
|
||||||
|
|
||||||
|
exists_criteria = (
|
||||||
|
select(table2.c.col2).where(table1.c.col1 == table2.c.col2).exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
The EXISTS criteria is then used inside of an enclosing SELECT::
|
||||||
|
|
||||||
|
stmt = select(table1.c.col1).where(exists_criteria)
|
||||||
|
|
||||||
|
The above statement will then be of the form:
|
||||||
|
|
||||||
|
.. sourcecode:: sql
|
||||||
|
|
||||||
|
SELECT col1 FROM table1 WHERE EXISTS
|
||||||
|
(SELECT table2.col2 FROM table2 WHERE table2.col2 = table1.col1)
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
|
||||||
|
|
||||||
|
:meth:`_sql.SelectBase.exists` - method to transform a ``SELECT`` to an
|
||||||
|
``EXISTS`` clause.
|
||||||
|
|
||||||
|
""" # noqa: E501
|
||||||
|
|
||||||
|
return Exists(__argument)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def intersect(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def intersect(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def intersect(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return an ``INTERSECT`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_intersect(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def intersect_all(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def intersect_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def intersect_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return an ``INTERSECT ALL`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_intersect_all(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
def join(
|
||||||
|
left: _FromClauseArgument,
|
||||||
|
right: _FromClauseArgument,
|
||||||
|
onclause: Optional[_OnClauseArgument] = None,
|
||||||
|
isouter: bool = False,
|
||||||
|
full: bool = False,
|
||||||
|
) -> Join:
|
||||||
|
"""Produce a :class:`_expression.Join` object, given two
|
||||||
|
:class:`_expression.FromClause`
|
||||||
|
expressions.
|
||||||
|
|
||||||
|
E.g.::
|
||||||
|
|
||||||
|
j = join(
|
||||||
|
user_table, address_table, user_table.c.id == address_table.c.user_id
|
||||||
|
)
|
||||||
|
stmt = select(user_table).select_from(j)
|
||||||
|
|
||||||
|
would emit SQL along the lines of:
|
||||||
|
|
||||||
|
.. sourcecode:: sql
|
||||||
|
|
||||||
|
SELECT user.id, user.name FROM user
|
||||||
|
JOIN address ON user.id = address.user_id
|
||||||
|
|
||||||
|
Similar functionality is available given any
|
||||||
|
:class:`_expression.FromClause` object (e.g. such as a
|
||||||
|
:class:`_schema.Table`) using
|
||||||
|
the :meth:`_expression.FromClause.join` method.
|
||||||
|
|
||||||
|
:param left: The left side of the join.
|
||||||
|
|
||||||
|
:param right: the right side of the join; this is any
|
||||||
|
:class:`_expression.FromClause` object such as a
|
||||||
|
:class:`_schema.Table` object, and
|
||||||
|
may also be a selectable-compatible object such as an ORM-mapped
|
||||||
|
class.
|
||||||
|
|
||||||
|
:param onclause: a SQL expression representing the ON clause of the
|
||||||
|
join. If left at ``None``, :meth:`_expression.FromClause.join`
|
||||||
|
will attempt to
|
||||||
|
join the two tables based on a foreign key relationship.
|
||||||
|
|
||||||
|
:param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN.
|
||||||
|
|
||||||
|
:param full: if True, render a FULL OUTER JOIN, instead of JOIN.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:meth:`_expression.FromClause.join` - method form,
|
||||||
|
based on a given left side.
|
||||||
|
|
||||||
|
:class:`_expression.Join` - the type of object produced.
|
||||||
|
|
||||||
|
""" # noqa: E501
|
||||||
|
|
||||||
|
return Join(left, right, onclause, isouter, full)
|
||||||
|
|
||||||
|
|
||||||
|
def lateral(
|
||||||
|
selectable: Union[SelectBase, _FromClauseArgument],
|
||||||
|
name: Optional[str] = None,
|
||||||
|
) -> LateralFromClause:
|
||||||
|
"""Return a :class:`_expression.Lateral` object.
|
||||||
|
|
||||||
|
:class:`_expression.Lateral` is an :class:`_expression.Alias`
|
||||||
|
subclass that represents
|
||||||
|
a subquery with the LATERAL keyword applied to it.
|
||||||
|
|
||||||
|
The special behavior of a LATERAL subquery is that it appears in the
|
||||||
|
FROM clause of an enclosing SELECT, but may correlate to other
|
||||||
|
FROM clauses of that SELECT. It is a special case of subquery
|
||||||
|
only supported by a small number of backends, currently more recent
|
||||||
|
PostgreSQL versions.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:ref:`tutorial_lateral_correlation` - overview of usage.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return Lateral._factory(selectable, name=name)
|
||||||
|
|
||||||
|
|
||||||
|
def outerjoin(
|
||||||
|
left: _FromClauseArgument,
|
||||||
|
right: _FromClauseArgument,
|
||||||
|
onclause: Optional[_OnClauseArgument] = None,
|
||||||
|
full: bool = False,
|
||||||
|
) -> Join:
|
||||||
|
"""Return an ``OUTER JOIN`` clause element.
|
||||||
|
|
||||||
|
The returned object is an instance of :class:`_expression.Join`.
|
||||||
|
|
||||||
|
Similar functionality is also available via the
|
||||||
|
:meth:`_expression.FromClause.outerjoin` method on any
|
||||||
|
:class:`_expression.FromClause`.
|
||||||
|
|
||||||
|
:param left: The left side of the join.
|
||||||
|
|
||||||
|
:param right: The right side of the join.
|
||||||
|
|
||||||
|
:param onclause: Optional criterion for the ``ON`` clause, is
|
||||||
|
derived from foreign key relationships established between
|
||||||
|
left and right otherwise.
|
||||||
|
|
||||||
|
To chain joins together, use the :meth:`_expression.FromClause.join`
|
||||||
|
or
|
||||||
|
:meth:`_expression.FromClause.outerjoin` methods on the resulting
|
||||||
|
:class:`_expression.Join` object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return Join(left, right, onclause, isouter=True, full=full)
|
||||||
|
|
||||||
|
|
||||||
|
# START OVERLOADED FUNCTIONS select Select 1-10
|
||||||
|
|
||||||
|
# code within this block is **programmatically,
|
||||||
|
# statically generated** by tools/generate_tuple_map_overloads.py
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(__ent0: _TCCA[_T0]) -> Select[Tuple[_T0]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
|
||||||
|
) -> Select[Tuple[_T0, _T1]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
__ent5: _TCCA[_T5],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
__ent5: _TCCA[_T5],
|
||||||
|
__ent6: _TCCA[_T6],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
__ent5: _TCCA[_T5],
|
||||||
|
__ent6: _TCCA[_T6],
|
||||||
|
__ent7: _TCCA[_T7],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
__ent5: _TCCA[_T5],
|
||||||
|
__ent6: _TCCA[_T6],
|
||||||
|
__ent7: _TCCA[_T7],
|
||||||
|
__ent8: _TCCA[_T8],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
__ent0: _TCCA[_T0],
|
||||||
|
__ent1: _TCCA[_T1],
|
||||||
|
__ent2: _TCCA[_T2],
|
||||||
|
__ent3: _TCCA[_T3],
|
||||||
|
__ent4: _TCCA[_T4],
|
||||||
|
__ent5: _TCCA[_T5],
|
||||||
|
__ent6: _TCCA[_T6],
|
||||||
|
__ent7: _TCCA[_T7],
|
||||||
|
__ent8: _TCCA[_T8],
|
||||||
|
__ent9: _TCCA[_T9],
|
||||||
|
) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
# END OVERLOADED FUNCTIONS select
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def select(
|
||||||
|
*entities: _ColumnsClauseArgument[Any], **__kw: Any
|
||||||
|
) -> Select[Any]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def select(*entities: _ColumnsClauseArgument[Any], **__kw: Any) -> Select[Any]:
|
||||||
|
r"""Construct a new :class:`_expression.Select`.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionadded:: 1.4 - The :func:`_sql.select` function now accepts
|
||||||
|
column arguments positionally. The top-level :func:`_sql.select`
|
||||||
|
function will automatically use the 1.x or 2.x style API based on
|
||||||
|
the incoming arguments; using :func:`_sql.select` from the
|
||||||
|
``sqlalchemy.future`` module will enforce that only the 2.x style
|
||||||
|
constructor is used.
|
||||||
|
|
||||||
|
Similar functionality is also available via the
|
||||||
|
:meth:`_expression.FromClause.select` method on any
|
||||||
|
:class:`_expression.FromClause`.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:ref:`tutorial_selecting_data` - in the :ref:`unified_tutorial`
|
||||||
|
|
||||||
|
:param \*entities:
|
||||||
|
Entities to SELECT from. For Core usage, this is typically a series
|
||||||
|
of :class:`_expression.ColumnElement` and / or
|
||||||
|
:class:`_expression.FromClause`
|
||||||
|
objects which will form the columns clause of the resulting
|
||||||
|
statement. For those objects that are instances of
|
||||||
|
:class:`_expression.FromClause` (typically :class:`_schema.Table`
|
||||||
|
or :class:`_expression.Alias`
|
||||||
|
objects), the :attr:`_expression.FromClause.c`
|
||||||
|
collection is extracted
|
||||||
|
to form a collection of :class:`_expression.ColumnElement` objects.
|
||||||
|
|
||||||
|
This parameter will also accept :class:`_expression.TextClause`
|
||||||
|
constructs as
|
||||||
|
given, as well as ORM-mapped classes.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# the keyword args are a necessary element in order for the typing
|
||||||
|
# to work out w/ the varargs vs. having named "keyword" arguments that
|
||||||
|
# aren't always present.
|
||||||
|
if __kw:
|
||||||
|
raise _no_kw()
|
||||||
|
return Select(*entities)
|
||||||
|
|
||||||
|
|
||||||
|
def table(name: str, *columns: ColumnClause[Any], **kw: Any) -> TableClause:
|
||||||
|
"""Produce a new :class:`_expression.TableClause`.
|
||||||
|
|
||||||
|
The object returned is an instance of
|
||||||
|
:class:`_expression.TableClause`, which
|
||||||
|
represents the "syntactical" portion of the schema-level
|
||||||
|
:class:`_schema.Table` object.
|
||||||
|
It may be used to construct lightweight table constructs.
|
||||||
|
|
||||||
|
:param name: Name of the table.
|
||||||
|
|
||||||
|
:param columns: A collection of :func:`_expression.column` constructs.
|
||||||
|
|
||||||
|
:param schema: The schema name for this table.
|
||||||
|
|
||||||
|
.. versionadded:: 1.3.18 :func:`_expression.table` can now
|
||||||
|
accept a ``schema`` argument.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return TableClause(name, *columns, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
def tablesample(
|
||||||
|
selectable: _FromClauseArgument,
|
||||||
|
sampling: Union[float, Function[Any]],
|
||||||
|
name: Optional[str] = None,
|
||||||
|
seed: Optional[roles.ExpressionElementRole[Any]] = None,
|
||||||
|
) -> TableSample:
|
||||||
|
"""Return a :class:`_expression.TableSample` object.
|
||||||
|
|
||||||
|
:class:`_expression.TableSample` is an :class:`_expression.Alias`
|
||||||
|
subclass that represents
|
||||||
|
a table with the TABLESAMPLE clause applied to it.
|
||||||
|
:func:`_expression.tablesample`
|
||||||
|
is also available from the :class:`_expression.FromClause`
|
||||||
|
class via the
|
||||||
|
:meth:`_expression.FromClause.tablesample` method.
|
||||||
|
|
||||||
|
The TABLESAMPLE clause allows selecting a randomly selected approximate
|
||||||
|
percentage of rows from a table. It supports multiple sampling methods,
|
||||||
|
most commonly BERNOULLI and SYSTEM.
|
||||||
|
|
||||||
|
e.g.::
|
||||||
|
|
||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
selectable = people.tablesample(
|
||||||
|
func.bernoulli(1), name="alias", seed=func.random()
|
||||||
|
)
|
||||||
|
stmt = select(selectable.c.people_id)
|
||||||
|
|
||||||
|
Assuming ``people`` with a column ``people_id``, the above
|
||||||
|
statement would render as:
|
||||||
|
|
||||||
|
.. sourcecode:: sql
|
||||||
|
|
||||||
|
SELECT alias.people_id FROM
|
||||||
|
people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
|
||||||
|
REPEATABLE (random())
|
||||||
|
|
||||||
|
:param sampling: a ``float`` percentage between 0 and 100 or
|
||||||
|
:class:`_functions.Function`.
|
||||||
|
|
||||||
|
:param name: optional alias name
|
||||||
|
|
||||||
|
:param seed: any real-valued SQL expression. When specified, the
|
||||||
|
REPEATABLE sub-clause is also rendered.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return TableSample._factory(selectable, sampling, name=name, seed=seed)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def union(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def union(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def union(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return a ``UNION`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
A similar :func:`union()` method is available on all
|
||||||
|
:class:`_expression.FromClause` subclasses.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
:param \**kwargs:
|
||||||
|
available keyword arguments are the same as those of
|
||||||
|
:func:`select`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_union(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def union_all(
|
||||||
|
*selects: _TypedSelectable[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def union_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def union_all(
|
||||||
|
*selects: _SelectStatementForCompoundArgument[_TP],
|
||||||
|
) -> CompoundSelect[_TP]:
|
||||||
|
r"""Return a ``UNION ALL`` of multiple selectables.
|
||||||
|
|
||||||
|
The returned object is an instance of
|
||||||
|
:class:`_expression.CompoundSelect`.
|
||||||
|
|
||||||
|
A similar :func:`union_all()` method is available on all
|
||||||
|
:class:`_expression.FromClause` subclasses.
|
||||||
|
|
||||||
|
:param \*selects:
|
||||||
|
a list of :class:`_expression.Select` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return CompoundSelect._create_union_all(*selects)
|
||||||
|
|
||||||
|
|
||||||
|
def values(
|
||||||
|
*columns: _OnlyColumnArgument[Any],
|
||||||
|
name: Optional[str] = None,
|
||||||
|
literal_binds: bool = False,
|
||||||
|
) -> Values:
|
||||||
|
r"""Construct a :class:`_expression.Values` construct representing the
|
||||||
|
SQL ``VALUES`` clause.
|
||||||
|
|
||||||
|
The column expressions and the actual data for :class:`_expression.Values`
|
||||||
|
are given in two separate steps. The constructor receives the column
|
||||||
|
expressions typically as :func:`_expression.column` constructs, and the
|
||||||
|
data is then passed via the :meth:`_expression.Values.data` method as a
|
||||||
|
list, which can be called multiple times to add more data, e.g.::
|
||||||
|
|
||||||
|
from sqlalchemy import column
|
||||||
|
from sqlalchemy import values
|
||||||
|
from sqlalchemy import Integer
|
||||||
|
from sqlalchemy import String
|
||||||
|
|
||||||
|
value_expr = (
|
||||||
|
values(
|
||||||
|
column("id", Integer),
|
||||||
|
column("name", String),
|
||||||
|
)
|
||||||
|
.data([(1, "name1"), (2, "name2")])
|
||||||
|
.data([(3, "name3")])
|
||||||
|
)
|
||||||
|
|
||||||
|
Would represent a SQL fragment like::
|
||||||
|
|
||||||
|
VALUES(1, "name1"), (2, "name2"), (3, "name3")
|
||||||
|
|
||||||
|
The :class:`_sql.values` construct has an optional
|
||||||
|
:paramref:`_sql.values.name` field; when using this field, the
|
||||||
|
PostgreSQL-specific "named VALUES" clause may be generated::
|
||||||
|
|
||||||
|
value_expr = values(
|
||||||
|
column("id", Integer), column("name", String), name="somename"
|
||||||
|
).data([(1, "name1"), (2, "name2"), (3, "name3")])
|
||||||
|
|
||||||
|
When selecting from the above construct, the name and column names will
|
||||||
|
be listed out using a PostgreSQL-specific syntax::
|
||||||
|
|
||||||
|
>>> print(value_expr.select())
|
||||||
|
SELECT somename.id, somename.name
|
||||||
|
FROM (VALUES (:param_1, :param_2), (:param_3, :param_4),
|
||||||
|
(:param_5, :param_6)) AS somename (id, name)
|
||||||
|
|
||||||
|
For a more database-agnostic means of SELECTing named columns from a
|
||||||
|
VALUES expression, the :meth:`.Values.cte` method may be used, which
|
||||||
|
produces a named CTE with explicit column names against the VALUES
|
||||||
|
construct within; this syntax works on PostgreSQL, SQLite, and MariaDB::
|
||||||
|
|
||||||
|
value_expr = (
|
||||||
|
values(
|
||||||
|
column("id", Integer),
|
||||||
|
column("name", String),
|
||||||
|
)
|
||||||
|
.data([(1, "name1"), (2, "name2"), (3, "name3")])
|
||||||
|
.cte()
|
||||||
|
)
|
||||||
|
|
||||||
|
Rendering as::
|
||||||
|
|
||||||
|
>>> print(value_expr.select())
|
||||||
|
WITH anon_1(id, name) AS
|
||||||
|
(VALUES (:param_1, :param_2), (:param_3, :param_4), (:param_5, :param_6))
|
||||||
|
SELECT anon_1.id, anon_1.name
|
||||||
|
FROM anon_1
|
||||||
|
|
||||||
|
.. versionadded:: 2.0.42 Added the :meth:`.Values.cte` method to
|
||||||
|
:class:`.Values`
|
||||||
|
|
||||||
|
:param \*columns: column expressions, typically composed using
|
||||||
|
:func:`_expression.column` objects.
|
||||||
|
|
||||||
|
:param name: the name for this VALUES construct. If omitted, the
|
||||||
|
VALUES construct will be unnamed in a SQL expression. Different
|
||||||
|
backends may have different requirements here.
|
||||||
|
|
||||||
|
:param literal_binds: Defaults to False. Whether or not to render
|
||||||
|
the data values inline in the SQL output, rather than using bound
|
||||||
|
parameters.
|
||||||
|
|
||||||
|
""" # noqa: E501
|
||||||
|
|
||||||
|
return Values(*columns, literal_binds=literal_binds, name=name)
|
||||||
482
venv/Lib/site-packages/sqlalchemy/sql/_typing.py
Normal file
482
venv/Lib/site-packages/sqlalchemy/sql/_typing.py
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
# sql/_typing.py
|
||||||
|
# Copyright (C) 2022-2026 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
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import operator
|
||||||
|
from typing import Any
|
||||||
|
from typing import Callable
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Generic
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import Mapping
|
||||||
|
from typing import NoReturn
|
||||||
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from . import roles
|
||||||
|
from .. import exc
|
||||||
|
from .. import util
|
||||||
|
from ..inspection import Inspectable
|
||||||
|
from ..util.typing import Literal
|
||||||
|
from ..util.typing import Protocol
|
||||||
|
from ..util.typing import TypeAlias
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from datetime import date
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import time
|
||||||
|
from datetime import timedelta
|
||||||
|
from decimal import Decimal
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from .base import Executable
|
||||||
|
from .compiler import Compiled
|
||||||
|
from .compiler import DDLCompiler
|
||||||
|
from .compiler import SQLCompiler
|
||||||
|
from .dml import UpdateBase
|
||||||
|
from .dml import ValuesBase
|
||||||
|
from .elements import ClauseElement
|
||||||
|
from .elements import ColumnElement
|
||||||
|
from .elements import KeyedColumnElement
|
||||||
|
from .elements import quoted_name
|
||||||
|
from .elements import SQLCoreOperations
|
||||||
|
from .elements import TextClause
|
||||||
|
from .lambdas import LambdaElement
|
||||||
|
from .roles import FromClauseRole
|
||||||
|
from .schema import Column
|
||||||
|
from .selectable import Alias
|
||||||
|
from .selectable import CompoundSelect
|
||||||
|
from .selectable import CTE
|
||||||
|
from .selectable import FromClause
|
||||||
|
from .selectable import Join
|
||||||
|
from .selectable import NamedFromClause
|
||||||
|
from .selectable import ReturnsRows
|
||||||
|
from .selectable import Select
|
||||||
|
from .selectable import Selectable
|
||||||
|
from .selectable import SelectBase
|
||||||
|
from .selectable import Subquery
|
||||||
|
from .selectable import TableClause
|
||||||
|
from .sqltypes import TableValueType
|
||||||
|
from .sqltypes import TupleType
|
||||||
|
from .type_api import TypeEngine
|
||||||
|
from ..engine import Connection
|
||||||
|
from ..engine import Dialect
|
||||||
|
from ..engine import Engine
|
||||||
|
from ..engine.mock import MockConnection
|
||||||
|
from ..util.typing import TypeGuard
|
||||||
|
|
||||||
|
_T = TypeVar("_T", bound=Any)
|
||||||
|
_T_co = TypeVar("_T_co", bound=Any, covariant=True)
|
||||||
|
|
||||||
|
|
||||||
|
_CE = TypeVar("_CE", bound="ColumnElement[Any]")
|
||||||
|
|
||||||
|
_CLE = TypeVar("_CLE", bound="ClauseElement")
|
||||||
|
|
||||||
|
|
||||||
|
class _HasClauseElement(Protocol, Generic[_T_co]):
|
||||||
|
"""indicates a class that has a __clause_element__() method"""
|
||||||
|
|
||||||
|
def __clause_element__(self) -> roles.ExpressionElementRole[_T_co]: ...
|
||||||
|
|
||||||
|
|
||||||
|
class _CoreAdapterProto(Protocol):
|
||||||
|
"""protocol for the ClauseAdapter/ColumnAdapter.traverse() method."""
|
||||||
|
|
||||||
|
def __call__(self, obj: _CE) -> _CE: ...
|
||||||
|
|
||||||
|
|
||||||
|
class _HasDialect(Protocol):
|
||||||
|
"""protocol for Engine/Connection-like objects that have dialect
|
||||||
|
attribute.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dialect(self) -> Dialect: ...
|
||||||
|
|
||||||
|
|
||||||
|
# match column types that are not ORM entities
|
||||||
|
_NOT_ENTITY = TypeVar(
|
||||||
|
"_NOT_ENTITY",
|
||||||
|
int,
|
||||||
|
str,
|
||||||
|
bool,
|
||||||
|
"datetime",
|
||||||
|
"date",
|
||||||
|
"time",
|
||||||
|
"timedelta",
|
||||||
|
"UUID",
|
||||||
|
float,
|
||||||
|
"Decimal",
|
||||||
|
)
|
||||||
|
|
||||||
|
_StarOrOne = Literal["*", 1]
|
||||||
|
|
||||||
|
_MAYBE_ENTITY = TypeVar(
|
||||||
|
"_MAYBE_ENTITY",
|
||||||
|
roles.ColumnsClauseRole,
|
||||||
|
_StarOrOne,
|
||||||
|
Type[Any],
|
||||||
|
Inspectable[_HasClauseElement[Any]],
|
||||||
|
_HasClauseElement[Any],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# convention:
|
||||||
|
# XYZArgument - something that the end user is passing to a public API method
|
||||||
|
# XYZElement - the internal representation that we use for the thing.
|
||||||
|
# the coercions system is responsible for converting from XYZArgument to
|
||||||
|
# XYZElement.
|
||||||
|
|
||||||
|
_TextCoercedExpressionArgument = Union[
|
||||||
|
str,
|
||||||
|
"TextClause",
|
||||||
|
"ColumnElement[_T]",
|
||||||
|
_HasClauseElement[_T],
|
||||||
|
roles.ExpressionElementRole[_T],
|
||||||
|
]
|
||||||
|
|
||||||
|
_ColumnsClauseArgument = Union[
|
||||||
|
roles.TypedColumnsClauseRole[_T],
|
||||||
|
roles.ColumnsClauseRole,
|
||||||
|
"SQLCoreOperations[_T]",
|
||||||
|
_StarOrOne,
|
||||||
|
Type[_T],
|
||||||
|
Inspectable[_HasClauseElement[_T]],
|
||||||
|
_HasClauseElement[_T],
|
||||||
|
]
|
||||||
|
"""open-ended SELECT columns clause argument.
|
||||||
|
|
||||||
|
Includes column expressions, tables, ORM mapped entities, a few literal values.
|
||||||
|
|
||||||
|
This type is used for lists of columns / entities to be returned in result
|
||||||
|
sets; select(...), insert().returning(...), etc.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_TypedColumnClauseArgument = Union[
|
||||||
|
roles.TypedColumnsClauseRole[_T],
|
||||||
|
"SQLCoreOperations[_T]",
|
||||||
|
Type[_T],
|
||||||
|
]
|
||||||
|
|
||||||
|
_TP = TypeVar("_TP", bound=Tuple[Any, ...])
|
||||||
|
|
||||||
|
_T0 = TypeVar("_T0", bound=Any)
|
||||||
|
_T1 = TypeVar("_T1", bound=Any)
|
||||||
|
_T2 = TypeVar("_T2", bound=Any)
|
||||||
|
_T3 = TypeVar("_T3", bound=Any)
|
||||||
|
_T4 = TypeVar("_T4", bound=Any)
|
||||||
|
_T5 = TypeVar("_T5", bound=Any)
|
||||||
|
_T6 = TypeVar("_T6", bound=Any)
|
||||||
|
_T7 = TypeVar("_T7", bound=Any)
|
||||||
|
_T8 = TypeVar("_T8", bound=Any)
|
||||||
|
_T9 = TypeVar("_T9", bound=Any)
|
||||||
|
|
||||||
|
|
||||||
|
_OnlyColumnArgument = Union[
|
||||||
|
"ColumnElement[_T]",
|
||||||
|
_HasClauseElement[_T],
|
||||||
|
roles.DMLColumnRole,
|
||||||
|
]
|
||||||
|
"""A narrow type that is looking for a ColumnClause (e.g. table column with a
|
||||||
|
name) or an ORM element that produces this.
|
||||||
|
|
||||||
|
This is used for constructs that need a named column to represent a
|
||||||
|
position in a selectable, like TextClause().columns() or values(...).
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ColumnExpressionArgument = Union[
|
||||||
|
"ColumnElement[_T]",
|
||||||
|
_HasClauseElement[_T],
|
||||||
|
"SQLCoreOperations[_T]",
|
||||||
|
roles.ExpressionElementRole[_T],
|
||||||
|
roles.TypedColumnsClauseRole[_T],
|
||||||
|
Callable[[], "ColumnElement[_T]"],
|
||||||
|
"LambdaElement",
|
||||||
|
]
|
||||||
|
"See docs in public alias ColumnExpressionArgument."
|
||||||
|
|
||||||
|
ColumnExpressionArgument: TypeAlias = _ColumnExpressionArgument[_T]
|
||||||
|
"""Narrower "column expression" argument.
|
||||||
|
|
||||||
|
This type is used for all the other "column" kinds of expressions that
|
||||||
|
typically represent a single SQL column expression, not a set of columns the
|
||||||
|
way a table or ORM entity does.
|
||||||
|
|
||||||
|
This includes ColumnElement, or ORM-mapped attributes that will have a
|
||||||
|
``__clause_element__()`` method, it also has the ExpressionElementRole
|
||||||
|
overall which brings in the TextClause object also.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0.13
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ColumnExpressionOrLiteralArgument = Union[Any, _ColumnExpressionArgument[_T]]
|
||||||
|
|
||||||
|
_ColumnExpressionOrStrLabelArgument = Union[str, _ColumnExpressionArgument[_T]]
|
||||||
|
|
||||||
|
_ByArgument = Union[
|
||||||
|
Iterable[_ColumnExpressionOrStrLabelArgument[Any]],
|
||||||
|
_ColumnExpressionOrStrLabelArgument[Any],
|
||||||
|
]
|
||||||
|
"""Used for keyword-based ``order_by`` and ``partition_by`` parameters."""
|
||||||
|
|
||||||
|
|
||||||
|
_InfoType = Dict[Any, Any]
|
||||||
|
"""the .info dictionary accepted and used throughout Core /ORM"""
|
||||||
|
|
||||||
|
_FromClauseArgument = Union[
|
||||||
|
roles.FromClauseRole,
|
||||||
|
roles.TypedColumnsClauseRole[Any],
|
||||||
|
Type[Any],
|
||||||
|
Inspectable[_HasClauseElement[Any]],
|
||||||
|
_HasClauseElement[Any],
|
||||||
|
]
|
||||||
|
"""A FROM clause, like we would send to select().select_from().
|
||||||
|
|
||||||
|
Also accommodates ORM entities and related constructs.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_JoinTargetArgument = Union[_FromClauseArgument, roles.JoinTargetRole]
|
||||||
|
"""target for join() builds on _FromClauseArgument to include additional
|
||||||
|
join target roles such as those which come from the ORM.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_OnClauseArgument = Union[_ColumnExpressionArgument[Any], roles.OnClauseRole]
|
||||||
|
"""target for an ON clause, includes additional roles such as those which
|
||||||
|
come from the ORM.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_SelectStatementForCompoundArgument = Union[
|
||||||
|
"Select[_TP]",
|
||||||
|
"CompoundSelect[_TP]",
|
||||||
|
roles.CompoundElementRole,
|
||||||
|
]
|
||||||
|
"""SELECT statement acceptable by ``union()`` and other SQL set operations"""
|
||||||
|
|
||||||
|
_DMLColumnArgument = Union[
|
||||||
|
str,
|
||||||
|
_HasClauseElement[Any],
|
||||||
|
roles.DMLColumnRole,
|
||||||
|
"SQLCoreOperations[Any]",
|
||||||
|
]
|
||||||
|
"""A DML column expression. This is a "key" inside of insert().values(),
|
||||||
|
update().values(), and related.
|
||||||
|
|
||||||
|
These are usually strings or SQL table columns.
|
||||||
|
|
||||||
|
There's also edge cases like JSON expression assignment, which we would want
|
||||||
|
the DMLColumnRole to be able to accommodate.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_DMLKey = TypeVar("_DMLKey", bound=_DMLColumnArgument)
|
||||||
|
_DMLColumnKeyMapping = Mapping[_DMLKey, Any]
|
||||||
|
|
||||||
|
|
||||||
|
_DDLColumnArgument = Union[str, "Column[Any]", roles.DDLConstraintColumnRole]
|
||||||
|
"""DDL column.
|
||||||
|
|
||||||
|
used for :class:`.PrimaryKeyConstraint`, :class:`.UniqueConstraint`, etc.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_DMLTableArgument = Union[
|
||||||
|
"TableClause",
|
||||||
|
"Join",
|
||||||
|
"Alias",
|
||||||
|
"CTE",
|
||||||
|
Type[Any],
|
||||||
|
Inspectable[_HasClauseElement[Any]],
|
||||||
|
_HasClauseElement[Any],
|
||||||
|
]
|
||||||
|
|
||||||
|
_PropagateAttrsType = util.immutabledict[str, Any]
|
||||||
|
|
||||||
|
_TypeEngineArgument = Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
|
||||||
|
|
||||||
|
_EquivalentColumnMap = Dict["ColumnElement[Any]", Set["ColumnElement[Any]"]]
|
||||||
|
|
||||||
|
_LimitOffsetType = Union[int, _ColumnExpressionArgument[int], None]
|
||||||
|
|
||||||
|
_AutoIncrementType = Union[bool, Literal["auto", "ignore_fk"]]
|
||||||
|
|
||||||
|
_CreateDropBind = Union["Engine", "Connection", "MockConnection"]
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
def is_sql_compiler(c: Compiled) -> TypeGuard[SQLCompiler]: ...
|
||||||
|
|
||||||
|
def is_ddl_compiler(c: Compiled) -> TypeGuard[DDLCompiler]: ...
|
||||||
|
|
||||||
|
def is_named_from_clause(
|
||||||
|
t: FromClauseRole,
|
||||||
|
) -> TypeGuard[NamedFromClause]: ...
|
||||||
|
|
||||||
|
def is_column_element(
|
||||||
|
c: ClauseElement,
|
||||||
|
) -> TypeGuard[ColumnElement[Any]]: ...
|
||||||
|
|
||||||
|
def is_keyed_column_element(
|
||||||
|
c: ClauseElement,
|
||||||
|
) -> TypeGuard[KeyedColumnElement[Any]]: ...
|
||||||
|
|
||||||
|
def is_text_clause(c: ClauseElement) -> TypeGuard[TextClause]: ...
|
||||||
|
|
||||||
|
def is_from_clause(c: ClauseElement) -> TypeGuard[FromClause]: ...
|
||||||
|
|
||||||
|
def is_tuple_type(t: TypeEngine[Any]) -> TypeGuard[TupleType]: ...
|
||||||
|
|
||||||
|
def is_table_value_type(
|
||||||
|
t: TypeEngine[Any],
|
||||||
|
) -> TypeGuard[TableValueType]: ...
|
||||||
|
|
||||||
|
def is_selectable(t: Any) -> TypeGuard[Selectable]: ...
|
||||||
|
|
||||||
|
def is_select_base(
|
||||||
|
t: Union[Executable, ReturnsRows],
|
||||||
|
) -> TypeGuard[SelectBase]: ...
|
||||||
|
|
||||||
|
def is_select_statement(
|
||||||
|
t: Union[Executable, ReturnsRows],
|
||||||
|
) -> TypeGuard[Select[Any]]: ...
|
||||||
|
|
||||||
|
def is_table(t: FromClause) -> TypeGuard[TableClause]: ...
|
||||||
|
|
||||||
|
def is_subquery(t: FromClause) -> TypeGuard[Subquery]: ...
|
||||||
|
|
||||||
|
def is_dml(c: ClauseElement) -> TypeGuard[UpdateBase]: ...
|
||||||
|
|
||||||
|
else:
|
||||||
|
is_sql_compiler = operator.attrgetter("is_sql")
|
||||||
|
is_ddl_compiler = operator.attrgetter("is_ddl")
|
||||||
|
is_named_from_clause = operator.attrgetter("named_with_column")
|
||||||
|
is_column_element = operator.attrgetter("_is_column_element")
|
||||||
|
is_keyed_column_element = operator.attrgetter("_is_keyed_column_element")
|
||||||
|
is_text_clause = operator.attrgetter("_is_text_clause")
|
||||||
|
is_from_clause = operator.attrgetter("_is_from_clause")
|
||||||
|
is_tuple_type = operator.attrgetter("_is_tuple_type")
|
||||||
|
is_table_value_type = operator.attrgetter("_is_table_value")
|
||||||
|
is_selectable = operator.attrgetter("is_selectable")
|
||||||
|
is_select_base = operator.attrgetter("_is_select_base")
|
||||||
|
is_select_statement = operator.attrgetter("_is_select_statement")
|
||||||
|
is_table = operator.attrgetter("_is_table")
|
||||||
|
is_subquery = operator.attrgetter("_is_subquery")
|
||||||
|
is_dml = operator.attrgetter("is_dml")
|
||||||
|
|
||||||
|
|
||||||
|
def has_schema_attr(t: FromClauseRole) -> TypeGuard[TableClause]:
|
||||||
|
return hasattr(t, "schema")
|
||||||
|
|
||||||
|
|
||||||
|
def is_quoted_name(s: str) -> TypeGuard[quoted_name]:
|
||||||
|
return hasattr(s, "quote")
|
||||||
|
|
||||||
|
|
||||||
|
def is_has_clause_element(s: object) -> TypeGuard[_HasClauseElement[Any]]:
|
||||||
|
return hasattr(s, "__clause_element__")
|
||||||
|
|
||||||
|
|
||||||
|
def is_insert_update(c: ClauseElement) -> TypeGuard[ValuesBase]:
|
||||||
|
return c.is_dml and (c.is_insert or c.is_update) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def _no_kw() -> exc.ArgumentError:
|
||||||
|
return exc.ArgumentError(
|
||||||
|
"Additional keyword arguments are not accepted by this "
|
||||||
|
"function/method. The presence of **kw is for pep-484 typing purposes"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _unexpected_kw(methname: str, kw: Dict[str, Any]) -> NoReturn:
|
||||||
|
k = list(kw)[0]
|
||||||
|
raise TypeError(f"{methname} got an unexpected keyword argument '{k}'")
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def Nullable(
|
||||||
|
val: "SQLCoreOperations[_T]",
|
||||||
|
) -> "SQLCoreOperations[Optional[_T]]": ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def Nullable(
|
||||||
|
val: roles.ExpressionElementRole[_T],
|
||||||
|
) -> roles.ExpressionElementRole[Optional[_T]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def Nullable(val: Type[_T]) -> Type[Optional[_T]]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def Nullable(
|
||||||
|
val: _TypedColumnClauseArgument[_T],
|
||||||
|
) -> _TypedColumnClauseArgument[Optional[_T]]:
|
||||||
|
"""Types a column or ORM class as nullable.
|
||||||
|
|
||||||
|
This can be used in select and other contexts to express that the value of
|
||||||
|
a column can be null, for example due to an outer join::
|
||||||
|
|
||||||
|
stmt1 = select(A, Nullable(B)).outerjoin(A.bs)
|
||||||
|
stmt2 = select(A.data, Nullable(B.data)).outerjoin(A.bs)
|
||||||
|
|
||||||
|
At runtime this method returns the input unchanged.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0.20
|
||||||
|
"""
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def NotNullable(
|
||||||
|
val: "SQLCoreOperations[Optional[_T]]",
|
||||||
|
) -> "SQLCoreOperations[_T]": ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def NotNullable(
|
||||||
|
val: roles.ExpressionElementRole[Optional[_T]],
|
||||||
|
) -> roles.ExpressionElementRole[_T]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def NotNullable(val: Type[Optional[_T]]) -> Type[_T]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def NotNullable(val: Optional[Type[_T]]) -> Type[_T]: ...
|
||||||
|
|
||||||
|
|
||||||
|
def NotNullable(
|
||||||
|
val: Union[_TypedColumnClauseArgument[Optional[_T]], Optional[Type[_T]]],
|
||||||
|
) -> _TypedColumnClauseArgument[_T]:
|
||||||
|
"""Types a column or ORM class as not nullable.
|
||||||
|
|
||||||
|
This can be used in select and other contexts to express that the value of
|
||||||
|
a column cannot be null, for example due to a where condition on a
|
||||||
|
nullable column::
|
||||||
|
|
||||||
|
stmt = select(NotNullable(A.value)).where(A.value.is_not(None))
|
||||||
|
|
||||||
|
At runtime this method returns the input unchanged.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0.20
|
||||||
|
"""
|
||||||
|
return val # type: ignore
|
||||||
587
venv/Lib/site-packages/sqlalchemy/sql/annotation.py
Normal file
587
venv/Lib/site-packages/sqlalchemy/sql/annotation.py
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
# sql/annotation.py
|
||||||
|
# Copyright (C) 2005-2026 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
|
||||||
|
|
||||||
|
"""The :class:`.Annotated` class and related routines; creates hash-equivalent
|
||||||
|
copies of SQL constructs which contain context-specific markers and
|
||||||
|
associations.
|
||||||
|
|
||||||
|
Note that the :class:`.Annotated` concept as implemented in this module is not
|
||||||
|
related in any way to the pep-593 concept of "Annotated".
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import typing
|
||||||
|
from typing import Any
|
||||||
|
from typing import Callable
|
||||||
|
from typing import cast
|
||||||
|
from typing import Dict
|
||||||
|
from typing import FrozenSet
|
||||||
|
from typing import Mapping
|
||||||
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
|
from typing import Sequence
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
from . import operators
|
||||||
|
from .cache_key import HasCacheKey
|
||||||
|
from .visitors import anon_map
|
||||||
|
from .visitors import ExternallyTraversible
|
||||||
|
from .visitors import InternalTraversal
|
||||||
|
from .. import util
|
||||||
|
from ..util.typing import Literal
|
||||||
|
from ..util.typing import Self
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .base import _EntityNamespace
|
||||||
|
from .visitors import _TraverseInternalsType
|
||||||
|
|
||||||
|
_AnnotationDict = Mapping[str, Any]
|
||||||
|
|
||||||
|
EMPTY_ANNOTATIONS: util.immutabledict[str, Any] = util.EMPTY_DICT
|
||||||
|
|
||||||
|
|
||||||
|
class SupportsAnnotations(ExternallyTraversible):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
_annotations: util.immutabledict[str, Any] = EMPTY_ANNOTATIONS
|
||||||
|
|
||||||
|
proxy_set: util.generic_fn_descriptor[FrozenSet[Any]]
|
||||||
|
|
||||||
|
_is_immutable: bool
|
||||||
|
|
||||||
|
def _annotate(self, values: _AnnotationDict) -> Self:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Literal[None] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> Self: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Sequence[str] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> SupportsAnnotations: ...
|
||||||
|
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Optional[Sequence[str]] = None,
|
||||||
|
clone: bool = False,
|
||||||
|
) -> SupportsAnnotations:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@util.memoized_property
|
||||||
|
def _annotations_cache_key(self) -> Tuple[Any, ...]:
|
||||||
|
anon_map_ = anon_map()
|
||||||
|
|
||||||
|
return self._gen_annotations_cache_key(anon_map_)
|
||||||
|
|
||||||
|
def _gen_annotations_cache_key(
|
||||||
|
self, anon_map: anon_map
|
||||||
|
) -> Tuple[Any, ...]:
|
||||||
|
return (
|
||||||
|
"_annotations",
|
||||||
|
tuple(
|
||||||
|
(
|
||||||
|
key,
|
||||||
|
(
|
||||||
|
value._gen_cache_key(anon_map, [])
|
||||||
|
if isinstance(value, HasCacheKey)
|
||||||
|
else value
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for key, value in [
|
||||||
|
(key, self._annotations[key])
|
||||||
|
for key in sorted(self._annotations)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SupportsWrappingAnnotations(SupportsAnnotations):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
_constructor: Callable[..., SupportsWrappingAnnotations]
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
@util.ro_non_memoized_property
|
||||||
|
def entity_namespace(self) -> _EntityNamespace: ...
|
||||||
|
|
||||||
|
def _annotate(self, values: _AnnotationDict) -> Self:
|
||||||
|
"""return a copy of this ClauseElement with annotations
|
||||||
|
updated by the given dictionary.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return Annotated._as_annotated_instance(self, values) # type: ignore
|
||||||
|
|
||||||
|
def _with_annotations(self, values: _AnnotationDict) -> Self:
|
||||||
|
"""return a copy of this ClauseElement with annotations
|
||||||
|
replaced by the given dictionary.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return Annotated._as_annotated_instance(self, values) # type: ignore
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Literal[None] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> Self: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Sequence[str] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> SupportsAnnotations: ...
|
||||||
|
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Optional[Sequence[str]] = None,
|
||||||
|
clone: bool = False,
|
||||||
|
) -> SupportsAnnotations:
|
||||||
|
"""return a copy of this :class:`_expression.ClauseElement`
|
||||||
|
with annotations
|
||||||
|
removed.
|
||||||
|
|
||||||
|
:param values: optional tuple of individual values
|
||||||
|
to remove.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if clone:
|
||||||
|
s = self._clone()
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class SupportsCloneAnnotations(SupportsWrappingAnnotations):
|
||||||
|
# SupportsCloneAnnotations extends from SupportsWrappingAnnotations
|
||||||
|
# to support the structure of having the base ClauseElement
|
||||||
|
# be a subclass of SupportsWrappingAnnotations. Any ClauseElement
|
||||||
|
# subclass that wants to extend from SupportsCloneAnnotations
|
||||||
|
# will inherently also be subclassing SupportsWrappingAnnotations, so
|
||||||
|
# make that specific here.
|
||||||
|
|
||||||
|
if not typing.TYPE_CHECKING:
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
_clone_annotations_traverse_internals: _TraverseInternalsType = [
|
||||||
|
("_annotations", InternalTraversal.dp_annotations_key)
|
||||||
|
]
|
||||||
|
|
||||||
|
def _annotate(self, values: _AnnotationDict) -> Self:
|
||||||
|
"""return a copy of this ClauseElement with annotations
|
||||||
|
updated by the given dictionary.
|
||||||
|
|
||||||
|
"""
|
||||||
|
new = self._clone()
|
||||||
|
new._annotations = new._annotations.union(values)
|
||||||
|
new.__dict__.pop("_annotations_cache_key", None)
|
||||||
|
new.__dict__.pop("_generate_cache_key", None)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _with_annotations(self, values: _AnnotationDict) -> Self:
|
||||||
|
"""return a copy of this ClauseElement with annotations
|
||||||
|
replaced by the given dictionary.
|
||||||
|
|
||||||
|
"""
|
||||||
|
new = self._clone()
|
||||||
|
new._annotations = util.immutabledict(values)
|
||||||
|
new.__dict__.pop("_annotations_cache_key", None)
|
||||||
|
new.__dict__.pop("_generate_cache_key", None)
|
||||||
|
return new
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Literal[None] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> Self: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Sequence[str] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> SupportsAnnotations: ...
|
||||||
|
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Optional[Sequence[str]] = None,
|
||||||
|
clone: bool = False,
|
||||||
|
) -> SupportsAnnotations:
|
||||||
|
"""return a copy of this :class:`_expression.ClauseElement`
|
||||||
|
with annotations
|
||||||
|
removed.
|
||||||
|
|
||||||
|
:param values: optional tuple of individual values
|
||||||
|
to remove.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if clone or self._annotations:
|
||||||
|
# clone is used when we are also copying
|
||||||
|
# the expression for a deep deannotation
|
||||||
|
new = self._clone()
|
||||||
|
new._annotations = util.immutabledict()
|
||||||
|
new.__dict__.pop("_annotations_cache_key", None)
|
||||||
|
return new
|
||||||
|
else:
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class Annotated(SupportsAnnotations):
|
||||||
|
"""clones a SupportsAnnotations and applies an 'annotations' dictionary.
|
||||||
|
|
||||||
|
Unlike regular clones, this clone also mimics __hash__() and
|
||||||
|
__eq__() of the original element so that it takes its place
|
||||||
|
in hashed collections.
|
||||||
|
|
||||||
|
A reference to the original element is maintained, for the important
|
||||||
|
reason of keeping its hash value current. When GC'ed, the
|
||||||
|
hash value may be reused, causing conflicts.
|
||||||
|
|
||||||
|
.. note:: The rationale for Annotated producing a brand new class,
|
||||||
|
rather than placing the functionality directly within ClauseElement,
|
||||||
|
is **performance**. The __hash__() method is absent on plain
|
||||||
|
ClauseElement which leads to significantly reduced function call
|
||||||
|
overhead, as the use of sets and dictionaries against ClauseElement
|
||||||
|
objects is prevalent, but most are not "annotated".
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_is_column_operators = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _as_annotated_instance(
|
||||||
|
cls, element: SupportsWrappingAnnotations, values: _AnnotationDict
|
||||||
|
) -> Annotated:
|
||||||
|
try:
|
||||||
|
cls = annotated_classes[element.__class__]
|
||||||
|
except KeyError:
|
||||||
|
cls = _new_annotation_type(element.__class__, cls)
|
||||||
|
return cls(element, values)
|
||||||
|
|
||||||
|
_annotations: util.immutabledict[str, Any]
|
||||||
|
__element: SupportsWrappingAnnotations
|
||||||
|
_hash: int
|
||||||
|
|
||||||
|
def __new__(cls: Type[Self], *args: Any) -> Self:
|
||||||
|
return object.__new__(cls)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, element: SupportsWrappingAnnotations, values: _AnnotationDict
|
||||||
|
):
|
||||||
|
self.__dict__ = element.__dict__.copy()
|
||||||
|
self.__dict__.pop("_annotations_cache_key", None)
|
||||||
|
self.__dict__.pop("_generate_cache_key", None)
|
||||||
|
self.__element = element
|
||||||
|
self._annotations = util.immutabledict(values)
|
||||||
|
self._hash = hash(element)
|
||||||
|
|
||||||
|
def _annotate(self, values: _AnnotationDict) -> Self:
|
||||||
|
_values = self._annotations.union(values)
|
||||||
|
new = self._with_annotations(_values)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _with_annotations(self, values: _AnnotationDict) -> Self:
|
||||||
|
clone = self.__class__.__new__(self.__class__)
|
||||||
|
clone.__dict__ = self.__dict__.copy()
|
||||||
|
clone.__dict__.pop("_annotations_cache_key", None)
|
||||||
|
clone.__dict__.pop("_generate_cache_key", None)
|
||||||
|
clone._annotations = util.immutabledict(values)
|
||||||
|
return clone
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Literal[None] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> Self: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Sequence[str] = ...,
|
||||||
|
clone: bool = ...,
|
||||||
|
) -> Annotated: ...
|
||||||
|
|
||||||
|
def _deannotate(
|
||||||
|
self,
|
||||||
|
values: Optional[Sequence[str]] = None,
|
||||||
|
clone: bool = True,
|
||||||
|
) -> SupportsAnnotations:
|
||||||
|
if values is None:
|
||||||
|
return self.__element
|
||||||
|
else:
|
||||||
|
return self._with_annotations(
|
||||||
|
util.immutabledict(
|
||||||
|
{
|
||||||
|
key: value
|
||||||
|
for key, value in self._annotations.items()
|
||||||
|
if key not in values
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not typing.TYPE_CHECKING:
|
||||||
|
# manually proxy some methods that need extra attention
|
||||||
|
def _compiler_dispatch(self, visitor: Any, **kw: Any) -> Any:
|
||||||
|
return self.__element.__class__._compiler_dispatch(
|
||||||
|
self, visitor, **kw
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _constructor(self):
|
||||||
|
return self.__element._constructor
|
||||||
|
|
||||||
|
def _clone(self, **kw: Any) -> Self:
|
||||||
|
clone = self.__element._clone(**kw)
|
||||||
|
if clone is self.__element:
|
||||||
|
# detect immutable, don't change anything
|
||||||
|
return self
|
||||||
|
else:
|
||||||
|
# update the clone with any changes that have occurred
|
||||||
|
# to this object's __dict__.
|
||||||
|
clone.__dict__.update(self.__dict__)
|
||||||
|
return self.__class__(clone, self._annotations)
|
||||||
|
|
||||||
|
def __reduce__(self) -> Tuple[Type[Annotated], Tuple[Any, ...]]:
|
||||||
|
return self.__class__, (self.__element, self._annotations)
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return self._hash
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if self._is_column_operators:
|
||||||
|
return self.__element.__class__.__eq__(self, other)
|
||||||
|
else:
|
||||||
|
return hash(other) == hash(self)
|
||||||
|
|
||||||
|
@util.ro_non_memoized_property
|
||||||
|
def entity_namespace(self) -> _EntityNamespace:
|
||||||
|
if "entity_namespace" in self._annotations:
|
||||||
|
return cast(
|
||||||
|
SupportsWrappingAnnotations,
|
||||||
|
self._annotations["entity_namespace"],
|
||||||
|
).entity_namespace
|
||||||
|
else:
|
||||||
|
return self.__element.entity_namespace
|
||||||
|
|
||||||
|
|
||||||
|
# hard-generate Annotated subclasses. this technique
|
||||||
|
# is used instead of on-the-fly types (i.e. type.__new__())
|
||||||
|
# so that the resulting objects are pickleable; additionally, other
|
||||||
|
# decisions can be made up front about the type of object being annotated
|
||||||
|
# just once per class rather than per-instance.
|
||||||
|
annotated_classes: Dict[Type[SupportsWrappingAnnotations], Type[Annotated]] = (
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
_SA = TypeVar("_SA", bound="SupportsAnnotations")
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_annotate(to_annotate: _SA, annotations: _AnnotationDict) -> _SA:
|
||||||
|
try:
|
||||||
|
_annotate = to_annotate._annotate
|
||||||
|
except AttributeError:
|
||||||
|
# skip objects that don't actually have an `_annotate`
|
||||||
|
# attribute, namely QueryableAttribute inside of a join
|
||||||
|
# condition
|
||||||
|
return to_annotate
|
||||||
|
else:
|
||||||
|
return _annotate(annotations)
|
||||||
|
|
||||||
|
|
||||||
|
def _deep_annotate(
|
||||||
|
element: _SA,
|
||||||
|
annotations: _AnnotationDict,
|
||||||
|
exclude: Optional[Sequence[SupportsAnnotations]] = None,
|
||||||
|
*,
|
||||||
|
detect_subquery_cols: bool = False,
|
||||||
|
ind_cols_on_fromclause: bool = False,
|
||||||
|
annotate_callable: Optional[
|
||||||
|
Callable[[SupportsAnnotations, _AnnotationDict], SupportsAnnotations]
|
||||||
|
] = None,
|
||||||
|
) -> _SA:
|
||||||
|
"""Deep copy the given ClauseElement, annotating each element
|
||||||
|
with the given annotations dictionary.
|
||||||
|
|
||||||
|
Elements within the exclude collection will be cloned but not annotated.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# annotated objects hack the __hash__() method so if we want to
|
||||||
|
# uniquely process them we have to use id()
|
||||||
|
|
||||||
|
cloned_ids: Dict[int, SupportsAnnotations] = {}
|
||||||
|
|
||||||
|
def clone(elem: SupportsAnnotations, **kw: Any) -> SupportsAnnotations:
|
||||||
|
# ind_cols_on_fromclause means make sure an AnnotatedFromClause
|
||||||
|
# has its own .c collection independent of that which its proxying.
|
||||||
|
# this is used specifically by orm.LoaderCriteriaOption to break
|
||||||
|
# a reference cycle that it's otherwise prone to building,
|
||||||
|
# see test_relationship_criteria->
|
||||||
|
# test_loader_criteria_subquery_w_same_entity. logic here was
|
||||||
|
# changed for #8796 and made explicit; previously it occurred
|
||||||
|
# by accident
|
||||||
|
|
||||||
|
kw["detect_subquery_cols"] = detect_subquery_cols
|
||||||
|
id_ = id(elem)
|
||||||
|
|
||||||
|
if id_ in cloned_ids:
|
||||||
|
return cloned_ids[id_]
|
||||||
|
|
||||||
|
if (
|
||||||
|
exclude
|
||||||
|
and hasattr(elem, "proxy_set")
|
||||||
|
and elem.proxy_set.intersection(exclude)
|
||||||
|
):
|
||||||
|
newelem = elem._clone(clone=clone, **kw)
|
||||||
|
elif annotations != elem._annotations:
|
||||||
|
if detect_subquery_cols and elem._is_immutable:
|
||||||
|
to_annotate = elem._clone(clone=clone, **kw)
|
||||||
|
else:
|
||||||
|
to_annotate = elem
|
||||||
|
if annotate_callable:
|
||||||
|
newelem = annotate_callable(to_annotate, annotations)
|
||||||
|
else:
|
||||||
|
newelem = _safe_annotate(to_annotate, annotations)
|
||||||
|
else:
|
||||||
|
newelem = elem
|
||||||
|
|
||||||
|
newelem._copy_internals(
|
||||||
|
clone=clone,
|
||||||
|
ind_cols_on_fromclause=ind_cols_on_fromclause,
|
||||||
|
_annotations_traversal=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
cloned_ids[id_] = newelem
|
||||||
|
return newelem
|
||||||
|
|
||||||
|
if element is not None:
|
||||||
|
element = cast(_SA, clone(element))
|
||||||
|
clone = None # type: ignore # remove gc cycles
|
||||||
|
return element
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deep_deannotate(
|
||||||
|
element: Literal[None], values: Optional[Sequence[str]] = None
|
||||||
|
) -> Literal[None]: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def _deep_deannotate(
|
||||||
|
element: _SA, values: Optional[Sequence[str]] = None
|
||||||
|
) -> _SA: ...
|
||||||
|
|
||||||
|
|
||||||
|
def _deep_deannotate(
|
||||||
|
element: Optional[_SA], values: Optional[Sequence[str]] = None
|
||||||
|
) -> Optional[_SA]:
|
||||||
|
"""Deep copy the given element, removing annotations."""
|
||||||
|
|
||||||
|
cloned: Dict[Any, SupportsAnnotations] = {}
|
||||||
|
|
||||||
|
def clone(elem: SupportsAnnotations, **kw: Any) -> SupportsAnnotations:
|
||||||
|
key: Any
|
||||||
|
if values:
|
||||||
|
key = id(elem)
|
||||||
|
else:
|
||||||
|
key = elem
|
||||||
|
|
||||||
|
if key not in cloned:
|
||||||
|
newelem = elem._deannotate(values=values, clone=True)
|
||||||
|
newelem._copy_internals(clone=clone, _annotations_traversal=True)
|
||||||
|
cloned[key] = newelem
|
||||||
|
return newelem
|
||||||
|
else:
|
||||||
|
return cloned[key]
|
||||||
|
|
||||||
|
if element is not None:
|
||||||
|
element = cast(_SA, clone(element))
|
||||||
|
clone = None # type: ignore # remove gc cycles
|
||||||
|
return element
|
||||||
|
|
||||||
|
|
||||||
|
def _shallow_annotate(element: _SA, annotations: _AnnotationDict) -> _SA:
|
||||||
|
"""Annotate the given ClauseElement and copy its internals so that
|
||||||
|
internal objects refer to the new annotated object.
|
||||||
|
|
||||||
|
Basically used to apply a "don't traverse" annotation to a
|
||||||
|
selectable, without digging throughout the whole
|
||||||
|
structure wasting time.
|
||||||
|
"""
|
||||||
|
element = element._annotate(annotations)
|
||||||
|
element._copy_internals(_annotations_traversal=True)
|
||||||
|
return element
|
||||||
|
|
||||||
|
|
||||||
|
def _new_annotation_type(
|
||||||
|
cls: Type[SupportsWrappingAnnotations], base_cls: Type[Annotated]
|
||||||
|
) -> Type[Annotated]:
|
||||||
|
"""Generates a new class that subclasses Annotated and proxies a given
|
||||||
|
element type.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if issubclass(cls, Annotated):
|
||||||
|
return cls
|
||||||
|
elif cls in annotated_classes:
|
||||||
|
return annotated_classes[cls]
|
||||||
|
|
||||||
|
for super_ in cls.__mro__:
|
||||||
|
# check if an Annotated subclass more specific than
|
||||||
|
# the given base_cls is already registered, such
|
||||||
|
# as AnnotatedColumnElement.
|
||||||
|
if super_ in annotated_classes:
|
||||||
|
base_cls = annotated_classes[super_]
|
||||||
|
break
|
||||||
|
|
||||||
|
annotated_classes[cls] = anno_cls = cast(
|
||||||
|
Type[Annotated],
|
||||||
|
type("Annotated%s" % cls.__name__, (base_cls, cls), {}),
|
||||||
|
)
|
||||||
|
globals()["Annotated%s" % cls.__name__] = anno_cls
|
||||||
|
|
||||||
|
if "_traverse_internals" in cls.__dict__:
|
||||||
|
anno_cls._traverse_internals = list(cls._traverse_internals) + [
|
||||||
|
("_annotations", InternalTraversal.dp_annotations_key)
|
||||||
|
]
|
||||||
|
elif cls.__dict__.get("inherit_cache", False):
|
||||||
|
anno_cls._traverse_internals = list(cls._traverse_internals) + [
|
||||||
|
("_annotations", InternalTraversal.dp_annotations_key)
|
||||||
|
]
|
||||||
|
|
||||||
|
# some classes include this even if they have traverse_internals
|
||||||
|
# e.g. BindParameter, add it if present.
|
||||||
|
if cls.__dict__.get("inherit_cache", False):
|
||||||
|
anno_cls.inherit_cache = True # type: ignore
|
||||||
|
elif "inherit_cache" in cls.__dict__:
|
||||||
|
anno_cls.inherit_cache = cls.__dict__["inherit_cache"] # type: ignore
|
||||||
|
|
||||||
|
anno_cls._is_column_operators = issubclass(cls, operators.ColumnOperators)
|
||||||
|
|
||||||
|
return anno_cls
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_annotations(
|
||||||
|
target_hierarchy: Type[SupportsWrappingAnnotations],
|
||||||
|
base_cls: Type[Annotated],
|
||||||
|
) -> None:
|
||||||
|
for cls in util.walk_subclasses(target_hierarchy):
|
||||||
|
_new_annotation_type(cls, base_cls)
|
||||||
2292
venv/Lib/site-packages/sqlalchemy/sql/base.py
Normal file
2292
venv/Lib/site-packages/sqlalchemy/sql/base.py
Normal file
File diff suppressed because it is too large
Load Diff
1057
venv/Lib/site-packages/sqlalchemy/sql/cache_key.py
Normal file
1057
venv/Lib/site-packages/sqlalchemy/sql/cache_key.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user