]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
initial reorganize for static typing
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Jan 2022 22:35:43 +0000 (17:35 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 12 Jan 2022 15:29:30 +0000 (10:29 -0500)
start applying foundational annotations to key
elements.

two main elements addressed here:

1. removal of public_factory() and replacement with
   explicit functions.  this just works much better with
   typing.

2. typing support for column expressions and operators.
   The biggest part of this involves stubbing out all the
   ColumnOperators methods under ColumnElement in a
   TYPE_CHECKING section.  Took me a while to see this
   method vs. much more complicated things I thought
   I needed.

Also for this version implementing #7519, ColumnElement
types against the Python type and not TypeEngine.  it is
hoped this leads to easier transferrence between ORM/Core
as well as eventual support for result set typing.
Not clear yet how well this approach will work and what
new issues it may introduce.

given the current approach we now get full, rich typing for
scenarios like this:

from sqlalchemy import column, Integer, String, Boolean

c1 = column('a', String)

c2 = column('a', Integer)

expr1 = c2.in_([1, 2, 3])

expr2 = c2 / 5

expr3 = -c2

expr4_a = ~(c2 == 5)

expr4_b = ~column('q', Boolean)

expr5 = c1 + 'x'

expr6 = c2 + 10

Fixes: #7519
Fixes: #6810
Change-Id: I078d9f57955549f6f7868314287175f6c61c44cb

45 files changed:
lib/sqlalchemy/__init__.py
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/dialects/mysql/dml.py
lib/sqlalchemy/dialects/postgresql/array.py
lib/sqlalchemy/dialects/postgresql/dml.py
lib/sqlalchemy/dialects/sqlite/dml.py
lib/sqlalchemy/future/__init__.py
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/_orm_constructors.py [new file with mode: 0644]
lib/sqlalchemy/orm/base.py
lib/sqlalchemy/orm/context.py
lib/sqlalchemy/orm/decl_api.py
lib/sqlalchemy/orm/decl_base.py
lib/sqlalchemy/orm/descriptor_props.py
lib/sqlalchemy/orm/dynamic.py
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/relationships.py
lib/sqlalchemy/orm/scoping.py
lib/sqlalchemy/orm/util.py
lib/sqlalchemy/sql/__init__.py
lib/sqlalchemy/sql/_dml_constructors.py [new file with mode: 0644]
lib/sqlalchemy/sql/_elements_constructors.py [new file with mode: 0644]
lib/sqlalchemy/sql/_selectable_constructors.py [new file with mode: 0644]
lib/sqlalchemy/sql/coercions.py
lib/sqlalchemy/sql/default_comparator.py
lib/sqlalchemy/sql/dml.py
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/expression.py
lib/sqlalchemy/sql/functions.py
lib/sqlalchemy/sql/operators.py
lib/sqlalchemy/sql/roles.py
lib/sqlalchemy/sql/schema.py
lib/sqlalchemy/sql/selectable.py
lib/sqlalchemy/sql/sqltypes.py
lib/sqlalchemy/sql/type_api.py
lib/sqlalchemy/sql/util.py
lib/sqlalchemy/util/compat.py
lib/sqlalchemy/util/langhelpers.py
setup.cfg
test/base/test_misc_py3k.py
test/base/test_utils.py
test/orm/test_deprecations.py

index 22be3d42f5affcd425d6b8cc11dc5edeca1d3398..7d402d44eceba69302eb08382016f1206fa7aa7c 100644 (file)
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 
 from . import util as _util
-from .engine import create_engine
-from .engine import create_mock_engine
-from .engine import engine_from_config
-from .inspection import inspect
-from .schema import BLANK_SCHEMA
-from .schema import CheckConstraint
-from .schema import Column
-from .schema import ColumnDefault
-from .schema import Computed
-from .schema import Constraint
-from .schema import DDL
-from .schema import DefaultClause
-from .schema import FetchedValue
-from .schema import ForeignKey
-from .schema import ForeignKeyConstraint
-from .schema import Identity
-from .schema import Index
-from .schema import MetaData
-from .schema import PrimaryKeyConstraint
-from .schema import Sequence
-from .schema import Table
-from .schema import UniqueConstraint
-from .sql import alias
-from .sql import all_
-from .sql import and_
-from .sql import any_
-from .sql import asc
-from .sql import between
-from .sql import bindparam
-from .sql import case
-from .sql import cast
-from .sql import collate
-from .sql import column
-from .sql import delete
-from .sql import desc
-from .sql import distinct
-from .sql import except_
-from .sql import except_all
-from .sql import exists
-from .sql import extract
-from .sql import false
-from .sql import func
-from .sql import funcfilter
-from .sql import insert
-from .sql import intersect
-from .sql import intersect_all
-from .sql import join
-from .sql import LABEL_STYLE_DEFAULT
-from .sql import LABEL_STYLE_DISAMBIGUATE_ONLY
-from .sql import LABEL_STYLE_NONE
-from .sql import LABEL_STYLE_TABLENAME_PLUS_COL
-from .sql import lambda_stmt
-from .sql import lateral
-from .sql import literal
-from .sql import literal_column
-from .sql import modifier
-from .sql import not_
-from .sql import null
-from .sql import nulls_first
-from .sql import nulls_last
-from .sql import nullsfirst
-from .sql import nullslast
-from .sql import or_
-from .sql import outerjoin
-from .sql import outparam
-from .sql import over
-from .sql import select
-from .sql import table
-from .sql import tablesample
-from .sql import text
-from .sql import true
-from .sql import tuple_
-from .sql import type_coerce
-from .sql import union
-from .sql import union_all
-from .sql import update
-from .sql import values
-from .sql import within_group
-from .types import ARRAY
-from .types import BIGINT
-from .types import BigInteger
-from .types import BINARY
-from .types import BLOB
-from .types import BOOLEAN
-from .types import Boolean
-from .types import CHAR
-from .types import CLOB
-from .types import DATE
-from .types import Date
-from .types import DATETIME
-from .types import DateTime
-from .types import DECIMAL
-from .types import Enum
-from .types import FLOAT
-from .types import Float
-from .types import INT
-from .types import INTEGER
-from .types import Integer
-from .types import Interval
-from .types import JSON
-from .types import LargeBinary
-from .types import NCHAR
-from .types import NUMERIC
-from .types import Numeric
-from .types import NVARCHAR
-from .types import PickleType
-from .types import REAL
-from .types import SMALLINT
-from .types import SmallInteger
-from .types import String
-from .types import TEXT
-from .types import Text
-from .types import TIME
-from .types import Time
-from .types import TIMESTAMP
-from .types import TupleType
-from .types import TypeDecorator
-from .types import Unicode
-from .types import UnicodeText
-from .types import VARBINARY
-from .types import VARCHAR
+from .engine import create_engine as create_engine
+from .engine import create_mock_engine as create_mock_engine
+from .engine import engine_from_config as engine_from_config
+from .inspection import inspect as inspect
+from .schema import BLANK_SCHEMA as BLANK_SCHEMA
+from .schema import CheckConstraint as CheckConstraint
+from .schema import Column as Column
+from .schema import ColumnDefault as ColumnDefault
+from .schema import Computed as Computed
+from .schema import Constraint as Constraint
+from .schema import DDL as DDL
+from .schema import DefaultClause as DefaultClause
+from .schema import FetchedValue as FetchedValue
+from .schema import ForeignKey as ForeignKey
+from .schema import ForeignKeyConstraint as ForeignKeyConstraint
+from .schema import Identity as Identity
+from .schema import Index as Index
+from .schema import MetaData as MetaData
+from .schema import PrimaryKeyConstraint as PrimaryKeyConstraint
+from .schema import Sequence as Sequence
+from .schema import Table as Table
+from .schema import UniqueConstraint as UniqueConstraint
+from .sql import alias as alias
+from .sql import all_ as all_
+from .sql import and_ as and_
+from .sql import any_ as any_
+from .sql import asc as asc
+from .sql import between as between
+from .sql import bindparam as bindparam
+from .sql import case as case
+from .sql import cast as cast
+from .sql import collate as collate
+from .sql import column as column
+from .sql import delete as delete
+from .sql import desc as desc
+from .sql import distinct as distinct
+from .sql import except_ as except_
+from .sql import except_all as except_all
+from .sql import exists as exists
+from .sql import extract as extract
+from .sql import false as false
+from .sql import func as func
+from .sql import funcfilter as funcfilter
+from .sql import insert as insert
+from .sql import intersect as intersect
+from .sql import intersect_all as intersect_all
+from .sql import join as join
+from .sql import label as label
+from .sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
+from .sql import LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY
+from .sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE
+from .sql import lambda_stmt as lambda_stmt
+from .sql import lateral as lateral
+from .sql import literal as literal
+from .sql import literal_column as literal_column
+from .sql import modifier as modifier
+from .sql import not_ as not_
+from .sql import null as null
+from .sql import nulls_first as nulls_first
+from .sql import nulls_last as nulls_last
+from .sql import nullsfirst as nullsfirst
+from .sql import nullslast as nullslast
+from .sql import or_ as or_
+from .sql import outerjoin as outerjoin
+from .sql import outparam as outparam
+from .sql import over as over
+from .sql import select as select
+from .sql import table as table
+from .sql import tablesample as tablesample
+from .sql import text as text
+from .sql import true as true
+from .sql import tuple_ as tuple_
+from .sql import type_coerce as type_coerce
+from .sql import union as union
+from .sql import union_all as union_all
+from .sql import update as update
+from .sql import values as values
+from .sql import within_group as within_group
+from .types import ARRAY as ARRAY
+from .types import BIGINT as BIGINT
+from .types import BigInteger as BigInteger
+from .types import BINARY as BINARY
+from .types import BLOB as BLOB
+from .types import BOOLEAN as BOOLEAN
+from .types import Boolean as Boolean
+from .types import CHAR as CHAR
+from .types import CLOB as CLOB
+from .types import DATE as DATE
+from .types import Date as Date
+from .types import DATETIME as DATETIME
+from .types import DateTime as DateTime
+from .types import DECIMAL as DECIMAL
+from .types import Enum as Enum
+from .types import FLOAT as FLOAT
+from .types import Float as Float
+from .types import INT as INT
+from .types import INTEGER as INTEGER
+from .types import Integer as Integer
+from .types import Interval as Interval
+from .types import JSON as JSON
+from .types import LargeBinary as LargeBinary
+from .types import NCHAR as NCHAR
+from .types import NUMERIC as NUMERIC
+from .types import Numeric as Numeric
+from .types import NVARCHAR as NVARCHAR
+from .types import PickleType as PickleType
+from .types import REAL as REAL
+from .types import SMALLINT as SMALLINT
+from .types import SmallInteger as SmallInteger
+from .types import String as String
+from .types import TEXT as TEXT
+from .types import Text as Text
+from .types import TIME as TIME
+from .types import Time as Time
+from .types import TIMESTAMP as TIMESTAMP
+from .types import TupleType as TupleType
+from .types import TypeDecorator as TypeDecorator
+from .types import Unicode as Unicode
+from .types import UnicodeText as UnicodeText
+from .types import VARBINARY as VARBINARY
+from .types import VARCHAR as VARCHAR
+
+if True:
+    # work around zimports bug
+    from .sql import (
+        LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
+    )
 
 
 __version__ = "2.0.0b1"
 
 
 def __go(lcls):
-    global __all__
-
-    from . import events
     from . import util as _sa_util
 
-    import inspect as _inspect
-
-    __all__ = sorted(
-        name
-        for name, obj in lcls.items()
-        if not (name.startswith("_") or _inspect.ismodule(obj))
-    )
-
     _sa_util.preloaded.import_prefix("sqlalchemy")
 
     from . import exc
index b57e89a419715294a3a211d86d5f014d2a41dd44..d48cca2a88ced34c64dcfc6ffe04a807ea071dec 100644 (file)
@@ -848,7 +848,6 @@ from ...types import SMALLINT
 from ...types import TEXT
 from ...types import VARCHAR
 from ...util import update_wrapper
-from ...util.langhelpers import public_factory
 
 
 # https://sqlserverbuilds.blogspot.com/
@@ -1347,41 +1346,40 @@ class SQL_VARIANT(sqltypes.TypeEngine):
     __visit_name__ = "SQL_VARIANT"
 
 
-class TryCast(sql.elements.Cast):
-    """Represent a SQL Server TRY_CAST expression."""
+def try_cast(*arg, **kw):
+    """Create a TRY_CAST expression.
 
-    __visit_name__ = "try_cast"
+    :class:`.TryCast` is a subclass of SQLAlchemy's :class:`.Cast`
+    construct, and works in the same way, except that the SQL expression
+    rendered is "TRY_CAST" rather than "CAST"::
 
-    stringify_dialect = "mssql"
-    inherit_cache = True
+        from sqlalchemy import select
+        from sqlalchemy import Numeric
+        from sqlalchemy.dialects.mssql import try_cast
 
-    def __init__(self, *arg, **kw):
-        """Create a TRY_CAST expression.
+        stmt = select(
+            try_cast(product_table.c.unit_price, Numeric(10, 4))
+        )
 
-        :class:`.TryCast` is a subclass of SQLAlchemy's :class:`.Cast`
-        construct, and works in the same way, except that the SQL expression
-        rendered is "TRY_CAST" rather than "CAST"::
+    The above would render::
 
-            from sqlalchemy import select
-            from sqlalchemy import Numeric
-            from sqlalchemy.dialects.mssql import try_cast
+        SELECT TRY_CAST (product_table.unit_price AS NUMERIC(10, 4))
+        FROM product_table
 
-            stmt = select(
-                try_cast(product_table.c.unit_price, Numeric(10, 4))
-            )
+    .. versionadded:: 1.3.7
 
-        The above would render::
+    """
+    return TryCast(*arg, **kw)
 
-            SELECT TRY_CAST (product_table.unit_price AS NUMERIC(10, 4))
-            FROM product_table
 
-        .. versionadded:: 1.3.7
+class TryCast(sql.elements.Cast):
+    """Represent a SQL Server TRY_CAST expression."""
 
-        """
-        super(TryCast, self).__init__(*arg, **kw)
+    __visit_name__ = "try_cast"
 
+    stringify_dialect = "mssql"
+    inherit_cache = True
 
-try_cast = public_factory(TryCast, ".dialects.mssql.try_cast")
 
 # old names.
 MSDateTime = _MSDateTime
index a21d49e0bb4cc8562a20acc5f4160f1a00829928..eb4a9f7980d662f6ecc7585c4421d9da9e585a5a 100644 (file)
@@ -14,12 +14,30 @@ from ...sql.base import ColumnCollection
 from ...sql.dml import Insert as StandardInsert
 from ...sql.elements import ClauseElement
 from ...sql.expression import alias
-from ...util.langhelpers import public_factory
 
 
 __all__ = ("Insert", "insert")
 
 
+def insert(table):
+    """Construct a MySQL/MariaDB-specific variant :class:`_mysql.Insert`
+    construct.
+
+    .. container:: inherited_member
+
+        The :func:`sqlalchemy.dialects.mysql.insert` function creates
+        a :class:`sqlalchemy.dialects.mysql.Insert`.  This class is based
+        on the dialect-agnostic :class:`_sql.Insert` construct which may
+        be constructed using the :func:`_sql.insert` function in
+        SQLAlchemy Core.
+
+    The :class:`_mysql.Insert` construct includes additional methods
+    :meth:`_mysql.Insert.on_duplicate_key_update`.
+
+    """
+    return Insert(table)
+
+
 SelfInsert = typing.TypeVar("SelfInsert", bound="Insert")
 
 
@@ -145,11 +163,6 @@ class Insert(StandardInsert):
         return self
 
 
-insert = public_factory(
-    Insert, ".dialects.mysql.insert", ".dialects.mysql.Insert"
-)
-
-
 class OnDuplicateClause(ClauseElement):
     __visit_name__ = "on_duplicate_key_update"
 
index f30a409c7dc422a7e75277e6c2e077c11bd5fd02..abe17ea35e2ef003d9abe3dddc516281fb05c56d 100644 (file)
@@ -94,13 +94,12 @@ class array(expression.ClauseList, expression.ColumnElement):
             coercions.expect(roles.ExpressionElementRole, c) for c in clauses
         ]
 
-        super(array, self).__init__(*clauses, **kw)
-
         self._type_tuple = [arg.type for arg in clauses]
         main_type = kw.pop(
             "type_",
             self._type_tuple[0] if self._type_tuple else sqltypes.NULLTYPE,
         )
+        super(array, self).__init__(*clauses, **kw)
 
         if isinstance(main_type, ARRAY):
             self.type = ARRAY(
index 48b180e81256915cfce37deb512b83cb09fe92d2..09dbd9558f5f857c83934e2209fa6e9bba186e48 100644 (file)
@@ -17,11 +17,31 @@ from ...sql.base import ColumnCollection
 from ...sql.dml import Insert as StandardInsert
 from ...sql.elements import ClauseElement
 from ...sql.expression import alias
-from ...util.langhelpers import public_factory
 
 
 __all__ = ("Insert", "insert")
 
+
+def insert(table):
+    """Construct a PostgreSQL-specific variant :class:`_postgresql.Insert`
+    construct.
+
+    .. container:: inherited_member
+
+        The :func:`sqlalchemy.dialects.postgresql.insert` function creates
+        a :class:`sqlalchemy.dialects.postgresql.Insert`.  This class is based
+        on the dialect-agnostic :class:`_sql.Insert` construct which may
+        be constructed using the :func:`_sql.insert` function in
+        SQLAlchemy Core.
+
+    The :class:`_postgresql.Insert` construct includes additional methods
+    :meth:`_postgresql.Insert.on_conflict_do_update`,
+    :meth:`_postgresql.Insert.on_conflict_do_nothing`.
+
+    """
+    return Insert(table)
+
+
 SelfInsert = typing.TypeVar("SelfInsert", bound="Insert")
 
 
@@ -183,11 +203,6 @@ class Insert(StandardInsert):
         return self
 
 
-insert = public_factory(
-    Insert, ".dialects.postgresql.insert", ".dialects.postgresql.Insert"
-)
-
-
 class OnConflictClause(ClauseElement):
     stringify_dialect = "postgresql"
 
index 9284070dfbd4f89ec307fb1b2706a409758c5b1b..7dee7e3b66c52834d69416f3a63e5d5298923130 100644 (file)
@@ -15,11 +15,31 @@ from ...sql.base import ColumnCollection
 from ...sql.dml import Insert as StandardInsert
 from ...sql.elements import ClauseElement
 from ...sql.expression import alias
-from ...util.langhelpers import public_factory
 
 
 __all__ = ("Insert", "insert")
 
+
+def insert(table):
+    """Construct a sqlite-specific variant :class:`_sqlite.Insert`
+    construct.
+
+    .. container:: inherited_member
+
+        The :func:`sqlalchemy.dialects.sqlite.insert` function creates
+        a :class:`sqlalchemy.dialects.sqlite.Insert`.  This class is based
+        on the dialect-agnostic :class:`_sql.Insert` construct which may
+        be constructed using the :func:`_sql.insert` function in
+        SQLAlchemy Core.
+
+    The :class:`_sqlite.Insert` construct includes additional methods
+    :meth:`_sqlite.Insert.on_conflict_do_update`,
+    :meth:`_sqlite.Insert.on_conflict_do_nothing`.
+
+    """
+    return Insert(table)
+
+
 SelfInsert = typing.TypeVar("SelfInsert", bound="Insert")
 
 
@@ -151,11 +171,6 @@ class Insert(StandardInsert):
         return self
 
 
-insert = public_factory(
-    Insert, ".dialects.sqlite.insert", ".dialects.sqlite.Insert"
-)
-
-
 class OnConflictClause(ClauseElement):
     stringify_dialect = "sqlite"
 
index 3c16e9c0e31b0c43fd5d665413122cd5ff216381..057e3bfbe06c4dda22a05222279c0d004eb8ca86 100644 (file)
@@ -8,11 +8,7 @@
 """Future 2.0 API features.
 
 """
-from .engine import Connection
-from .engine import create_engine
-from .engine import Engine
-from ..sql.selectable import Select
-from ..util.langhelpers import public_factory
-
-
-select = public_factory(Select._create, ".future.select")
+from .engine import Connection as Connection
+from .engine import create_engine as create_engine
+from .engine import Engine as Engine
+from ..sql._selectable_constructors import select as select
index 0d197bf8786b333ceb8fe01f02859cd29de141ff..17167a7de15920ff18a05d287124b9293a64c9dd 100644 (file)
@@ -13,323 +13,115 @@ documentation for an overview of how this module is used.
 
 """
 
-from . import exc
+from . import exc as exc
 from . import mapper as mapperlib
-from . import strategy_options
-from .attributes import AttributeEvent
-from .attributes import InstrumentedAttribute
-from .attributes import Mapped
-from .attributes import QueryableAttribute
-from .context import QueryContext
-from .decl_api import as_declarative
-from .decl_api import declarative_base
-from .decl_api import declarative_mixin
-from .decl_api import DeclarativeMeta
-from .decl_api import declared_attr
-from .decl_api import has_inherited_table
-from .decl_api import registry
-from .decl_api import synonym_for
-from .descriptor_props import CompositeProperty
-from .descriptor_props import SynonymProperty
-from .identity import IdentityMap
-from .instrumentation import ClassManager
-from .interfaces import EXT_CONTINUE
-from .interfaces import EXT_SKIP
-from .interfaces import EXT_STOP
-from .interfaces import InspectionAttr
-from .interfaces import InspectionAttrInfo
-from .interfaces import MANYTOMANY
-from .interfaces import MANYTOONE
-from .interfaces import MapperProperty
-from .interfaces import NOT_EXTENSION
-from .interfaces import ONETOMANY
-from .interfaces import PropComparator
-from .interfaces import UserDefinedOption
-from .loading import merge_frozen_result
-from .loading import merge_result
-from .mapper import class_mapper
-from .mapper import configure_mappers
-from .mapper import Mapper
-from .mapper import reconstructor
-from .mapper import validates
-from .properties import ColumnProperty
-from .query import AliasOption
-from .query import FromStatement
-from .query import Query
-from .relationships import foreign
-from .relationships import RelationshipProperty
-from .relationships import remote
-from .scoping import scoped_session
-from .session import close_all_sessions
-from .session import make_transient
-from .session import make_transient_to_detached
-from .session import object_session
-from .session import ORMExecuteState
-from .session import Session
-from .session import sessionmaker
-from .session import SessionTransaction
-from .state import AttributeState
-from .state import InstanceState
-from .strategy_options import contains_eager
-from .strategy_options import defaultload
-from .strategy_options import defer
-from .strategy_options import immediateload
-from .strategy_options import joinedload
-from .strategy_options import lazyload
-from .strategy_options import Load
-from .strategy_options import load_only
-from .strategy_options import noload
-from .strategy_options import raiseload
-from .strategy_options import selectin_polymorphic
-from .strategy_options import selectinload
-from .strategy_options import subqueryload
-from .strategy_options import undefer
-from .strategy_options import undefer_group
-from .strategy_options import with_expression
-from .unitofwork import UOWTransaction
-from .util import aliased
-from .util import Bundle
-from .util import CascadeOptions
-from .util import join
-from .util import LoaderCriteriaOption
-from .util import object_mapper
-from .util import outerjoin
-from .util import polymorphic_union
-from .util import was_deleted
-from .util import with_parent
-from .util import with_polymorphic
-from .. import sql as _sql
+from . import strategy_options as strategy_options
+from ._orm_constructors import _mapper_fn as mapper
+from ._orm_constructors import backref as backref
+from ._orm_constructors import clear_mappers as clear_mappers
+from ._orm_constructors import column_property as column_property
+from ._orm_constructors import composite as composite
+from ._orm_constructors import contains_alias as contains_alias
+from ._orm_constructors import create_session as create_session
+from ._orm_constructors import deferred as deferred
+from ._orm_constructors import dynamic_loader as dynamic_loader
+from ._orm_constructors import query_expression as query_expression
+from ._orm_constructors import relationship as relationship
+from ._orm_constructors import synonym as synonym
+from ._orm_constructors import with_loader_criteria as with_loader_criteria
+from .attributes import AttributeEvent as AttributeEvent
+from .attributes import InstrumentedAttribute as InstrumentedAttribute
+from .attributes import Mapped as Mapped
+from .attributes import QueryableAttribute as QueryableAttribute
+from .context import QueryContext as QueryContext
+from .decl_api import as_declarative as as_declarative
+from .decl_api import declarative_base as declarative_base
+from .decl_api import declarative_mixin as declarative_mixin
+from .decl_api import DeclarativeMeta as DeclarativeMeta
+from .decl_api import declared_attr as declared_attr
+from .decl_api import has_inherited_table as has_inherited_table
+from .decl_api import registry as registry
+from .decl_api import synonym_for as synonym_for
+from .descriptor_props import CompositeProperty as CompositeProperty
+from .descriptor_props import SynonymProperty as SynonymProperty
+from .dynamic import AppenderQuery as AppenderQuery
+from .events import AttributeEvents as AttributeEvents
+from .events import InstanceEvents as InstanceEvents
+from .events import InstrumentationEvents as InstrumentationEvents
+from .events import MapperEvents as MapperEvents
+from .events import QueryEvents as QueryEvents
+from .events import SessionEvents as SessionEvents
+from .identity import IdentityMap as IdentityMap
+from .instrumentation import ClassManager as ClassManager
+from .interfaces import EXT_CONTINUE as EXT_CONTINUE
+from .interfaces import EXT_SKIP as EXT_SKIP
+from .interfaces import EXT_STOP as EXT_STOP
+from .interfaces import InspectionAttr as InspectionAttr
+from .interfaces import InspectionAttrInfo as InspectionAttrInfo
+from .interfaces import MANYTOMANY as MANYTOMANY
+from .interfaces import MANYTOONE as MANYTOONE
+from .interfaces import MapperProperty as MapperProperty
+from .interfaces import NOT_EXTENSION as NOT_EXTENSION
+from .interfaces import ONETOMANY as ONETOMANY
+from .interfaces import PropComparator as PropComparator
+from .interfaces import UserDefinedOption as UserDefinedOption
+from .loading import merge_frozen_result as merge_frozen_result
+from .loading import merge_result as merge_result
+from .mapper import class_mapper as class_mapper
+from .mapper import configure_mappers as configure_mappers
+from .mapper import Mapper as Mapper
+from .mapper import reconstructor as reconstructor
+from .mapper import validates as validates
+from .properties import ColumnProperty as ColumnProperty
+from .query import AliasOption as AliasOption
+from .query import FromStatement as FromStatement
+from .query import Query as Query
+from .relationships import foreign as foreign
+from .relationships import RelationshipProperty as RelationshipProperty
+from .relationships import remote as remote
+from .scoping import scoped_session as scoped_session
+from .session import close_all_sessions as close_all_sessions
+from .session import make_transient as make_transient
+from .session import make_transient_to_detached as make_transient_to_detached
+from .session import object_session as object_session
+from .session import ORMExecuteState as ORMExecuteState
+from .session import Session as Session
+from .session import sessionmaker as sessionmaker
+from .session import SessionTransaction as SessionTransaction
+from .state import AttributeState as AttributeState
+from .state import InstanceState as InstanceState
+from .strategy_options import contains_eager as contains_eager
+from .strategy_options import defaultload as defaultload
+from .strategy_options import defer as defer
+from .strategy_options import immediateload as immediateload
+from .strategy_options import joinedload as joinedload
+from .strategy_options import lazyload as lazyload
+from .strategy_options import Load as Load
+from .strategy_options import load_only as load_only
+from .strategy_options import noload as noload
+from .strategy_options import raiseload as raiseload
+from .strategy_options import selectin_polymorphic as selectin_polymorphic
+from .strategy_options import selectinload as selectinload
+from .strategy_options import subqueryload as subqueryload
+from .strategy_options import undefer as undefer
+from .strategy_options import undefer_group as undefer_group
+from .strategy_options import with_expression as with_expression
+from .unitofwork import UOWTransaction as UOWTransaction
+from .util import aliased as aliased
+from .util import Bundle as Bundle
+from .util import CascadeOptions as CascadeOptions
+from .util import join as join
+from .util import LoaderCriteriaOption as LoaderCriteriaOption
+from .util import object_mapper as object_mapper
+from .util import outerjoin as outerjoin
+from .util import polymorphic_union as polymorphic_union
+from .util import was_deleted as was_deleted
+from .util import with_parent as with_parent
+from .util import with_polymorphic as with_polymorphic
 from .. import util as _sa_util
-from ..exc import InvalidRequestError
-from ..util.langhelpers import public_factory
-
-
-def create_session(bind=None, **kwargs):
-    r"""Create a new :class:`.Session`
-    with no automation enabled by default.
-
-    This function is used primarily for testing.   The usual
-    route to :class:`.Session` creation is via its constructor
-    or the :func:`.sessionmaker` function.
-
-    :param bind: optional, a single Connectable to use for all
-      database access in the created
-      :class:`~sqlalchemy.orm.session.Session`.
-
-    :param \*\*kwargs: optional, passed through to the
-      :class:`.Session` constructor.
-
-    :returns: an :class:`~sqlalchemy.orm.session.Session` instance
-
-    The defaults of create_session() are the opposite of that of
-    :func:`sessionmaker`; ``autoflush`` and ``expire_on_commit`` are
-    False.
-
-    Usage::
-
-      >>> from sqlalchemy.orm import create_session
-      >>> session = create_session()
-
-    It is recommended to use :func:`sessionmaker` instead of
-    create_session().
-
-    """
-
-    kwargs.setdefault("autoflush", False)
-    kwargs.setdefault("expire_on_commit", False)
-    return Session(bind=bind, **kwargs)
-
-
-with_loader_criteria = public_factory(LoaderCriteriaOption, ".orm")
-
-relationship = public_factory(RelationshipProperty, ".orm.relationship")
-
-
-def mapper(*arg, **kw):
-    """Placeholder for the now-removed ``mapper()`` function.
-
-    Classical mappings should be performed using the
-    :meth:`_orm.registry.map_imperatively` method.
-
-    This symbol remains in SQLAlchemy 2.0 to suit the deprecated use case
-    of using the ``mapper()`` function as a target for ORM event listeners,
-    which failed to be marked as deprecated in the 1.4 series.
-
-    Global ORM mapper listeners should instead use the :class:`_orm.Mapper`
-    class as the target.
-
-    .. versionchanged:: 2.0  The ``mapper()`` function was removed; the
-       symbol remains temporarily as a placeholder for the event listening
-       use case.
-
-    """
-    raise InvalidRequestError(
-        "The 'sqlalchemy.orm.mapper()' function is removed as of "
-        "SQLAlchemy 2.0.  Use the "
-        "'sqlalchemy.orm.registry.map_imperatively()` "
-        "method of the ``sqlalchemy.orm.registry`` class to perform "
-        "classical mapping."
-    )
-
-
-def dynamic_loader(argument, **kw):
-    """Construct a dynamically-loading mapper property.
-
-    This is essentially the same as
-    using the ``lazy='dynamic'`` argument with :func:`relationship`::
-
-        dynamic_loader(SomeClass)
-
-        # is the same as
-
-        relationship(SomeClass, lazy="dynamic")
-
-    See the section :ref:`dynamic_relationship` for more details
-    on dynamic loading.
-
-    """
-    kw["lazy"] = "dynamic"
-    return relationship(argument, **kw)
-
-
-column_property = public_factory(ColumnProperty, ".orm.column_property")
-composite = public_factory(CompositeProperty, ".orm.composite")
-
-
-def backref(name, **kwargs):
-    """Create a back reference with explicit keyword arguments, which are the
-    same arguments one can send to :func:`relationship`.
-
-    Used with the ``backref`` keyword argument to :func:`relationship` in
-    place of a string argument, e.g.::
-
-        'items':relationship(
-            SomeItem, backref=backref('parent', lazy='subquery'))
-
-    .. seealso::
-
-        :ref:`relationships_backref`
-
-    """
-
-    return (name, kwargs)
-
-
-def deferred(*columns, **kw):
-    r"""Indicate a column-based mapped attribute that by default will
-    not load unless accessed.
-
-    :param \*columns: columns to be mapped.  This is typically a single
-     :class:`_schema.Column` object,
-     however a collection is supported in order
-     to support multiple columns mapped under the same attribute.
-
-    :param raiseload: boolean, if True, indicates an exception should be raised
-     if the load operation is to take place.
-
-     .. versionadded:: 1.4
-
-     .. seealso::
-
-        :ref:`deferred_raiseload`
-
-    :param \**kw: additional keyword arguments passed to
-     :class:`.ColumnProperty`.
-
-    .. seealso::
-
-        :ref:`deferred`
-
-    """
-    return ColumnProperty(deferred=True, *columns, **kw)
-
-
-def query_expression(default_expr=_sql.null()):
-    """Indicate an attribute that populates from a query-time SQL expression.
-
-    :param default_expr: Optional SQL expression object that will be used in
-        all cases if not assigned later with :func:`_orm.with_expression`.
-        E.g.::
-
-            from sqlalchemy.sql import literal
-
-            class C(Base):
-                #...
-                my_expr = query_expression(literal(1))
-
-        .. versionadded:: 1.3.18
-
-
-    .. versionadded:: 1.2
-
-    .. seealso::
-
-        :ref:`mapper_querytime_expression`
-
-    """
-    prop = ColumnProperty(default_expr)
-    prop.strategy_key = (("query_expression", True),)
-    return prop
-
-
-synonym = public_factory(SynonymProperty, ".orm.synonym")
-
-
-def clear_mappers():
-    """Remove all mappers from all classes.
-
-    .. versionchanged:: 1.4  This function now locates all
-       :class:`_orm.registry` objects and calls upon the
-       :meth:`_orm.registry.dispose` method of each.
-
-    This function removes all instrumentation from classes and disposes
-    of their associated mappers.  Once called, the classes are unmapped
-    and can be later re-mapped with new mappers.
-
-    :func:`.clear_mappers` is *not* for normal use, as there is literally no
-    valid usage for it outside of very specific testing scenarios. Normally,
-    mappers are permanent structural components of user-defined classes, and
-    are never discarded independently of their class.  If a mapped class
-    itself is garbage collected, its mapper is automatically disposed of as
-    well. As such, :func:`.clear_mappers` is only for usage in test suites
-    that re-use the same classes with different mappings, which is itself an
-    extremely rare use case - the only such use case is in fact SQLAlchemy's
-    own test suite, and possibly the test suites of other ORM extension
-    libraries which intend to test various combinations of mapper construction
-    upon a fixed set of classes.
-
-    """
-
-    mapperlib._dispose_registries(mapperlib._all_registries(), False)
-
-
-contains_alias = public_factory(AliasOption, ".orm.contains_alias")
-
-if True:
-    from .events import AttributeEvents
-    from .events import MapperEvents
-    from .events import InstanceEvents
-    from .events import InstrumentationEvents
-    from .events import QueryEvents
-    from .events import SessionEvents
 
 
 def __go(lcls):
-    global __all__
-    global AppenderQuery
-    from .. import util as sa_util
-    from . import dynamic
-    from . import events
-    from . import loading
-    import inspect as _inspect
-
-    from .dynamic import AppenderQuery
-
-    __all__ = sorted(
-        name
-        for name, obj in lcls.items()
-        if not (name.startswith("_") or _inspect.ismodule(obj))
-    )
 
     _sa_util.preloaded.import_prefix("sqlalchemy.orm")
     _sa_util.preloaded.import_prefix("sqlalchemy.ext")
diff --git a/lib/sqlalchemy/orm/_orm_constructors.py b/lib/sqlalchemy/orm/_orm_constructors.py
new file mode 100644 (file)
index 0000000..be0d23d
--- /dev/null
@@ -0,0 +1,1557 @@
+# orm/_orm_constructors.py
+# Copyright (C) 2005-2022 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
+
+import typing
+from typing import Callable
+from typing import Type
+from typing import Union
+
+from . import mapper as mapperlib
+from .descriptor_props import CompositeProperty
+from .descriptor_props import SynonymProperty
+from .properties import ColumnProperty
+from .query import AliasOption
+from .relationships import RelationshipProperty
+from .session import Session
+from .util import LoaderCriteriaOption
+from .. import sql
+from .. import util
+from ..exc import InvalidRequestError
+
+_RC = typing.TypeVar("_RC")
+_T = typing.TypeVar("_T")
+
+
+@util.deprecated(
+    "1.4",
+    "The :class:`.AliasOption` object is not necessary "
+    "for entities to be matched up to a query that is established "
+    "via :meth:`.Query.from_statement` and now does nothing.",
+)
+def contains_alias(alias) -> "AliasOption":
+    r"""Return a :class:`.MapperOption` that will indicate to the
+    :class:`_query.Query`
+    that the main table has been aliased.
+
+    """
+    return AliasOption(alias)
+
+
+def column_property(
+    column: sql.ColumnElement[_T], *additional_columns, **kwargs
+) -> "ColumnProperty[_T]":
+    r"""Provide a column-level property for use with a mapping.
+
+    Column-based properties can normally be applied to the mapper's
+    ``properties`` dictionary using the :class:`_schema.Column`
+    element directly.
+    Use this function when the given column is not directly present within
+    the mapper's selectable; examples include SQL expressions, functions,
+    and scalar SELECT queries.
+
+    The :func:`_orm.column_property` function returns an instance of
+    :class:`.ColumnProperty`.
+
+    Columns that aren't present in the mapper's selectable won't be
+    persisted by the mapper and are effectively "read-only" attributes.
+
+    :param \*cols:
+          list of Column objects to be mapped.
+
+    :param active_history=False:
+      When ``True``, indicates that the "previous" value for a
+      scalar attribute should be loaded when replaced, if not
+      already loaded. Normally, history tracking logic for
+      simple non-primary-key scalar values only needs to be
+      aware of the "new" value in order to perform a flush. This
+      flag is available for applications that make use of
+      :func:`.attributes.get_history` or :meth:`.Session.is_modified`
+      which also need to know
+      the "previous" value of the attribute.
+
+    :param comparator_factory: a class which extends
+       :class:`.ColumnProperty.Comparator` which provides custom SQL
+       clause generation for comparison operations.
+
+    :param group:
+        a group name for this property when marked as deferred.
+
+    :param deferred:
+          when True, the column property is "deferred", meaning that
+          it does not load immediately, and is instead loaded when the
+          attribute is first accessed on an instance.  See also
+          :func:`~sqlalchemy.orm.deferred`.
+
+    :param doc:
+          optional string that will be applied as the doc on the
+          class-bound descriptor.
+
+    :param expire_on_flush=True:
+        Disable expiry on flush.   A column_property() which refers
+        to a SQL expression (and not a single table-bound column)
+        is considered to be a "read only" property; populating it
+        has no effect on the state of data, and it can only return
+        database state.   For this reason a column_property()'s value
+        is expired whenever the parent object is involved in a
+        flush, that is, has any kind of "dirty" state within a flush.
+        Setting this parameter to ``False`` will have the effect of
+        leaving any existing value present after the flush proceeds.
+        Note however that the :class:`.Session` with default expiration
+        settings still expires
+        all attributes after a :meth:`.Session.commit` call, however.
+
+    :param info: Optional data dictionary which will be populated into the
+        :attr:`.MapperProperty.info` attribute of this object.
+
+    :param raiseload: if True, indicates the column should raise an error
+        when undeferred, rather than loading the value.  This can be
+        altered at query time by using the :func:`.deferred` option with
+        raiseload=False.
+
+        .. versionadded:: 1.4
+
+        .. seealso::
+
+            :ref:`deferred_raiseload`
+
+    .. seealso::
+
+        :ref:`column_property_options` - to map columns while including
+        mapping options
+
+        :ref:`mapper_column_property_sql_expressions` - to map SQL
+        expressions
+
+    """
+    return ColumnProperty(column, *additional_columns, **kwargs)
+
+
+def composite(class_: Type[_T], *attrs, **kwargs) -> "CompositeProperty[_T]":
+    r"""Return a composite column-based property for use with a Mapper.
+
+    See the mapping documentation section :ref:`mapper_composite` for a
+    full usage example.
+
+    The :class:`.MapperProperty` returned by :func:`.composite`
+    is the :class:`.CompositeProperty`.
+
+    :param class\_:
+      The "composite type" class, or any classmethod or callable which
+      will produce a new instance of the composite object given the
+      column values in order.
+
+    :param \*cols:
+      List of Column objects to be mapped.
+
+    :param active_history=False:
+      When ``True``, indicates that the "previous" value for a
+      scalar attribute should be loaded when replaced, if not
+      already loaded.  See the same flag on :func:`.column_property`.
+
+    :param group:
+      A group name for this property when marked as deferred.
+
+    :param deferred:
+      When True, the column property is "deferred", meaning that it does
+      not load immediately, and is instead loaded when the attribute is
+      first accessed on an instance.  See also
+      :func:`~sqlalchemy.orm.deferred`.
+
+    :param comparator_factory:  a class which extends
+      :class:`.CompositeProperty.Comparator` which provides custom SQL
+      clause generation for comparison operations.
+
+    :param doc:
+      optional string that will be applied as the doc on the
+      class-bound descriptor.
+
+    :param info: Optional data dictionary which will be populated into the
+        :attr:`.MapperProperty.info` attribute of this object.
+
+    """
+    return CompositeProperty(class_, *attrs, **kwargs)
+
+
+def with_loader_criteria(
+    entity_or_base,
+    where_criteria,
+    loader_only=False,
+    include_aliases=False,
+    propagate_to_loaders=True,
+    track_closure_variables=True,
+) -> "LoaderCriteriaOption":
+    """Add additional WHERE criteria to the load for all occurrences of
+    a particular entity.
+
+    .. versionadded:: 1.4
+
+    The :func:`_orm.with_loader_criteria` option is intended to add
+    limiting criteria to a particular kind of entity in a query,
+    **globally**, meaning it will apply to the entity as it appears
+    in the SELECT query as well as within any subqueries, join
+    conditions, and relationship loads, including both eager and lazy
+    loaders, without the need for it to be specified in any particular
+    part of the query.    The rendering logic uses the same system used by
+    single table inheritance to ensure a certain discriminator is applied
+    to a table.
+
+    E.g., using :term:`2.0-style` queries, we can limit the way the
+    ``User.addresses`` collection is loaded, regardless of the kind
+    of loading used::
+
+        from sqlalchemy.orm import with_loader_criteria
+
+        stmt = select(User).options(
+            selectinload(User.addresses),
+            with_loader_criteria(Address, Address.email_address != 'foo'))
+        )
+
+    Above, the "selectinload" for ``User.addresses`` will apply the
+    given filtering criteria to the WHERE clause.
+
+    Another example, where the filtering will be applied to the
+    ON clause of the join, in this example using :term:`1.x style`
+    queries::
+
+        q = session.query(User).outerjoin(User.addresses).options(
+            with_loader_criteria(Address, Address.email_address != 'foo'))
+        )
+
+    The primary purpose of :func:`_orm.with_loader_criteria` is to use
+    it in the :meth:`_orm.SessionEvents.do_orm_execute` event handler
+    to ensure that all occurrences of a particular entity are filtered
+    in a certain way, such as filtering for access control roles.    It
+    also can be used to apply criteria to relationship loads.  In the
+    example below, we can apply a certain set of rules to all queries
+    emitted by a particular :class:`_orm.Session`::
+
+        session = Session(bind=engine)
+
+        @event.listens_for("do_orm_execute", session)
+        def _add_filtering_criteria(execute_state):
+
+            if (
+                execute_state.is_select
+                and not execute_state.is_column_load
+                and not execute_state.is_relationship_load
+            ):
+                execute_state.statement = execute_state.statement.options(
+                    with_loader_criteria(
+                        SecurityRole,
+                        lambda cls: cls.role.in_(['some_role']),
+                        include_aliases=True
+                    )
+                )
+
+    In the above example, the :meth:`_orm.SessionEvents.do_orm_execute`
+    event will intercept all queries emitted using the
+    :class:`_orm.Session`. For those queries which are SELECT statements
+    and are not attribute or relationship loads a custom
+    :func:`_orm.with_loader_criteria` option is added to the query.    The
+    :func:`_orm.with_loader_criteria` option will be used in the given
+    statement and will also be automatically propagated to all relationship
+    loads that descend from this query.
+
+    The criteria argument given is a ``lambda`` that accepts a ``cls``
+    argument.  The given class will expand to include all mapped subclass
+    and need not itself be a mapped class.
+
+    .. tip::
+
+       When using :func:`_orm.with_loader_criteria` option in
+       conjunction with the :func:`_orm.contains_eager` loader option,
+       it's important to note that :func:`_orm.with_loader_criteria` only
+       affects the part of the query that determines what SQL is rendered
+       in terms of the WHERE and FROM clauses. The
+       :func:`_orm.contains_eager` option does not affect the rendering of
+       the SELECT statement outside of the columns clause, so does not have
+       any interaction with the :func:`_orm.with_loader_criteria` option.
+       However, the way things "work" is that :func:`_orm.contains_eager`
+       is meant to be used with a query that is already selecting from the
+       additional entities in some way, where
+       :func:`_orm.with_loader_criteria` can apply it's additional
+       criteria.
+
+       In the example below, assuming a mapping relationship as
+       ``A -> A.bs -> B``, the given :func:`_orm.with_loader_criteria`
+       option will affect the way in which the JOIN is rendered::
+
+            stmt = select(A).join(A.bs).options(
+                contains_eager(A.bs),
+                with_loader_criteria(B, B.flag == 1)
+            )
+
+       Above, the given :func:`_orm.with_loader_criteria` option will
+       affect the ON clause of the JOIN that is specified by
+       ``.join(A.bs)``, so is applied as expected. The
+       :func:`_orm.contains_eager` option has the effect that columns from
+       ``B`` are added to the columns clause::
+
+            SELECT
+                b.id, b.a_id, b.data, b.flag,
+                a.id AS id_1,
+                a.data AS data_1
+            FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
+
+
+       The use of the :func:`_orm.contains_eager` option within the above
+       statement has no effect on the behavior of the
+       :func:`_orm.with_loader_criteria` option. If the
+       :func:`_orm.contains_eager` option were omitted, the SQL would be
+       the same as regards the FROM and WHERE clauses, where
+       :func:`_orm.with_loader_criteria` continues to add its criteria to
+       the ON clause of the JOIN. The addition of
+       :func:`_orm.contains_eager` only affects the columns clause, in that
+       additional columns against ``b`` are added which are then consumed
+       by the ORM to produce ``B`` instances.
+
+    .. warning:: The use of a lambda inside of the call to
+      :func:`_orm.with_loader_criteria` is only invoked **once per unique
+      class**. Custom functions should not be invoked within this lambda.
+      See :ref:`engine_lambda_caching` for an overview of the "lambda SQL"
+      feature, which is for advanced use only.
+
+    :param entity_or_base: a mapped class, or a class that is a super
+     class of a particular set of mapped classes, to which the rule
+     will apply.
+
+    :param where_criteria: a Core SQL expression that applies limiting
+     criteria.   This may also be a "lambda:" or Python function that
+     accepts a target class as an argument, when the given class is
+     a base with many different mapped subclasses.
+
+    :param include_aliases: if True, apply the rule to :func:`_orm.aliased`
+     constructs as well.
+
+    :param propagate_to_loaders: defaults to True, apply to relationship
+     loaders such as lazy loaders.
+
+
+     .. seealso::
+
+        :ref:`examples_session_orm_events` - includes examples of using
+        :func:`_orm.with_loader_criteria`.
+
+        :ref:`do_orm_execute_global_criteria` - basic example on how to
+        combine :func:`_orm.with_loader_criteria` with the
+        :meth:`_orm.SessionEvents.do_orm_execute` event.
+
+    :param track_closure_variables: when False, closure variables inside
+     of a lambda expression will not be used as part of
+     any cache key.    This allows more complex expressions to be used
+     inside of a lambda expression but requires that the lambda ensures
+     it returns the identical SQL every time given a particular class.
+
+     .. versionadded:: 1.4.0b2
+
+    """
+    return LoaderCriteriaOption(
+        entity_or_base,
+        where_criteria,
+        loader_only,
+        include_aliases,
+        propagate_to_loaders,
+        track_closure_variables,
+    )
+
+
+def relationship(
+    argument: Union[str, Type[_RC], Callable[[], Type[_RC]]],
+    secondary=None,
+    primaryjoin=None,
+    secondaryjoin=None,
+    foreign_keys=None,
+    uselist=None,
+    order_by=False,
+    backref=None,
+    back_populates=None,
+    overlaps=None,
+    post_update=False,
+    cascade=False,
+    viewonly=False,
+    lazy="select",
+    collection_class=None,
+    passive_deletes=RelationshipProperty._persistence_only["passive_deletes"],
+    passive_updates=RelationshipProperty._persistence_only["passive_updates"],
+    remote_side=None,
+    enable_typechecks=RelationshipProperty._persistence_only[
+        "enable_typechecks"
+    ],
+    join_depth=None,
+    comparator_factory=None,
+    single_parent=False,
+    innerjoin=False,
+    distinct_target_key=None,
+    doc=None,
+    active_history=RelationshipProperty._persistence_only["active_history"],
+    cascade_backrefs=RelationshipProperty._persistence_only[
+        "cascade_backrefs"
+    ],
+    load_on_pending=False,
+    bake_queries=True,
+    _local_remote_pairs=None,
+    query_class=None,
+    info=None,
+    omit_join=None,
+    sync_backref=None,
+    _legacy_inactive_history_style=False,
+) -> RelationshipProperty[_RC]:
+    """Provide a relationship between two mapped classes.
+
+    This corresponds to a parent-child or associative table relationship.
+    The constructed class is an instance of
+    :class:`.RelationshipProperty`.
+
+    A typical :func:`_orm.relationship`, used in a classical mapping::
+
+       mapper(Parent, properties={
+         'children': relationship(Child)
+       })
+
+    Some arguments accepted by :func:`_orm.relationship`
+    optionally accept a
+    callable function, which when called produces the desired value.
+    The callable is invoked by the parent :class:`_orm.Mapper` at "mapper
+    initialization" time, which happens only when mappers are first used,
+    and is assumed to be after all mappings have been constructed.  This
+    can be used to resolve order-of-declaration and other dependency
+    issues, such as if ``Child`` is declared below ``Parent`` in the same
+    file::
+
+        mapper(Parent, properties={
+            "children":relationship(lambda: Child,
+                                order_by=lambda: Child.id)
+        })
+
+    When using the :ref:`declarative_toplevel` extension, the Declarative
+    initializer allows string arguments to be passed to
+    :func:`_orm.relationship`.  These string arguments are converted into
+    callables that evaluate the string as Python code, using the
+    Declarative class-registry as a namespace.  This allows the lookup of
+    related classes to be automatic via their string name, and removes the
+    need for related classes to be imported into the local module space
+    before the dependent classes have been declared.  It is still required
+    that the modules in which these related classes appear are imported
+    anywhere in the application at some point before the related mappings
+    are actually used, else a lookup error will be raised when the
+    :func:`_orm.relationship`
+    attempts to resolve the string reference to the
+    related class.    An example of a string- resolved class is as
+    follows::
+
+        from sqlalchemy.ext.declarative import declarative_base
+
+        Base = declarative_base()
+
+        class Parent(Base):
+            __tablename__ = 'parent'
+            id = Column(Integer, primary_key=True)
+            children = relationship("Child", order_by="Child.id")
+
+    .. seealso::
+
+      :ref:`relationship_config_toplevel` - Full introductory and
+      reference documentation for :func:`_orm.relationship`.
+
+      :ref:`orm_tutorial_relationship` - ORM tutorial introduction.
+
+    :param argument:
+      A mapped class, or actual :class:`_orm.Mapper` instance,
+      representing
+      the target of the relationship.
+
+      :paramref:`_orm.relationship.argument`
+      may also be passed as a callable
+      function which is evaluated at mapper initialization time, and may
+      be passed as a string name when using Declarative.
+
+      .. warning:: Prior to SQLAlchemy 1.3.16, this value is interpreted
+         using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      .. versionchanged 1.3.16::
+
+         The string evaluation of the main "argument" no longer accepts an
+         open ended Python expression, instead only accepting a string
+         class name or dotted package-qualified name.
+
+      .. seealso::
+
+        :ref:`declarative_configuring_relationships` - further detail
+        on relationship configuration when using Declarative.
+
+    :param secondary:
+      For a many-to-many relationship, specifies the intermediary
+      table, and is typically an instance of :class:`_schema.Table`.
+      In less common circumstances, the argument may also be specified
+      as an :class:`_expression.Alias` construct, or even a
+      :class:`_expression.Join` construct.
+
+      :paramref:`_orm.relationship.secondary` may
+      also be passed as a callable function which is evaluated at
+      mapper initialization time.  When using Declarative, it may also
+      be a string argument noting the name of a :class:`_schema.Table`
+      that is
+      present in the :class:`_schema.MetaData`
+      collection associated with the
+      parent-mapped :class:`_schema.Table`.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      The :paramref:`_orm.relationship.secondary` keyword argument is
+      typically applied in the case where the intermediary
+      :class:`_schema.Table`
+      is not otherwise expressed in any direct class mapping. If the
+      "secondary" table is also explicitly mapped elsewhere (e.g. as in
+      :ref:`association_pattern`), one should consider applying the
+      :paramref:`_orm.relationship.viewonly` flag so that this
+      :func:`_orm.relationship`
+      is not used for persistence operations which
+      may conflict with those of the association object pattern.
+
+      .. seealso::
+
+          :ref:`relationships_many_to_many` - Reference example of "many
+          to many".
+
+          :ref:`orm_tutorial_many_to_many` - ORM tutorial introduction to
+          many-to-many relationships.
+
+          :ref:`self_referential_many_to_many` - Specifics on using
+          many-to-many in a self-referential case.
+
+          :ref:`declarative_many_to_many` - Additional options when using
+          Declarative.
+
+          :ref:`association_pattern` - an alternative to
+          :paramref:`_orm.relationship.secondary`
+          when composing association
+          table relationships, allowing additional attributes to be
+          specified on the association table.
+
+          :ref:`composite_secondary_join` - a lesser-used pattern which
+          in some cases can enable complex :func:`_orm.relationship` SQL
+          conditions to be used.
+
+      .. versionadded:: 0.9.2 :paramref:`_orm.relationship.secondary`
+         works
+         more effectively when referring to a :class:`_expression.Join`
+         instance.
+
+    :param active_history=False:
+      When ``True``, indicates that the "previous" value for a
+      many-to-one reference should be loaded when replaced, if
+      not already loaded. Normally, history tracking logic for
+      simple many-to-ones only needs to be aware of the "new"
+      value in order to perform a flush. This flag is available
+      for applications that make use of
+      :func:`.attributes.get_history` which also need to know
+      the "previous" value of the attribute.
+
+    :param backref:
+      Indicates the string name of a property to be placed on the related
+      mapper's class that will handle this relationship in the other
+      direction. The other property will be created automatically
+      when the mappers are configured.  Can also be passed as a
+      :func:`.backref` object to control the configuration of the
+      new relationship.
+
+      .. seealso::
+
+        :ref:`relationships_backref` - Introductory documentation and
+        examples.
+
+        :paramref:`_orm.relationship.back_populates` - alternative form
+        of backref specification.
+
+        :func:`.backref` - allows control over :func:`_orm.relationship`
+        configuration when using :paramref:`_orm.relationship.backref`.
+
+
+    :param back_populates:
+      Takes a string name and has the same meaning as
+      :paramref:`_orm.relationship.backref`, except the complementing
+      property is **not** created automatically, and instead must be
+      configured explicitly on the other mapper.  The complementing
+      property should also indicate
+      :paramref:`_orm.relationship.back_populates` to this relationship to
+      ensure proper functioning.
+
+      .. seealso::
+
+        :ref:`relationships_backref` - Introductory documentation and
+        examples.
+
+        :paramref:`_orm.relationship.backref` - alternative form
+        of backref specification.
+
+    :param overlaps:
+       A string name or comma-delimited set of names of other relationships
+       on either this mapper, a descendant mapper, or a target mapper with
+       which this relationship may write to the same foreign keys upon
+       persistence.   The only effect this has is to eliminate the
+       warning that this relationship will conflict with another upon
+       persistence.   This is used for such relationships that are truly
+       capable of conflicting with each other on write, but the application
+       will ensure that no such conflicts occur.
+
+       .. versionadded:: 1.4
+
+       .. seealso::
+
+            :ref:`error_qzyx` - usage example
+
+    :param bake_queries=True:
+      Enable :ref:`lambda caching <engine_lambda_caching>` for loader
+      strategies, if applicable, which adds a performance gain to the
+      construction of SQL constructs used by loader strategies, in addition
+      to the usual SQL statement caching used throughout SQLAlchemy. This
+      parameter currently applies only to the "lazy" and "selectin" loader
+      strategies. There is generally no reason to set this parameter to
+      False.
+
+      .. versionchanged:: 1.4  Relationship loaders no longer use the
+         previous "baked query" system of query caching.   The "lazy"
+         and "selectin" loaders make use of the "lambda cache" system
+         for the construction of SQL constructs,
+         as well as the usual SQL caching system that is throughout
+         SQLAlchemy as of the 1.4 series.
+
+    :param cascade:
+      A comma-separated list of cascade rules which determines how
+      Session operations should be "cascaded" from parent to child.
+      This defaults to ``False``, which means the default cascade
+      should be used - this default cascade is ``"save-update, merge"``.
+
+      The available cascades are ``save-update``, ``merge``,
+      ``expunge``, ``delete``, ``delete-orphan``, and ``refresh-expire``.
+      An additional option, ``all`` indicates shorthand for
+      ``"save-update, merge, refresh-expire,
+      expunge, delete"``, and is often used as in ``"all, delete-orphan"``
+      to indicate that related objects should follow along with the
+      parent object in all cases, and be deleted when de-associated.
+
+      .. seealso::
+
+        :ref:`unitofwork_cascades` - Full detail on each of the available
+        cascade options.
+
+        :ref:`tutorial_delete_cascade` - Tutorial example describing
+        a delete cascade.
+
+    :param cascade_backrefs=False:
+      Legacy; this flag is always False.
+
+      .. versionchanged:: 2.0 "cascade_backrefs" functionality has been
+         removed.
+
+    :param collection_class:
+      A class or callable that returns a new list-holding object. will
+      be used in place of a plain list for storing elements.
+
+      .. seealso::
+
+        :ref:`custom_collections` - Introductory documentation and
+        examples.
+
+    :param comparator_factory:
+      A class which extends :class:`.RelationshipProperty.Comparator`
+      which provides custom SQL clause generation for comparison
+      operations.
+
+      .. seealso::
+
+        :class:`.PropComparator` - some detail on redefining comparators
+        at this level.
+
+        :ref:`custom_comparators` - Brief intro to this feature.
+
+
+    :param distinct_target_key=None:
+      Indicate if a "subquery" eager load should apply the DISTINCT
+      keyword to the innermost SELECT statement.  When left as ``None``,
+      the DISTINCT keyword will be applied in those cases when the target
+      columns do not comprise the full primary key of the target table.
+      When set to ``True``, the DISTINCT keyword is applied to the
+      innermost SELECT unconditionally.
+
+      It may be desirable to set this flag to False when the DISTINCT is
+      reducing performance of the innermost subquery beyond that of what
+      duplicate innermost rows may be causing.
+
+      .. versionchanged:: 0.9.0 -
+         :paramref:`_orm.relationship.distinct_target_key` now defaults to
+         ``None``, so that the feature enables itself automatically for
+         those cases where the innermost query targets a non-unique
+         key.
+
+      .. seealso::
+
+        :ref:`loading_toplevel` - includes an introduction to subquery
+        eager loading.
+
+    :param doc:
+      Docstring which will be applied to the resulting descriptor.
+
+    :param foreign_keys:
+
+      A list of columns which are to be used as "foreign key"
+      columns, or columns which refer to the value in a remote
+      column, within the context of this :func:`_orm.relationship`
+      object's :paramref:`_orm.relationship.primaryjoin` condition.
+      That is, if the :paramref:`_orm.relationship.primaryjoin`
+      condition of this :func:`_orm.relationship` is ``a.id ==
+      b.a_id``, and the values in ``b.a_id`` are required to be
+      present in ``a.id``, then the "foreign key" column of this
+      :func:`_orm.relationship` is ``b.a_id``.
+
+      In normal cases, the :paramref:`_orm.relationship.foreign_keys`
+      parameter is **not required.** :func:`_orm.relationship` will
+      automatically determine which columns in the
+      :paramref:`_orm.relationship.primaryjoin` condition are to be
+      considered "foreign key" columns based on those
+      :class:`_schema.Column` objects that specify
+      :class:`_schema.ForeignKey`,
+      or are otherwise listed as referencing columns in a
+      :class:`_schema.ForeignKeyConstraint` construct.
+      :paramref:`_orm.relationship.foreign_keys` is only needed when:
+
+        1. There is more than one way to construct a join from the local
+           table to the remote table, as there are multiple foreign key
+           references present.  Setting ``foreign_keys`` will limit the
+           :func:`_orm.relationship`
+           to consider just those columns specified
+           here as "foreign".
+
+        2. The :class:`_schema.Table` being mapped does not actually have
+           :class:`_schema.ForeignKey` or
+           :class:`_schema.ForeignKeyConstraint`
+           constructs present, often because the table
+           was reflected from a database that does not support foreign key
+           reflection (MySQL MyISAM).
+
+        3. The :paramref:`_orm.relationship.primaryjoin`
+           argument is used to
+           construct a non-standard join condition, which makes use of
+           columns or expressions that do not normally refer to their
+           "parent" column, such as a join condition expressed by a
+           complex comparison using a SQL function.
+
+      The :func:`_orm.relationship` construct will raise informative
+      error messages that suggest the use of the
+      :paramref:`_orm.relationship.foreign_keys` parameter when
+      presented with an ambiguous condition.   In typical cases,
+      if :func:`_orm.relationship` doesn't raise any exceptions, the
+      :paramref:`_orm.relationship.foreign_keys` parameter is usually
+      not needed.
+
+      :paramref:`_orm.relationship.foreign_keys` may also be passed as a
+      callable function which is evaluated at mapper initialization time,
+      and may be passed as a Python-evaluable string when using
+      Declarative.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      .. seealso::
+
+        :ref:`relationship_foreign_keys`
+
+        :ref:`relationship_custom_foreign`
+
+        :func:`.foreign` - allows direct annotation of the "foreign"
+        columns within a :paramref:`_orm.relationship.primaryjoin`
+        condition.
+
+    :param info: Optional data dictionary which will be populated into the
+        :attr:`.MapperProperty.info` attribute of this object.
+
+    :param innerjoin=False:
+      When ``True``, joined eager loads will use an inner join to join
+      against related tables instead of an outer join.  The purpose
+      of this option is generally one of performance, as inner joins
+      generally perform better than outer joins.
+
+      This flag can be set to ``True`` when the relationship references an
+      object via many-to-one using local foreign keys that are not
+      nullable, or when the reference is one-to-one or a collection that
+      is guaranteed to have one or at least one entry.
+
+      The option supports the same "nested" and "unnested" options as
+      that of :paramref:`_orm.joinedload.innerjoin`.  See that flag
+      for details on nested / unnested behaviors.
+
+      .. seealso::
+
+        :paramref:`_orm.joinedload.innerjoin` - the option as specified by
+        loader option, including detail on nesting behavior.
+
+        :ref:`what_kind_of_loading` - Discussion of some details of
+        various loader options.
+
+
+    :param join_depth:
+      When non-``None``, an integer value indicating how many levels
+      deep "eager" loaders should join on a self-referring or cyclical
+      relationship.  The number counts how many times the same Mapper
+      shall be present in the loading condition along a particular join
+      branch.  When left at its default of ``None``, eager loaders
+      will stop chaining when they encounter a the same target mapper
+      which is already higher up in the chain.  This option applies
+      both to joined- and subquery- eager loaders.
+
+      .. seealso::
+
+        :ref:`self_referential_eager_loading` - Introductory documentation
+        and examples.
+
+    :param lazy='select': specifies
+      How the related items should be loaded.  Default value is
+      ``select``.  Values include:
+
+      * ``select`` - items should be loaded lazily when the property is
+        first accessed, using a separate SELECT statement, or identity map
+        fetch for simple many-to-one references.
+
+      * ``immediate`` - items should be loaded as the parents are loaded,
+        using a separate SELECT statement, or identity map fetch for
+        simple many-to-one references.
+
+      * ``joined`` - items should be loaded "eagerly" in the same query as
+        that of the parent, using a JOIN or LEFT OUTER JOIN.  Whether
+        the join is "outer" or not is determined by the
+        :paramref:`_orm.relationship.innerjoin` parameter.
+
+      * ``subquery`` - items should be loaded "eagerly" as the parents are
+        loaded, using one additional SQL statement, which issues a JOIN to
+        a subquery of the original statement, for each collection
+        requested.
+
+      * ``selectin`` - items should be loaded "eagerly" as the parents
+        are loaded, using one or more additional SQL statements, which
+        issues a JOIN to the immediate parent object, specifying primary
+        key identifiers using an IN clause.
+
+        .. versionadded:: 1.2
+
+      * ``noload`` - no loading should occur at any time.  This is to
+        support "write-only" attributes, or attributes which are
+        populated in some manner specific to the application.
+
+      * ``raise`` - lazy loading is disallowed; accessing
+        the attribute, if its value were not already loaded via eager
+        loading, will raise an :exc:`~sqlalchemy.exc.InvalidRequestError`.
+        This strategy can be used when objects are to be detached from
+        their attached :class:`.Session` after they are loaded.
+
+        .. versionadded:: 1.1
+
+      * ``raise_on_sql`` - lazy loading that emits SQL is disallowed;
+        accessing the attribute, if its value were not already loaded via
+        eager loading, will raise an
+        :exc:`~sqlalchemy.exc.InvalidRequestError`, **if the lazy load
+        needs to emit SQL**.  If the lazy load can pull the related value
+        from the identity map or determine that it should be None, the
+        value is loaded.  This strategy can be used when objects will
+        remain associated with the attached :class:`.Session`, however
+        additional SELECT statements should be blocked.
+
+        .. versionadded:: 1.1
+
+      * ``dynamic`` - the attribute will return a pre-configured
+        :class:`_query.Query` object for all read
+        operations, onto which further filtering operations can be
+        applied before iterating the results.  See
+        the section :ref:`dynamic_relationship` for more details.
+
+      * True - a synonym for 'select'
+
+      * False - a synonym for 'joined'
+
+      * None - a synonym for 'noload'
+
+      .. seealso::
+
+        :doc:`/orm/loading_relationships` - Full documentation on
+        relationship loader configuration.
+
+        :ref:`dynamic_relationship` - detail on the ``dynamic`` option.
+
+        :ref:`collections_noload_raiseload` - notes on "noload" and "raise"
+
+    :param load_on_pending=False:
+      Indicates loading behavior for transient or pending parent objects.
+
+      When set to ``True``, causes the lazy-loader to
+      issue a query for a parent object that is not persistent, meaning it
+      has never been flushed.  This may take effect for a pending object
+      when autoflush is disabled, or for a transient object that has been
+      "attached" to a :class:`.Session` but is not part of its pending
+      collection.
+
+      The :paramref:`_orm.relationship.load_on_pending`
+      flag does not improve
+      behavior when the ORM is used normally - object references should be
+      constructed at the object level, not at the foreign key level, so
+      that they are present in an ordinary way before a flush proceeds.
+      This flag is not not intended for general use.
+
+      .. seealso::
+
+          :meth:`.Session.enable_relationship_loading` - this method
+          establishes "load on pending" behavior for the whole object, and
+          also allows loading on objects that remain transient or
+          detached.
+
+    :param order_by:
+      Indicates the ordering that should be applied when loading these
+      items.  :paramref:`_orm.relationship.order_by`
+      is expected to refer to
+      one of the :class:`_schema.Column`
+      objects to which the target class is
+      mapped, or the attribute itself bound to the target class which
+      refers to the column.
+
+      :paramref:`_orm.relationship.order_by`
+      may also be passed as a callable
+      function which is evaluated at mapper initialization time, and may
+      be passed as a Python-evaluable string when using Declarative.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+    :param passive_deletes=False:
+       Indicates loading behavior during delete operations.
+
+       A value of True indicates that unloaded child items should not
+       be loaded during a delete operation on the parent.  Normally,
+       when a parent item is deleted, all child items are loaded so
+       that they can either be marked as deleted, or have their
+       foreign key to the parent set to NULL.  Marking this flag as
+       True usually implies an ON DELETE <CASCADE|SET NULL> rule is in
+       place which will handle updating/deleting child rows on the
+       database side.
+
+       Additionally, setting the flag to the string value 'all' will
+       disable the "nulling out" of the child foreign keys, when the parent
+       object is deleted and there is no delete or delete-orphan cascade
+       enabled.  This is typically used when a triggering or error raise
+       scenario is in place on the database side.  Note that the foreign
+       key attributes on in-session child objects will not be changed after
+       a flush occurs so this is a very special use-case setting.
+       Additionally, the "nulling out" will still occur if the child
+       object is de-associated with the parent.
+
+       .. seealso::
+
+            :ref:`passive_deletes` - Introductory documentation
+            and examples.
+
+    :param passive_updates=True:
+      Indicates the persistence behavior to take when a referenced
+      primary key value changes in place, indicating that the referencing
+      foreign key columns will also need their value changed.
+
+      When True, it is assumed that ``ON UPDATE CASCADE`` is configured on
+      the foreign key in the database, and that the database will
+      handle propagation of an UPDATE from a source column to
+      dependent rows.  When False, the SQLAlchemy
+      :func:`_orm.relationship`
+      construct will attempt to emit its own UPDATE statements to
+      modify related targets.  However note that SQLAlchemy **cannot**
+      emit an UPDATE for more than one level of cascade.  Also,
+      setting this flag to False is not compatible in the case where
+      the database is in fact enforcing referential integrity, unless
+      those constraints are explicitly "deferred", if the target backend
+      supports it.
+
+      It is highly advised that an application which is employing
+      mutable primary keys keeps ``passive_updates`` set to True,
+      and instead uses the referential integrity features of the database
+      itself in order to handle the change efficiently and fully.
+
+      .. seealso::
+
+          :ref:`passive_updates` - Introductory documentation and
+          examples.
+
+          :paramref:`.mapper.passive_updates` - a similar flag which
+          takes effect for joined-table inheritance mappings.
+
+    :param post_update:
+      This indicates that the relationship should be handled by a
+      second UPDATE statement after an INSERT or before a
+      DELETE. Currently, it also will issue an UPDATE after the
+      instance was UPDATEd as well, although this technically should
+      be improved. This flag is used to handle saving bi-directional
+      dependencies between two individual rows (i.e. each row
+      references the other), where it would otherwise be impossible to
+      INSERT or DELETE both rows fully since one row exists before the
+      other. Use this flag when a particular mapping arrangement will
+      incur two rows that are dependent on each other, such as a table
+      that has a one-to-many relationship to a set of child rows, and
+      also has a column that references a single child row within that
+      list (i.e. both tables contain a foreign key to each other). If
+      a flush operation returns an error that a "cyclical
+      dependency" was detected, this is a cue that you might want to
+      use :paramref:`_orm.relationship.post_update` to "break" the cycle.
+
+      .. seealso::
+
+          :ref:`post_update` - Introductory documentation and examples.
+
+    :param primaryjoin:
+      A SQL expression that will be used as the primary
+      join of the child object against the parent object, or in a
+      many-to-many relationship the join of the parent object to the
+      association table. By default, this value is computed based on the
+      foreign key relationships of the parent and child tables (or
+      association table).
+
+      :paramref:`_orm.relationship.primaryjoin` may also be passed as a
+      callable function which is evaluated at mapper initialization time,
+      and may be passed as a Python-evaluable string when using
+      Declarative.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      .. seealso::
+
+          :ref:`relationship_primaryjoin`
+
+    :param remote_side:
+      Used for self-referential relationships, indicates the column or
+      list of columns that form the "remote side" of the relationship.
+
+      :paramref:`_orm.relationship.remote_side` may also be passed as a
+      callable function which is evaluated at mapper initialization time,
+      and may be passed as a Python-evaluable string when using
+      Declarative.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      .. seealso::
+
+        :ref:`self_referential` - in-depth explanation of how
+        :paramref:`_orm.relationship.remote_side`
+        is used to configure self-referential relationships.
+
+        :func:`.remote` - an annotation function that accomplishes the
+        same purpose as :paramref:`_orm.relationship.remote_side`,
+        typically
+        when a custom :paramref:`_orm.relationship.primaryjoin` condition
+        is used.
+
+    :param query_class:
+      A :class:`_query.Query`
+      subclass that will be used internally by the
+      ``AppenderQuery`` returned by a "dynamic" relationship, that
+      is, a relationship that specifies ``lazy="dynamic"`` or was
+      otherwise constructed using the :func:`_orm.dynamic_loader`
+      function.
+
+      .. seealso::
+
+        :ref:`dynamic_relationship` - Introduction to "dynamic"
+        relationship loaders.
+
+    :param secondaryjoin:
+      A SQL expression that will be used as the join of
+      an association table to the child object. By default, this value is
+      computed based on the foreign key relationships of the association
+      and child tables.
+
+      :paramref:`_orm.relationship.secondaryjoin` may also be passed as a
+      callable function which is evaluated at mapper initialization time,
+      and may be passed as a Python-evaluable string when using
+      Declarative.
+
+      .. warning:: When passed as a Python-evaluable string, the
+         argument is interpreted using Python's ``eval()`` function.
+         **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+         See :ref:`declarative_relationship_eval` for details on
+         declarative evaluation of :func:`_orm.relationship` arguments.
+
+      .. seealso::
+
+          :ref:`relationship_primaryjoin`
+
+    :param single_parent:
+      When True, installs a validator which will prevent objects
+      from being associated with more than one parent at a time.
+      This is used for many-to-one or many-to-many relationships that
+      should be treated either as one-to-one or one-to-many.  Its usage
+      is optional, except for :func:`_orm.relationship` constructs which
+      are many-to-one or many-to-many and also
+      specify the ``delete-orphan`` cascade option.  The
+      :func:`_orm.relationship` construct itself will raise an error
+      instructing when this option is required.
+
+      .. seealso::
+
+        :ref:`unitofwork_cascades` - includes detail on when the
+        :paramref:`_orm.relationship.single_parent`
+        flag may be appropriate.
+
+    :param uselist:
+      A boolean that indicates if this property should be loaded as a
+      list or a scalar. In most cases, this value is determined
+      automatically by :func:`_orm.relationship` at mapper configuration
+      time, based on the type and direction
+      of the relationship - one to many forms a list, many to one
+      forms a scalar, many to many is a list. If a scalar is desired
+      where normally a list would be present, such as a bi-directional
+      one-to-one relationship, set :paramref:`_orm.relationship.uselist`
+      to
+      False.
+
+      The :paramref:`_orm.relationship.uselist`
+      flag is also available on an
+      existing :func:`_orm.relationship`
+      construct as a read-only attribute,
+      which can be used to determine if this :func:`_orm.relationship`
+      deals
+      with collections or scalar attributes::
+
+          >>> User.addresses.property.uselist
+          True
+
+      .. seealso::
+
+          :ref:`relationships_one_to_one` - Introduction to the "one to
+          one" relationship pattern, which is typically when the
+          :paramref:`_orm.relationship.uselist` flag is needed.
+
+    :param viewonly=False:
+      When set to ``True``, the relationship is used only for loading
+      objects, and not for any persistence operation.  A
+      :func:`_orm.relationship` which specifies
+      :paramref:`_orm.relationship.viewonly` can work
+      with a wider range of SQL operations within the
+      :paramref:`_orm.relationship.primaryjoin` condition, including
+      operations that feature the use of a variety of comparison operators
+      as well as SQL functions such as :func:`_expression.cast`.  The
+      :paramref:`_orm.relationship.viewonly`
+      flag is also of general use when defining any kind of
+      :func:`_orm.relationship` that doesn't represent
+      the full set of related objects, to prevent modifications of the
+      collection from resulting in persistence operations.
+
+      When using the :paramref:`_orm.relationship.viewonly` flag in
+      conjunction with backrefs, the originating relationship for a
+      particular state change will not produce state changes within the
+      viewonly relationship.   This is the behavior implied by
+      :paramref:`_orm.relationship.sync_backref` being set to False.
+
+      .. versionchanged:: 1.3.17 - the
+         :paramref:`_orm.relationship.sync_backref` flag is set to False
+             when using viewonly in conjunction with backrefs.
+
+      .. seealso::
+
+        :paramref:`_orm.relationship.sync_backref`
+
+    :param sync_backref:
+      A boolean that enables the events used to synchronize the in-Python
+      attributes when this relationship is target of either
+      :paramref:`_orm.relationship.backref` or
+      :paramref:`_orm.relationship.back_populates`.
+
+      Defaults to ``None``, which indicates that an automatic value should
+      be selected based on the value of the
+      :paramref:`_orm.relationship.viewonly` flag.  When left at its
+      default, changes in state will be back-populated only if neither
+      sides of a relationship is viewonly.
+
+      .. versionadded:: 1.3.17
+
+      .. versionchanged:: 1.4 - A relationship that specifies
+         :paramref:`_orm.relationship.viewonly` automatically implies
+         that :paramref:`_orm.relationship.sync_backref` is ``False``.
+
+      .. seealso::
+
+        :paramref:`_orm.relationship.viewonly`
+
+    :param omit_join:
+      Allows manual control over the "selectin" automatic join
+      optimization.  Set to ``False`` to disable the "omit join" feature
+      added in SQLAlchemy 1.3; or leave as ``None`` to leave automatic
+      optimization in place.
+
+      .. note:: This flag may only be set to ``False``.   It is not
+         necessary to set it to ``True`` as the "omit_join" optimization is
+         automatically detected; if it is not detected, then the
+         optimization is not supported.
+
+         .. versionchanged:: 1.3.11  setting ``omit_join`` to True will now
+            emit a warning as this was not the intended use of this flag.
+
+      .. versionadded:: 1.3
+
+
+    """
+    return RelationshipProperty(
+        argument,
+        secondary,
+        primaryjoin,
+        secondaryjoin,
+        foreign_keys,
+        uselist,
+        order_by,
+        backref,
+        back_populates,
+        overlaps,
+        post_update,
+        cascade,
+        viewonly,
+        lazy,
+        collection_class,
+        passive_deletes,
+        passive_updates,
+        remote_side,
+        enable_typechecks,
+        join_depth,
+        comparator_factory,
+        single_parent,
+        innerjoin,
+        distinct_target_key,
+        doc,
+        active_history,
+        cascade_backrefs,
+        load_on_pending,
+        bake_queries,
+        _local_remote_pairs,
+        query_class,
+        info,
+        omit_join,
+        sync_backref,
+        _legacy_inactive_history_style,
+    )
+
+
+def synonym(
+    name,
+    map_column=None,
+    descriptor=None,
+    comparator_factory=None,
+    doc=None,
+    info=None,
+) -> "SynonymProperty":
+    """Denote an attribute name as a synonym to a mapped property,
+    in that the attribute will mirror the value and expression behavior
+    of another attribute.
+
+    e.g.::
+
+        class MyClass(Base):
+            __tablename__ = 'my_table'
+
+            id = Column(Integer, primary_key=True)
+            job_status = Column(String(50))
+
+            status = synonym("job_status")
+
+
+    :param name: the name of the existing mapped property.  This
+      can refer to the string name ORM-mapped attribute
+      configured on the class, including column-bound attributes
+      and relationships.
+
+    :param descriptor: a Python :term:`descriptor` that will be used
+      as a getter (and potentially a setter) when this attribute is
+      accessed at the instance level.
+
+    :param map_column: **For classical mappings and mappings against
+      an existing Table object only**.  if ``True``, the :func:`.synonym`
+      construct will locate the :class:`_schema.Column`
+      object upon the mapped
+      table that would normally be associated with the attribute name of
+      this synonym, and produce a new :class:`.ColumnProperty` that instead
+      maps this :class:`_schema.Column`
+      to the alternate name given as the "name"
+      argument of the synonym; in this way, the usual step of redefining
+      the mapping of the :class:`_schema.Column`
+      to be under a different name is
+      unnecessary. This is usually intended to be used when a
+      :class:`_schema.Column`
+      is to be replaced with an attribute that also uses a
+      descriptor, that is, in conjunction with the
+      :paramref:`.synonym.descriptor` parameter::
+
+        my_table = Table(
+            "my_table", metadata,
+            Column('id', Integer, primary_key=True),
+            Column('job_status', String(50))
+        )
+
+        class MyClass:
+            @property
+            def _job_status_descriptor(self):
+                return "Status: %s" % self._job_status
+
+
+        mapper(
+            MyClass, my_table, properties={
+                "job_status": synonym(
+                    "_job_status", map_column=True,
+                    descriptor=MyClass._job_status_descriptor)
+            }
+        )
+
+      Above, the attribute named ``_job_status`` is automatically
+      mapped to the ``job_status`` column::
+
+        >>> j1 = MyClass()
+        >>> j1._job_status = "employed"
+        >>> j1.job_status
+        Status: employed
+
+      When using Declarative, in order to provide a descriptor in
+      conjunction with a synonym, use the
+      :func:`sqlalchemy.ext.declarative.synonym_for` helper.  However,
+      note that the :ref:`hybrid properties <mapper_hybrids>` feature
+      should usually be preferred, particularly when redefining attribute
+      behavior.
+
+    :param info: Optional data dictionary which will be populated into the
+        :attr:`.InspectionAttr.info` attribute of this object.
+
+        .. versionadded:: 1.0.0
+
+    :param comparator_factory: A subclass of :class:`.PropComparator`
+      that will provide custom comparison behavior at the SQL expression
+      level.
+
+      .. note::
+
+        For the use case of providing an attribute which redefines both
+        Python-level and SQL-expression level behavior of an attribute,
+        please refer to the Hybrid attribute introduced at
+        :ref:`mapper_hybrids` for a more effective technique.
+
+    .. seealso::
+
+        :ref:`synonyms` - Overview of synonyms
+
+        :func:`.synonym_for` - a helper oriented towards Declarative
+
+        :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
+        updated approach to augmenting attribute behavior more flexibly
+        than can be achieved with synonyms.
+
+    """
+    return SynonymProperty(
+        name, map_column, descriptor, comparator_factory, doc, info
+    )
+
+
+def create_session(bind=None, **kwargs):
+    r"""Create a new :class:`.Session`
+    with no automation enabled by default.
+
+    This function is used primarily for testing.   The usual
+    route to :class:`.Session` creation is via its constructor
+    or the :func:`.sessionmaker` function.
+
+    :param bind: optional, a single Connectable to use for all
+      database access in the created
+      :class:`~sqlalchemy.orm.session.Session`.
+
+    :param \*\*kwargs: optional, passed through to the
+      :class:`.Session` constructor.
+
+    :returns: an :class:`~sqlalchemy.orm.session.Session` instance
+
+    The defaults of create_session() are the opposite of that of
+    :func:`sessionmaker`; ``autoflush`` and ``expire_on_commit`` are
+    False.
+
+    Usage::
+
+      >>> from sqlalchemy.orm import create_session
+      >>> session = create_session()
+
+    It is recommended to use :func:`sessionmaker` instead of
+    create_session().
+
+    """
+
+    kwargs.setdefault("autoflush", False)
+    kwargs.setdefault("expire_on_commit", False)
+    return Session(bind=bind, **kwargs)
+
+
+def _mapper_fn(*arg, **kw):
+    """Placeholder for the now-removed ``mapper()`` function.
+
+    Classical mappings should be performed using the
+    :meth:`_orm.registry.map_imperatively` method.
+
+    This symbol remains in SQLAlchemy 2.0 to suit the deprecated use case
+    of using the ``mapper()`` function as a target for ORM event listeners,
+    which failed to be marked as deprecated in the 1.4 series.
+
+    Global ORM mapper listeners should instead use the :class:`_orm.Mapper`
+    class as the target.
+
+    .. versionchanged:: 2.0  The ``mapper()`` function was removed; the
+       symbol remains temporarily as a placeholder for the event listening
+       use case.
+
+    """
+    raise InvalidRequestError(
+        "The 'sqlalchemy.orm.mapper()' function is removed as of "
+        "SQLAlchemy 2.0.  Use the "
+        "'sqlalchemy.orm.registry.map_imperatively()` "
+        "method of the ``sqlalchemy.orm.registry`` class to perform "
+        "classical mapping."
+    )
+
+
+def dynamic_loader(argument, **kw):
+    """Construct a dynamically-loading mapper property.
+
+    This is essentially the same as
+    using the ``lazy='dynamic'`` argument with :func:`relationship`::
+
+        dynamic_loader(SomeClass)
+
+        # is the same as
+
+        relationship(SomeClass, lazy="dynamic")
+
+    See the section :ref:`dynamic_relationship` for more details
+    on dynamic loading.
+
+    """
+    kw["lazy"] = "dynamic"
+    return relationship(argument, **kw)
+
+
+def backref(name, **kwargs):
+    """Create a back reference with explicit keyword arguments, which are the
+    same arguments one can send to :func:`relationship`.
+
+    Used with the ``backref`` keyword argument to :func:`relationship` in
+    place of a string argument, e.g.::
+
+        'items':relationship(
+            SomeItem, backref=backref('parent', lazy='subquery'))
+
+    .. seealso::
+
+        :ref:`relationships_backref`
+
+    """
+
+    return (name, kwargs)
+
+
+def deferred(*columns, **kw):
+    r"""Indicate a column-based mapped attribute that by default will
+    not load unless accessed.
+
+    :param \*columns: columns to be mapped.  This is typically a single
+     :class:`_schema.Column` object,
+     however a collection is supported in order
+     to support multiple columns mapped under the same attribute.
+
+    :param raiseload: boolean, if True, indicates an exception should be raised
+     if the load operation is to take place.
+
+     .. versionadded:: 1.4
+
+     .. seealso::
+
+        :ref:`deferred_raiseload`
+
+    :param \**kw: additional keyword arguments passed to
+     :class:`.ColumnProperty`.
+
+    .. seealso::
+
+        :ref:`deferred`
+
+    """
+    return ColumnProperty(deferred=True, *columns, **kw)
+
+
+def query_expression(default_expr=sql.null()):
+    """Indicate an attribute that populates from a query-time SQL expression.
+
+    :param default_expr: Optional SQL expression object that will be used in
+        all cases if not assigned later with :func:`_orm.with_expression`.
+        E.g.::
+
+            from sqlalchemy.sql import literal
+
+            class C(Base):
+                #...
+                my_expr = query_expression(literal(1))
+
+        .. versionadded:: 1.3.18
+
+
+    .. versionadded:: 1.2
+
+    .. seealso::
+
+        :ref:`mapper_querytime_expression`
+
+    """
+    prop = ColumnProperty(default_expr)
+    prop.strategy_key = (("query_expression", True),)
+    return prop
+
+
+def clear_mappers():
+    """Remove all mappers from all classes.
+
+    .. versionchanged:: 1.4  This function now locates all
+       :class:`_orm.registry` objects and calls upon the
+       :meth:`_orm.registry.dispose` method of each.
+
+    This function removes all instrumentation from classes and disposes
+    of their associated mappers.  Once called, the classes are unmapped
+    and can be later re-mapped with new mappers.
+
+    :func:`.clear_mappers` is *not* for normal use, as there is literally no
+    valid usage for it outside of very specific testing scenarios. Normally,
+    mappers are permanent structural components of user-defined classes, and
+    are never discarded independently of their class.  If a mapped class
+    itself is garbage collected, its mapper is automatically disposed of as
+    well. As such, :func:`.clear_mappers` is only for usage in test suites
+    that re-use the same classes with different mappings, which is itself an
+    extremely rare use case - the only such use case is in fact SQLAlchemy's
+    own test suite, and possibly the test suites of other ORM extension
+    libraries which intend to test various combinations of mapper construction
+    upon a fixed set of classes.
+
+    """
+
+    mapperlib._dispose_registries(mapperlib._all_registries(), False)
index 10902e970470149472111e74afbe496a027f242b..93e2d609adea378fd1635d1223b5e8ac9cd08166 100644 (file)
@@ -11,6 +11,9 @@
 
 import operator
 import typing
+from typing import Any
+from typing import Generic
+from typing import TypeVar
 
 from . import exc
 from .. import exc as sa_exc
@@ -19,6 +22,8 @@ from .. import util
 from ..util import typing as compat_typing
 
 
+_T = TypeVar("_T", bound=Any)
+
 PASSIVE_NO_RESULT = util.symbol(
     "PASSIVE_NO_RESULT",
     """Symbol returned by a loader callable or other attribute/history
@@ -574,7 +579,7 @@ class InspectionAttrInfo(InspectionAttr):
         return {}
 
 
-class _MappedAttribute:
+class _MappedAttribute(Generic[_T]):
     """Mixin for attributes which should be replaced by mapper-assigned
     attributes.
 
index cba7cf07dcc2d9378373acb03ee8d9a104fbd573..e8ac892ce4a20ea024322fc13f61e6837fc94fa6 100644 (file)
@@ -34,6 +34,7 @@ from ..sql.base import Options
 from ..sql.selectable import LABEL_STYLE_DISAMBIGUATE_ONLY
 from ..sql.selectable import LABEL_STYLE_NONE
 from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
+from ..sql.selectable import Select
 from ..sql.selectable import SelectState
 from ..sql.visitors import InternalTraversal
 
@@ -1132,7 +1133,6 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
         group_by,
     ):
 
-        Select = future.Select
         statement = Select._create_raw_select(
             _raw_columns=raw_columns,
             _from_obj=from_obj,
index 2a5b1bb2b0e2467c586c0f656316c075528cc8cf..99b2e9b6f11ee128e37a57e9894a4b36fbb6d493 100644 (file)
@@ -14,7 +14,7 @@ from . import clsregistry
 from . import exc as orm_exc
 from . import instrumentation
 from . import interfaces
-from . import mapper as mapperlib
+from . import mapperlib
 from .base import _inspect_mapped_class
 from .decl_base import _add_attribute
 from .decl_base import _as_declarative
index 4316271f0bc79a0479cb36e67cc0e20996070373..fb736806c4ed78f686d7662ceee05dd107522be0 100644 (file)
@@ -12,7 +12,7 @@ from sqlalchemy.orm import attributes
 from sqlalchemy.orm import instrumentation
 from . import clsregistry
 from . import exc as orm_exc
-from . import mapper as mapperlib
+from . import mapperlib
 from .attributes import InstrumentedAttribute
 from .attributes import QueryableAttribute
 from .base import _is_mapped_class
index d5083dcf199464ec2488a9b63f7c851fa63bc6f8..80fce86d0d594b31f38cdf895e77bbad4047bb2f 100644 (file)
@@ -10,6 +10,9 @@ that exist as configurational elements, but don't participate
 as actively in the load/persist ORM loop.
 
 """
+from typing import Any
+from typing import Type
+from typing import TypeVar
 
 from . import attributes
 from . import util as orm_util
@@ -24,8 +27,10 @@ from .. import util
 from ..sql import expression
 from ..sql import operators
 
+_T = TypeVar("_T", bound=Any)
 
-class DescriptorProperty(MapperProperty):
+
+class DescriptorProperty(MapperProperty[_T]):
     """:class:`.MapperProperty` which proxies access to a
     user-defined descriptor."""
 
@@ -86,7 +91,7 @@ class DescriptorProperty(MapperProperty):
         mapper.class_manager.instrument_attribute(self.key, proxy_attr)
 
 
-class CompositeProperty(DescriptorProperty):
+class CompositeProperty(DescriptorProperty[_T]):
     """Defines a "composite" mapped attribute, representing a collection
     of columns as one attribute.
 
@@ -99,49 +104,7 @@ class CompositeProperty(DescriptorProperty):
 
     """
 
-    def __init__(self, class_, *attrs, **kwargs):
-        r"""Return a composite column-based property for use with a Mapper.
-
-        See the mapping documentation section :ref:`mapper_composite` for a
-        full usage example.
-
-        The :class:`.MapperProperty` returned by :func:`.composite`
-        is the :class:`.CompositeProperty`.
-
-        :param class\_:
-          The "composite type" class, or any classmethod or callable which
-          will produce a new instance of the composite object given the
-          column values in order.
-
-        :param \*cols:
-          List of Column objects to be mapped.
-
-        :param active_history=False:
-          When ``True``, indicates that the "previous" value for a
-          scalar attribute should be loaded when replaced, if not
-          already loaded.  See the same flag on :func:`.column_property`.
-
-        :param group:
-          A group name for this property when marked as deferred.
-
-        :param deferred:
-          When True, the column property is "deferred", meaning that it does
-          not load immediately, and is instead loaded when the attribute is
-          first accessed on an instance.  See also
-          :func:`~sqlalchemy.orm.deferred`.
-
-        :param comparator_factory:  a class which extends
-          :class:`.CompositeProperty.Comparator` which provides custom SQL
-          clause generation for comparison operations.
-
-        :param doc:
-          optional string that will be applied as the doc on the
-          class-bound descriptor.
-
-        :param info: Optional data dictionary which will be populated into the
-            :attr:`.MapperProperty.info` attribute of this object.
-
-        """
+    def __init__(self, class_: Type[_T], *attrs, **kwargs):
         super(CompositeProperty, self).__init__()
 
         self.attrs = attrs
@@ -548,109 +511,6 @@ class SynonymProperty(DescriptorProperty):
         doc=None,
         info=None,
     ):
-        """Denote an attribute name as a synonym to a mapped property,
-        in that the attribute will mirror the value and expression behavior
-        of another attribute.
-
-        e.g.::
-
-            class MyClass(Base):
-                __tablename__ = 'my_table'
-
-                id = Column(Integer, primary_key=True)
-                job_status = Column(String(50))
-
-                status = synonym("job_status")
-
-
-        :param name: the name of the existing mapped property.  This
-          can refer to the string name ORM-mapped attribute
-          configured on the class, including column-bound attributes
-          and relationships.
-
-        :param descriptor: a Python :term:`descriptor` that will be used
-          as a getter (and potentially a setter) when this attribute is
-          accessed at the instance level.
-
-        :param map_column: **For classical mappings and mappings against
-          an existing Table object only**.  if ``True``, the :func:`.synonym`
-          construct will locate the :class:`_schema.Column`
-          object upon the mapped
-          table that would normally be associated with the attribute name of
-          this synonym, and produce a new :class:`.ColumnProperty` that instead
-          maps this :class:`_schema.Column`
-          to the alternate name given as the "name"
-          argument of the synonym; in this way, the usual step of redefining
-          the mapping of the :class:`_schema.Column`
-          to be under a different name is
-          unnecessary. This is usually intended to be used when a
-          :class:`_schema.Column`
-          is to be replaced with an attribute that also uses a
-          descriptor, that is, in conjunction with the
-          :paramref:`.synonym.descriptor` parameter::
-
-            my_table = Table(
-                "my_table", metadata,
-                Column('id', Integer, primary_key=True),
-                Column('job_status', String(50))
-            )
-
-            class MyClass:
-                @property
-                def _job_status_descriptor(self):
-                    return "Status: %s" % self._job_status
-
-
-            mapper(
-                MyClass, my_table, properties={
-                    "job_status": synonym(
-                        "_job_status", map_column=True,
-                        descriptor=MyClass._job_status_descriptor)
-                }
-            )
-
-          Above, the attribute named ``_job_status`` is automatically
-          mapped to the ``job_status`` column::
-
-            >>> j1 = MyClass()
-            >>> j1._job_status = "employed"
-            >>> j1.job_status
-            Status: employed
-
-          When using Declarative, in order to provide a descriptor in
-          conjunction with a synonym, use the
-          :func:`sqlalchemy.ext.declarative.synonym_for` helper.  However,
-          note that the :ref:`hybrid properties <mapper_hybrids>` feature
-          should usually be preferred, particularly when redefining attribute
-          behavior.
-
-        :param info: Optional data dictionary which will be populated into the
-            :attr:`.InspectionAttr.info` attribute of this object.
-
-            .. versionadded:: 1.0.0
-
-        :param comparator_factory: A subclass of :class:`.PropComparator`
-          that will provide custom comparison behavior at the SQL expression
-          level.
-
-          .. note::
-
-            For the use case of providing an attribute which redefines both
-            Python-level and SQL-expression level behavior of an attribute,
-            please refer to the Hybrid attribute introduced at
-            :ref:`mapper_hybrids` for a more effective technique.
-
-        .. seealso::
-
-            :ref:`synonyms` - Overview of synonyms
-
-            :func:`.synonym_for` - a helper oriented towards Declarative
-
-            :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
-            updated approach to augmenting attribute behavior more flexibly
-            than can be achieved with synonyms.
-
-        """
         super(SynonymProperty, self).__init__()
 
         self.name = name
index 7b2be9f050709821f950f75300042107e843b383..ade47480d5700b3747d4efbe1a8e23be2451ea04 100644 (file)
@@ -15,12 +15,12 @@ basic add/delete mutation.
 from . import attributes
 from . import exc as orm_exc
 from . import interfaces
-from . import object_mapper
-from . import object_session
 from . import relationships
 from . import strategies
 from . import util as orm_util
+from .base import object_mapper
 from .query import Query
+from .session import object_session
 from .. import exc
 from .. import log
 from .. import util
index d842df2215657769a307855712c21fd8b571df3e..df265db5757c46a20c4e92988cbcc6eccf8e6b72 100644 (file)
@@ -17,6 +17,8 @@ are exposed when inspecting mappings.
 """
 
 import collections
+from typing import Any
+from typing import TypeVar
 
 from . import exc as orm_exc
 from . import path_registry
@@ -39,6 +41,7 @@ from ..sql import visitors
 from ..sql.base import ExecutableOption
 from ..sql.cache_key import HasCacheKey
 
+_T = TypeVar("_T", bound=Any)
 
 __all__ = (
     "EXT_CONTINUE",
@@ -77,7 +80,7 @@ class ORMFromClauseRole(roles.StrictFromClauseRole):
 
 @inspection._self_inspects
 class MapperProperty(
-    HasCacheKey, _MappedAttribute, InspectionAttr, util.MemoizedSlots
+    HasCacheKey, _MappedAttribute[_T], InspectionAttr, util.MemoizedSlots
 ):
     """Represent a particular class attribute mapped by :class:`_orm.Mapper`.
 
index dbcbc8a1b769fe762e8086945fb2c260f6291b6b..87829d6433b3d96fd0c6f7c5f53781664d99f69b 100644 (file)
@@ -14,11 +14,13 @@ This is a semi-private module; the main configurational API of the ORM is
 available in :class:`~sqlalchemy.orm.`.
 
 """
-
 from collections import deque
 from functools import reduce
 from itertools import chain
 import sys
+from typing import Generic
+from typing import Type
+from typing import TypeVar
 import weakref
 
 from . import attributes
@@ -58,6 +60,9 @@ from ..util import HasMemoized
 _mapper_registries = weakref.WeakKeyDictionary()
 
 
+_MC = TypeVar("_MC")
+
+
 def _all_registries():
     with _CONFIGURE_MUTEX:
         return set(_mapper_registries)
@@ -88,6 +93,7 @@ class Mapper(
     ORMEntityColumnsClauseRole,
     sql_base.MemoizedHasCacheKey,
     InspectionAttr,
+    Generic[_MC],
 ):
     """Defines an association between a Python class and a database table or
     other relational structure, so that ORM operations against the class may
@@ -115,7 +121,7 @@ class Mapper(
     )
     def __init__(
         self,
-        class_,
+        class_: Type[_MC],
         local_table=None,
         properties=None,
         primary_key=None,
index 1fd5dbaf8e50e75cece5d66b0e7c917f70665b9a..8ee26315ef996d51521f018f531d3cfef8f99938 100644 (file)
@@ -12,6 +12,10 @@ mapped attributes.
 
 """
 
+from typing import Any
+from typing import Generic
+from typing import TypeVar
+
 from . import attributes
 from . import strategy_options
 from .descriptor_props import CompositeProperty
@@ -22,10 +26,12 @@ from .interfaces import StrategizedProperty
 from .relationships import RelationshipProperty
 from .util import _orm_full_deannotate
 from .. import log
+from .. import sql
 from .. import util
 from ..sql import coercions
 from ..sql import roles
 
+_T = TypeVar("_T", bound=Any)
 
 __all__ = [
     "ColumnProperty",
@@ -37,7 +43,7 @@ __all__ = [
 
 
 @log.class_logger
-class ColumnProperty(StrategizedProperty):
+class ColumnProperty(StrategizedProperty, Generic[_T]):
     """Describes an object attribute that corresponds to a table column.
 
     Public constructor is the :func:`_orm.column_property` function.
@@ -70,91 +76,11 @@ class ColumnProperty(StrategizedProperty):
         "raiseload",
     )
 
-    def __init__(self, *columns, **kwargs):
-        r"""Provide a column-level property for use with a mapping.
-
-        Column-based properties can normally be applied to the mapper's
-        ``properties`` dictionary using the :class:`_schema.Column`
-        element directly.
-        Use this function when the given column is not directly present within
-        the mapper's selectable; examples include SQL expressions, functions,
-        and scalar SELECT queries.
-
-        The :func:`_orm.column_property` function returns an instance of
-        :class:`.ColumnProperty`.
-
-        Columns that aren't present in the mapper's selectable won't be
-        persisted by the mapper and are effectively "read-only" attributes.
-
-        :param \*cols:
-              list of Column objects to be mapped.
-
-        :param active_history=False:
-          When ``True``, indicates that the "previous" value for a
-          scalar attribute should be loaded when replaced, if not
-          already loaded. Normally, history tracking logic for
-          simple non-primary-key scalar values only needs to be
-          aware of the "new" value in order to perform a flush. This
-          flag is available for applications that make use of
-          :func:`.attributes.get_history` or :meth:`.Session.is_modified`
-          which also need to know
-          the "previous" value of the attribute.
-
-        :param comparator_factory: a class which extends
-           :class:`.ColumnProperty.Comparator` which provides custom SQL
-           clause generation for comparison operations.
-
-        :param group:
-            a group name for this property when marked as deferred.
-
-        :param deferred:
-              when True, the column property is "deferred", meaning that
-              it does not load immediately, and is instead loaded when the
-              attribute is first accessed on an instance.  See also
-              :func:`~sqlalchemy.orm.deferred`.
-
-        :param doc:
-              optional string that will be applied as the doc on the
-              class-bound descriptor.
-
-        :param expire_on_flush=True:
-            Disable expiry on flush.   A column_property() which refers
-            to a SQL expression (and not a single table-bound column)
-            is considered to be a "read only" property; populating it
-            has no effect on the state of data, and it can only return
-            database state.   For this reason a column_property()'s value
-            is expired whenever the parent object is involved in a
-            flush, that is, has any kind of "dirty" state within a flush.
-            Setting this parameter to ``False`` will have the effect of
-            leaving any existing value present after the flush proceeds.
-            Note however that the :class:`.Session` with default expiration
-            settings still expires
-            all attributes after a :meth:`.Session.commit` call, however.
-
-        :param info: Optional data dictionary which will be populated into the
-            :attr:`.MapperProperty.info` attribute of this object.
-
-        :param raiseload: if True, indicates the column should raise an error
-            when undeferred, rather than loading the value.  This can be
-            altered at query time by using the :func:`.deferred` option with
-            raiseload=False.
-
-            .. versionadded:: 1.4
-
-            .. seealso::
-
-                :ref:`deferred_raiseload`
-
-        .. seealso::
-
-            :ref:`column_property_options` - to map columns while including
-            mapping options
-
-            :ref:`mapper_column_property_sql_expressions` - to map SQL
-            expressions
-
-        """
+    def __init__(
+        self, column: sql.ColumnElement[_T], *additional_columns, **kwargs
+    ):
         super(ColumnProperty, self).__init__()
+        columns = (column,) + additional_columns
         self._orig_columns = [
             coercions.expect(roles.LabeledColumnExprRole, c) for c in columns
         ]
index e6d16f1788a68bbe6d71164f522b89172d81e941..15259f130cb3548e3e179d0acb0019dd5f2cc36c 100644 (file)
@@ -2809,6 +2809,8 @@ class FromStatement(GroupedElement, SelectBase, Executable):
 
 
 class AliasOption(interfaces.LoaderOption):
+    inherit_cache = False
+
     @util.deprecated(
         "1.4",
         "The :class:`.AliasOption` is not necessary "
@@ -2822,8 +2824,6 @@ class AliasOption(interfaces.LoaderOption):
 
         """
 
-    inherit_cache = False
-
     def process_compile_state(self, compile_state):
         pass
 
index fb4723e29963e29ecb634e2798731282ac503b36..330d4543052769b48aba74725b126bffafd8d460 100644 (file)
@@ -15,6 +15,11 @@ and `secondaryjoin` aspects of :func:`_orm.relationship`.
 """
 import collections
 import re
+from typing import Callable
+from typing import Generic
+from typing import Type
+from typing import TypeVar
+from typing import Union
 import weakref
 
 from . import attributes
@@ -48,6 +53,8 @@ from ..sql.util import join_condition
 from ..sql.util import selectables_overlap
 from ..sql.util import visit_binary_product
 
+_RC = TypeVar("_RC")
+
 
 def remote(expr):
     """Annotate a portion of a primaryjoin expression
@@ -89,7 +96,7 @@ def foreign(expr):
 
 
 @log.class_logger
-class RelationshipProperty(StrategizedProperty):
+class RelationshipProperty(StrategizedProperty, Generic[_RC]):
     """Describes an object property that holds a single item or list
     of items that correspond to a related database table.
 
@@ -118,7 +125,7 @@ class RelationshipProperty(StrategizedProperty):
 
     def __init__(
         self,
-        argument,
+        argument: Union[str, Type[_RC], Callable[[], Type[_RC]]],
         secondary=None,
         primaryjoin=None,
         secondaryjoin=None,
@@ -154,821 +161,6 @@ class RelationshipProperty(StrategizedProperty):
         sync_backref=None,
         _legacy_inactive_history_style=False,
     ):
-        """Provide a relationship between two mapped classes.
-
-        This corresponds to a parent-child or associative table relationship.
-        The constructed class is an instance of
-        :class:`.RelationshipProperty`.
-
-        A typical :func:`_orm.relationship`, used in a classical mapping::
-
-           mapper(Parent, properties={
-             'children': relationship(Child)
-           })
-
-        Some arguments accepted by :func:`_orm.relationship`
-        optionally accept a
-        callable function, which when called produces the desired value.
-        The callable is invoked by the parent :class:`_orm.Mapper` at "mapper
-        initialization" time, which happens only when mappers are first used,
-        and is assumed to be after all mappings have been constructed.  This
-        can be used to resolve order-of-declaration and other dependency
-        issues, such as if ``Child`` is declared below ``Parent`` in the same
-        file::
-
-            mapper(Parent, properties={
-                "children":relationship(lambda: Child,
-                                    order_by=lambda: Child.id)
-            })
-
-        When using the :ref:`declarative_toplevel` extension, the Declarative
-        initializer allows string arguments to be passed to
-        :func:`_orm.relationship`.  These string arguments are converted into
-        callables that evaluate the string as Python code, using the
-        Declarative class-registry as a namespace.  This allows the lookup of
-        related classes to be automatic via their string name, and removes the
-        need for related classes to be imported into the local module space
-        before the dependent classes have been declared.  It is still required
-        that the modules in which these related classes appear are imported
-        anywhere in the application at some point before the related mappings
-        are actually used, else a lookup error will be raised when the
-        :func:`_orm.relationship`
-        attempts to resolve the string reference to the
-        related class.    An example of a string- resolved class is as
-        follows::
-
-            from sqlalchemy.ext.declarative import declarative_base
-
-            Base = declarative_base()
-
-            class Parent(Base):
-                __tablename__ = 'parent'
-                id = Column(Integer, primary_key=True)
-                children = relationship("Child", order_by="Child.id")
-
-        .. seealso::
-
-          :ref:`relationship_config_toplevel` - Full introductory and
-          reference documentation for :func:`_orm.relationship`.
-
-          :ref:`orm_tutorial_relationship` - ORM tutorial introduction.
-
-        :param argument:
-          A mapped class, or actual :class:`_orm.Mapper` instance,
-          representing
-          the target of the relationship.
-
-          :paramref:`_orm.relationship.argument`
-          may also be passed as a callable
-          function which is evaluated at mapper initialization time, and may
-          be passed as a string name when using Declarative.
-
-          .. warning:: Prior to SQLAlchemy 1.3.16, this value is interpreted
-             using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          .. versionchanged 1.3.16::
-
-             The string evaluation of the main "argument" no longer accepts an
-             open ended Python expression, instead only accepting a string
-             class name or dotted package-qualified name.
-
-          .. seealso::
-
-            :ref:`declarative_configuring_relationships` - further detail
-            on relationship configuration when using Declarative.
-
-        :param secondary:
-          For a many-to-many relationship, specifies the intermediary
-          table, and is typically an instance of :class:`_schema.Table`.
-          In less common circumstances, the argument may also be specified
-          as an :class:`_expression.Alias` construct, or even a
-          :class:`_expression.Join` construct.
-
-          :paramref:`_orm.relationship.secondary` may
-          also be passed as a callable function which is evaluated at
-          mapper initialization time.  When using Declarative, it may also
-          be a string argument noting the name of a :class:`_schema.Table`
-          that is
-          present in the :class:`_schema.MetaData`
-          collection associated with the
-          parent-mapped :class:`_schema.Table`.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          The :paramref:`_orm.relationship.secondary` keyword argument is
-          typically applied in the case where the intermediary
-          :class:`_schema.Table`
-          is not otherwise expressed in any direct class mapping. If the
-          "secondary" table is also explicitly mapped elsewhere (e.g. as in
-          :ref:`association_pattern`), one should consider applying the
-          :paramref:`_orm.relationship.viewonly` flag so that this
-          :func:`_orm.relationship`
-          is not used for persistence operations which
-          may conflict with those of the association object pattern.
-
-          .. seealso::
-
-              :ref:`relationships_many_to_many` - Reference example of "many
-              to many".
-
-              :ref:`orm_tutorial_many_to_many` - ORM tutorial introduction to
-              many-to-many relationships.
-
-              :ref:`self_referential_many_to_many` - Specifics on using
-              many-to-many in a self-referential case.
-
-              :ref:`declarative_many_to_many` - Additional options when using
-              Declarative.
-
-              :ref:`association_pattern` - an alternative to
-              :paramref:`_orm.relationship.secondary`
-              when composing association
-              table relationships, allowing additional attributes to be
-              specified on the association table.
-
-              :ref:`composite_secondary_join` - a lesser-used pattern which
-              in some cases can enable complex :func:`_orm.relationship` SQL
-              conditions to be used.
-
-          .. versionadded:: 0.9.2 :paramref:`_orm.relationship.secondary`
-             works
-             more effectively when referring to a :class:`_expression.Join`
-             instance.
-
-        :param active_history=False:
-          When ``True``, indicates that the "previous" value for a
-          many-to-one reference should be loaded when replaced, if
-          not already loaded. Normally, history tracking logic for
-          simple many-to-ones only needs to be aware of the "new"
-          value in order to perform a flush. This flag is available
-          for applications that make use of
-          :func:`.attributes.get_history` which also need to know
-          the "previous" value of the attribute.
-
-        :param backref:
-          Indicates the string name of a property to be placed on the related
-          mapper's class that will handle this relationship in the other
-          direction. The other property will be created automatically
-          when the mappers are configured.  Can also be passed as a
-          :func:`.backref` object to control the configuration of the
-          new relationship.
-
-          .. seealso::
-
-            :ref:`relationships_backref` - Introductory documentation and
-            examples.
-
-            :paramref:`_orm.relationship.back_populates` - alternative form
-            of backref specification.
-
-            :func:`.backref` - allows control over :func:`_orm.relationship`
-            configuration when using :paramref:`_orm.relationship.backref`.
-
-
-        :param back_populates:
-          Takes a string name and has the same meaning as
-          :paramref:`_orm.relationship.backref`, except the complementing
-          property is **not** created automatically, and instead must be
-          configured explicitly on the other mapper.  The complementing
-          property should also indicate
-          :paramref:`_orm.relationship.back_populates` to this relationship to
-          ensure proper functioning.
-
-          .. seealso::
-
-            :ref:`relationships_backref` - Introductory documentation and
-            examples.
-
-            :paramref:`_orm.relationship.backref` - alternative form
-            of backref specification.
-
-        :param overlaps:
-           A string name or comma-delimited set of names of other relationships
-           on either this mapper, a descendant mapper, or a target mapper with
-           which this relationship may write to the same foreign keys upon
-           persistence.   The only effect this has is to eliminate the
-           warning that this relationship will conflict with another upon
-           persistence.   This is used for such relationships that are truly
-           capable of conflicting with each other on write, but the application
-           will ensure that no such conflicts occur.
-
-           .. versionadded:: 1.4
-
-           .. seealso::
-
-                :ref:`error_qzyx` - usage example
-
-        :param bake_queries=True:
-          Enable :ref:`lambda caching <engine_lambda_caching>` for loader
-          strategies, if applicable, which adds a performance gain to the
-          construction of SQL constructs used by loader strategies, in addition
-          to the usual SQL statement caching used throughout SQLAlchemy. This
-          parameter currently applies only to the "lazy" and "selectin" loader
-          strategies. There is generally no reason to set this parameter to
-          False.
-
-          .. versionchanged:: 1.4  Relationship loaders no longer use the
-             previous "baked query" system of query caching.   The "lazy"
-             and "selectin" loaders make use of the "lambda cache" system
-             for the construction of SQL constructs,
-             as well as the usual SQL caching system that is throughout
-             SQLAlchemy as of the 1.4 series.
-
-        :param cascade:
-          A comma-separated list of cascade rules which determines how
-          Session operations should be "cascaded" from parent to child.
-          This defaults to ``False``, which means the default cascade
-          should be used - this default cascade is ``"save-update, merge"``.
-
-          The available cascades are ``save-update``, ``merge``,
-          ``expunge``, ``delete``, ``delete-orphan``, and ``refresh-expire``.
-          An additional option, ``all`` indicates shorthand for
-          ``"save-update, merge, refresh-expire,
-          expunge, delete"``, and is often used as in ``"all, delete-orphan"``
-          to indicate that related objects should follow along with the
-          parent object in all cases, and be deleted when de-associated.
-
-          .. seealso::
-
-            :ref:`unitofwork_cascades` - Full detail on each of the available
-            cascade options.
-
-            :ref:`tutorial_delete_cascade` - Tutorial example describing
-            a delete cascade.
-
-        :param cascade_backrefs=False:
-          Legacy; this flag is always False.
-
-          .. versionchanged:: 2.0 "cascade_backrefs" functionality has been
-             removed.
-
-        :param collection_class:
-          A class or callable that returns a new list-holding object. will
-          be used in place of a plain list for storing elements.
-
-          .. seealso::
-
-            :ref:`custom_collections` - Introductory documentation and
-            examples.
-
-        :param comparator_factory:
-          A class which extends :class:`.RelationshipProperty.Comparator`
-          which provides custom SQL clause generation for comparison
-          operations.
-
-          .. seealso::
-
-            :class:`.PropComparator` - some detail on redefining comparators
-            at this level.
-
-            :ref:`custom_comparators` - Brief intro to this feature.
-
-
-        :param distinct_target_key=None:
-          Indicate if a "subquery" eager load should apply the DISTINCT
-          keyword to the innermost SELECT statement.  When left as ``None``,
-          the DISTINCT keyword will be applied in those cases when the target
-          columns do not comprise the full primary key of the target table.
-          When set to ``True``, the DISTINCT keyword is applied to the
-          innermost SELECT unconditionally.
-
-          It may be desirable to set this flag to False when the DISTINCT is
-          reducing performance of the innermost subquery beyond that of what
-          duplicate innermost rows may be causing.
-
-          .. versionchanged:: 0.9.0 -
-             :paramref:`_orm.relationship.distinct_target_key` now defaults to
-             ``None``, so that the feature enables itself automatically for
-             those cases where the innermost query targets a non-unique
-             key.
-
-          .. seealso::
-
-            :ref:`loading_toplevel` - includes an introduction to subquery
-            eager loading.
-
-        :param doc:
-          Docstring which will be applied to the resulting descriptor.
-
-        :param foreign_keys:
-
-          A list of columns which are to be used as "foreign key"
-          columns, or columns which refer to the value in a remote
-          column, within the context of this :func:`_orm.relationship`
-          object's :paramref:`_orm.relationship.primaryjoin` condition.
-          That is, if the :paramref:`_orm.relationship.primaryjoin`
-          condition of this :func:`_orm.relationship` is ``a.id ==
-          b.a_id``, and the values in ``b.a_id`` are required to be
-          present in ``a.id``, then the "foreign key" column of this
-          :func:`_orm.relationship` is ``b.a_id``.
-
-          In normal cases, the :paramref:`_orm.relationship.foreign_keys`
-          parameter is **not required.** :func:`_orm.relationship` will
-          automatically determine which columns in the
-          :paramref:`_orm.relationship.primaryjoin` condition are to be
-          considered "foreign key" columns based on those
-          :class:`_schema.Column` objects that specify
-          :class:`_schema.ForeignKey`,
-          or are otherwise listed as referencing columns in a
-          :class:`_schema.ForeignKeyConstraint` construct.
-          :paramref:`_orm.relationship.foreign_keys` is only needed when:
-
-            1. There is more than one way to construct a join from the local
-               table to the remote table, as there are multiple foreign key
-               references present.  Setting ``foreign_keys`` will limit the
-               :func:`_orm.relationship`
-               to consider just those columns specified
-               here as "foreign".
-
-            2. The :class:`_schema.Table` being mapped does not actually have
-               :class:`_schema.ForeignKey` or
-               :class:`_schema.ForeignKeyConstraint`
-               constructs present, often because the table
-               was reflected from a database that does not support foreign key
-               reflection (MySQL MyISAM).
-
-            3. The :paramref:`_orm.relationship.primaryjoin`
-               argument is used to
-               construct a non-standard join condition, which makes use of
-               columns or expressions that do not normally refer to their
-               "parent" column, such as a join condition expressed by a
-               complex comparison using a SQL function.
-
-          The :func:`_orm.relationship` construct will raise informative
-          error messages that suggest the use of the
-          :paramref:`_orm.relationship.foreign_keys` parameter when
-          presented with an ambiguous condition.   In typical cases,
-          if :func:`_orm.relationship` doesn't raise any exceptions, the
-          :paramref:`_orm.relationship.foreign_keys` parameter is usually
-          not needed.
-
-          :paramref:`_orm.relationship.foreign_keys` may also be passed as a
-          callable function which is evaluated at mapper initialization time,
-          and may be passed as a Python-evaluable string when using
-          Declarative.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          .. seealso::
-
-            :ref:`relationship_foreign_keys`
-
-            :ref:`relationship_custom_foreign`
-
-            :func:`.foreign` - allows direct annotation of the "foreign"
-            columns within a :paramref:`_orm.relationship.primaryjoin`
-            condition.
-
-        :param info: Optional data dictionary which will be populated into the
-            :attr:`.MapperProperty.info` attribute of this object.
-
-        :param innerjoin=False:
-          When ``True``, joined eager loads will use an inner join to join
-          against related tables instead of an outer join.  The purpose
-          of this option is generally one of performance, as inner joins
-          generally perform better than outer joins.
-
-          This flag can be set to ``True`` when the relationship references an
-          object via many-to-one using local foreign keys that are not
-          nullable, or when the reference is one-to-one or a collection that
-          is guaranteed to have one or at least one entry.
-
-          The option supports the same "nested" and "unnested" options as
-          that of :paramref:`_orm.joinedload.innerjoin`.  See that flag
-          for details on nested / unnested behaviors.
-
-          .. seealso::
-
-            :paramref:`_orm.joinedload.innerjoin` - the option as specified by
-            loader option, including detail on nesting behavior.
-
-            :ref:`what_kind_of_loading` - Discussion of some details of
-            various loader options.
-
-
-        :param join_depth:
-          When non-``None``, an integer value indicating how many levels
-          deep "eager" loaders should join on a self-referring or cyclical
-          relationship.  The number counts how many times the same Mapper
-          shall be present in the loading condition along a particular join
-          branch.  When left at its default of ``None``, eager loaders
-          will stop chaining when they encounter a the same target mapper
-          which is already higher up in the chain.  This option applies
-          both to joined- and subquery- eager loaders.
-
-          .. seealso::
-
-            :ref:`self_referential_eager_loading` - Introductory documentation
-            and examples.
-
-        :param lazy='select': specifies
-          How the related items should be loaded.  Default value is
-          ``select``.  Values include:
-
-          * ``select`` - items should be loaded lazily when the property is
-            first accessed, using a separate SELECT statement, or identity map
-            fetch for simple many-to-one references.
-
-          * ``immediate`` - items should be loaded as the parents are loaded,
-            using a separate SELECT statement, or identity map fetch for
-            simple many-to-one references.
-
-          * ``joined`` - items should be loaded "eagerly" in the same query as
-            that of the parent, using a JOIN or LEFT OUTER JOIN.  Whether
-            the join is "outer" or not is determined by the
-            :paramref:`_orm.relationship.innerjoin` parameter.
-
-          * ``subquery`` - items should be loaded "eagerly" as the parents are
-            loaded, using one additional SQL statement, which issues a JOIN to
-            a subquery of the original statement, for each collection
-            requested.
-
-          * ``selectin`` - items should be loaded "eagerly" as the parents
-            are loaded, using one or more additional SQL statements, which
-            issues a JOIN to the immediate parent object, specifying primary
-            key identifiers using an IN clause.
-
-            .. versionadded:: 1.2
-
-          * ``noload`` - no loading should occur at any time.  This is to
-            support "write-only" attributes, or attributes which are
-            populated in some manner specific to the application.
-
-          * ``raise`` - lazy loading is disallowed; accessing
-            the attribute, if its value were not already loaded via eager
-            loading, will raise an :exc:`~sqlalchemy.exc.InvalidRequestError`.
-            This strategy can be used when objects are to be detached from
-            their attached :class:`.Session` after they are loaded.
-
-            .. versionadded:: 1.1
-
-          * ``raise_on_sql`` - lazy loading that emits SQL is disallowed;
-            accessing the attribute, if its value were not already loaded via
-            eager loading, will raise an
-            :exc:`~sqlalchemy.exc.InvalidRequestError`, **if the lazy load
-            needs to emit SQL**.  If the lazy load can pull the related value
-            from the identity map or determine that it should be None, the
-            value is loaded.  This strategy can be used when objects will
-            remain associated with the attached :class:`.Session`, however
-            additional SELECT statements should be blocked.
-
-            .. versionadded:: 1.1
-
-          * ``dynamic`` - the attribute will return a pre-configured
-            :class:`_query.Query` object for all read
-            operations, onto which further filtering operations can be
-            applied before iterating the results.  See
-            the section :ref:`dynamic_relationship` for more details.
-
-          * True - a synonym for 'select'
-
-          * False - a synonym for 'joined'
-
-          * None - a synonym for 'noload'
-
-          .. seealso::
-
-            :doc:`/orm/loading_relationships` - Full documentation on
-            relationship loader configuration.
-
-            :ref:`dynamic_relationship` - detail on the ``dynamic`` option.
-
-            :ref:`collections_noload_raiseload` - notes on "noload" and "raise"
-
-        :param load_on_pending=False:
-          Indicates loading behavior for transient or pending parent objects.
-
-          When set to ``True``, causes the lazy-loader to
-          issue a query for a parent object that is not persistent, meaning it
-          has never been flushed.  This may take effect for a pending object
-          when autoflush is disabled, or for a transient object that has been
-          "attached" to a :class:`.Session` but is not part of its pending
-          collection.
-
-          The :paramref:`_orm.relationship.load_on_pending`
-          flag does not improve
-          behavior when the ORM is used normally - object references should be
-          constructed at the object level, not at the foreign key level, so
-          that they are present in an ordinary way before a flush proceeds.
-          This flag is not not intended for general use.
-
-          .. seealso::
-
-              :meth:`.Session.enable_relationship_loading` - this method
-              establishes "load on pending" behavior for the whole object, and
-              also allows loading on objects that remain transient or
-              detached.
-
-        :param order_by:
-          Indicates the ordering that should be applied when loading these
-          items.  :paramref:`_orm.relationship.order_by`
-          is expected to refer to
-          one of the :class:`_schema.Column`
-          objects to which the target class is
-          mapped, or the attribute itself bound to the target class which
-          refers to the column.
-
-          :paramref:`_orm.relationship.order_by`
-          may also be passed as a callable
-          function which is evaluated at mapper initialization time, and may
-          be passed as a Python-evaluable string when using Declarative.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-        :param passive_deletes=False:
-           Indicates loading behavior during delete operations.
-
-           A value of True indicates that unloaded child items should not
-           be loaded during a delete operation on the parent.  Normally,
-           when a parent item is deleted, all child items are loaded so
-           that they can either be marked as deleted, or have their
-           foreign key to the parent set to NULL.  Marking this flag as
-           True usually implies an ON DELETE <CASCADE|SET NULL> rule is in
-           place which will handle updating/deleting child rows on the
-           database side.
-
-           Additionally, setting the flag to the string value 'all' will
-           disable the "nulling out" of the child foreign keys, when the parent
-           object is deleted and there is no delete or delete-orphan cascade
-           enabled.  This is typically used when a triggering or error raise
-           scenario is in place on the database side.  Note that the foreign
-           key attributes on in-session child objects will not be changed after
-           a flush occurs so this is a very special use-case setting.
-           Additionally, the "nulling out" will still occur if the child
-           object is de-associated with the parent.
-
-           .. seealso::
-
-                :ref:`passive_deletes` - Introductory documentation
-                and examples.
-
-        :param passive_updates=True:
-          Indicates the persistence behavior to take when a referenced
-          primary key value changes in place, indicating that the referencing
-          foreign key columns will also need their value changed.
-
-          When True, it is assumed that ``ON UPDATE CASCADE`` is configured on
-          the foreign key in the database, and that the database will
-          handle propagation of an UPDATE from a source column to
-          dependent rows.  When False, the SQLAlchemy
-          :func:`_orm.relationship`
-          construct will attempt to emit its own UPDATE statements to
-          modify related targets.  However note that SQLAlchemy **cannot**
-          emit an UPDATE for more than one level of cascade.  Also,
-          setting this flag to False is not compatible in the case where
-          the database is in fact enforcing referential integrity, unless
-          those constraints are explicitly "deferred", if the target backend
-          supports it.
-
-          It is highly advised that an application which is employing
-          mutable primary keys keeps ``passive_updates`` set to True,
-          and instead uses the referential integrity features of the database
-          itself in order to handle the change efficiently and fully.
-
-          .. seealso::
-
-              :ref:`passive_updates` - Introductory documentation and
-              examples.
-
-              :paramref:`.mapper.passive_updates` - a similar flag which
-              takes effect for joined-table inheritance mappings.
-
-        :param post_update:
-          This indicates that the relationship should be handled by a
-          second UPDATE statement after an INSERT or before a
-          DELETE. Currently, it also will issue an UPDATE after the
-          instance was UPDATEd as well, although this technically should
-          be improved. This flag is used to handle saving bi-directional
-          dependencies between two individual rows (i.e. each row
-          references the other), where it would otherwise be impossible to
-          INSERT or DELETE both rows fully since one row exists before the
-          other. Use this flag when a particular mapping arrangement will
-          incur two rows that are dependent on each other, such as a table
-          that has a one-to-many relationship to a set of child rows, and
-          also has a column that references a single child row within that
-          list (i.e. both tables contain a foreign key to each other). If
-          a flush operation returns an error that a "cyclical
-          dependency" was detected, this is a cue that you might want to
-          use :paramref:`_orm.relationship.post_update` to "break" the cycle.
-
-          .. seealso::
-
-              :ref:`post_update` - Introductory documentation and examples.
-
-        :param primaryjoin:
-          A SQL expression that will be used as the primary
-          join of the child object against the parent object, or in a
-          many-to-many relationship the join of the parent object to the
-          association table. By default, this value is computed based on the
-          foreign key relationships of the parent and child tables (or
-          association table).
-
-          :paramref:`_orm.relationship.primaryjoin` may also be passed as a
-          callable function which is evaluated at mapper initialization time,
-          and may be passed as a Python-evaluable string when using
-          Declarative.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          .. seealso::
-
-              :ref:`relationship_primaryjoin`
-
-        :param remote_side:
-          Used for self-referential relationships, indicates the column or
-          list of columns that form the "remote side" of the relationship.
-
-          :paramref:`_orm.relationship.remote_side` may also be passed as a
-          callable function which is evaluated at mapper initialization time,
-          and may be passed as a Python-evaluable string when using
-          Declarative.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          .. seealso::
-
-            :ref:`self_referential` - in-depth explanation of how
-            :paramref:`_orm.relationship.remote_side`
-            is used to configure self-referential relationships.
-
-            :func:`.remote` - an annotation function that accomplishes the
-            same purpose as :paramref:`_orm.relationship.remote_side`,
-            typically
-            when a custom :paramref:`_orm.relationship.primaryjoin` condition
-            is used.
-
-        :param query_class:
-          A :class:`_query.Query`
-          subclass that will be used internally by the
-          ``AppenderQuery`` returned by a "dynamic" relationship, that
-          is, a relationship that specifies ``lazy="dynamic"`` or was
-          otherwise constructed using the :func:`_orm.dynamic_loader`
-          function.
-
-          .. seealso::
-
-            :ref:`dynamic_relationship` - Introduction to "dynamic"
-            relationship loaders.
-
-        :param secondaryjoin:
-          A SQL expression that will be used as the join of
-          an association table to the child object. By default, this value is
-          computed based on the foreign key relationships of the association
-          and child tables.
-
-          :paramref:`_orm.relationship.secondaryjoin` may also be passed as a
-          callable function which is evaluated at mapper initialization time,
-          and may be passed as a Python-evaluable string when using
-          Declarative.
-
-          .. warning:: When passed as a Python-evaluable string, the
-             argument is interpreted using Python's ``eval()`` function.
-             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
-             See :ref:`declarative_relationship_eval` for details on
-             declarative evaluation of :func:`_orm.relationship` arguments.
-
-          .. seealso::
-
-              :ref:`relationship_primaryjoin`
-
-        :param single_parent:
-          When True, installs a validator which will prevent objects
-          from being associated with more than one parent at a time.
-          This is used for many-to-one or many-to-many relationships that
-          should be treated either as one-to-one or one-to-many.  Its usage
-          is optional, except for :func:`_orm.relationship` constructs which
-          are many-to-one or many-to-many and also
-          specify the ``delete-orphan`` cascade option.  The
-          :func:`_orm.relationship` construct itself will raise an error
-          instructing when this option is required.
-
-          .. seealso::
-
-            :ref:`unitofwork_cascades` - includes detail on when the
-            :paramref:`_orm.relationship.single_parent`
-            flag may be appropriate.
-
-        :param uselist:
-          A boolean that indicates if this property should be loaded as a
-          list or a scalar. In most cases, this value is determined
-          automatically by :func:`_orm.relationship` at mapper configuration
-          time, based on the type and direction
-          of the relationship - one to many forms a list, many to one
-          forms a scalar, many to many is a list. If a scalar is desired
-          where normally a list would be present, such as a bi-directional
-          one-to-one relationship, set :paramref:`_orm.relationship.uselist`
-          to
-          False.
-
-          The :paramref:`_orm.relationship.uselist`
-          flag is also available on an
-          existing :func:`_orm.relationship`
-          construct as a read-only attribute,
-          which can be used to determine if this :func:`_orm.relationship`
-          deals
-          with collections or scalar attributes::
-
-              >>> User.addresses.property.uselist
-              True
-
-          .. seealso::
-
-              :ref:`relationships_one_to_one` - Introduction to the "one to
-              one" relationship pattern, which is typically when the
-              :paramref:`_orm.relationship.uselist` flag is needed.
-
-        :param viewonly=False:
-          When set to ``True``, the relationship is used only for loading
-          objects, and not for any persistence operation.  A
-          :func:`_orm.relationship` which specifies
-          :paramref:`_orm.relationship.viewonly` can work
-          with a wider range of SQL operations within the
-          :paramref:`_orm.relationship.primaryjoin` condition, including
-          operations that feature the use of a variety of comparison operators
-          as well as SQL functions such as :func:`_expression.cast`.  The
-          :paramref:`_orm.relationship.viewonly`
-          flag is also of general use when defining any kind of
-          :func:`_orm.relationship` that doesn't represent
-          the full set of related objects, to prevent modifications of the
-          collection from resulting in persistence operations.
-
-          When using the :paramref:`_orm.relationship.viewonly` flag in
-          conjunction with backrefs, the originating relationship for a
-          particular state change will not produce state changes within the
-          viewonly relationship.   This is the behavior implied by
-          :paramref:`_orm.relationship.sync_backref` being set to False.
-
-          .. versionchanged:: 1.3.17 - the
-             :paramref:`_orm.relationship.sync_backref` flag is set to False
-                 when using viewonly in conjunction with backrefs.
-
-          .. seealso::
-
-            :paramref:`_orm.relationship.sync_backref`
-
-        :param sync_backref:
-          A boolean that enables the events used to synchronize the in-Python
-          attributes when this relationship is target of either
-          :paramref:`_orm.relationship.backref` or
-          :paramref:`_orm.relationship.back_populates`.
-
-          Defaults to ``None``, which indicates that an automatic value should
-          be selected based on the value of the
-          :paramref:`_orm.relationship.viewonly` flag.  When left at its
-          default, changes in state will be back-populated only if neither
-          sides of a relationship is viewonly.
-
-          .. versionadded:: 1.3.17
-
-          .. versionchanged:: 1.4 - A relationship that specifies
-             :paramref:`_orm.relationship.viewonly` automatically implies
-             that :paramref:`_orm.relationship.sync_backref` is ``False``.
-
-          .. seealso::
-
-            :paramref:`_orm.relationship.viewonly`
-
-        :param omit_join:
-          Allows manual control over the "selectin" automatic join
-          optimization.  Set to ``False`` to disable the "omit join" feature
-          added in SQLAlchemy 1.3; or leave as ``None`` to leave automatic
-          optimization in place.
-
-          .. note:: This flag may only be set to ``False``.   It is not
-             necessary to set it to ``True`` as the "omit_join" optimization is
-             automatically detected; if it is not detected, then the
-             optimization is not supported.
-
-             .. versionchanged:: 1.3.11  setting ``omit_join`` to True will now
-                emit a warning as this was not the intended use of this flag.
-
-          .. versionadded:: 1.3
-
-
-        """
         super(RelationshipProperty, self).__init__()
 
         self.uselist = uselist
index ead0d06efccf4ce58a9c3ee671190532ef639eed..47da85716f40a38c353517c291c4fc1c55ef4b4c 100644 (file)
@@ -5,8 +5,8 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 
-from . import class_mapper
 from . import exc as orm_exc
+from .base import class_mapper
 from .session import Session
 from .. import exc as sa_exc
 from ..util import create_proxy_methods
index e0dd5941d7698aac2d63e9b785b5a089be544546..c1ce3b8455676c586297a2b25d66807ca1f017e6 100644 (file)
@@ -968,172 +968,6 @@ class LoaderCriteriaOption(CriteriaOption):
         propagate_to_loaders=True,
         track_closure_variables=True,
     ):
-        """Add additional WHERE criteria to the load for all occurrences of
-        a particular entity.
-
-        .. versionadded:: 1.4
-
-        The :func:`_orm.with_loader_criteria` option is intended to add
-        limiting criteria to a particular kind of entity in a query,
-        **globally**, meaning it will apply to the entity as it appears
-        in the SELECT query as well as within any subqueries, join
-        conditions, and relationship loads, including both eager and lazy
-        loaders, without the need for it to be specified in any particular
-        part of the query.    The rendering logic uses the same system used by
-        single table inheritance to ensure a certain discriminator is applied
-        to a table.
-
-        E.g., using :term:`2.0-style` queries, we can limit the way the
-        ``User.addresses`` collection is loaded, regardless of the kind
-        of loading used::
-
-            from sqlalchemy.orm import with_loader_criteria
-
-            stmt = select(User).options(
-                selectinload(User.addresses),
-                with_loader_criteria(Address, Address.email_address != 'foo'))
-            )
-
-        Above, the "selectinload" for ``User.addresses`` will apply the
-        given filtering criteria to the WHERE clause.
-
-        Another example, where the filtering will be applied to the
-        ON clause of the join, in this example using :term:`1.x style`
-        queries::
-
-            q = session.query(User).outerjoin(User.addresses).options(
-                with_loader_criteria(Address, Address.email_address != 'foo'))
-            )
-
-        The primary purpose of :func:`_orm.with_loader_criteria` is to use
-        it in the :meth:`_orm.SessionEvents.do_orm_execute` event handler
-        to ensure that all occurrences of a particular entity are filtered
-        in a certain way, such as filtering for access control roles.    It
-        also can be used to apply criteria to relationship loads.  In the
-        example below, we can apply a certain set of rules to all queries
-        emitted by a particular :class:`_orm.Session`::
-
-            session = Session(bind=engine)
-
-            @event.listens_for("do_orm_execute", session)
-            def _add_filtering_criteria(execute_state):
-
-                if (
-                    execute_state.is_select
-                    and not execute_state.is_column_load
-                    and not execute_state.is_relationship_load
-                ):
-                    execute_state.statement = execute_state.statement.options(
-                        with_loader_criteria(
-                            SecurityRole,
-                            lambda cls: cls.role.in_(['some_role']),
-                            include_aliases=True
-                        )
-                    )
-
-        In the above example, the :meth:`_orm.SessionEvents.do_orm_execute`
-        event will intercept all queries emitted using the
-        :class:`_orm.Session`. For those queries which are SELECT statements
-        and are not attribute or relationship loads a custom
-        :func:`_orm.with_loader_criteria` option is added to the query.    The
-        :func:`_orm.with_loader_criteria` option will be used in the given
-        statement and will also be automatically propagated to all relationship
-        loads that descend from this query.
-
-        The criteria argument given is a ``lambda`` that accepts a ``cls``
-        argument.  The given class will expand to include all mapped subclass
-        and need not itself be a mapped class.
-
-        .. tip::
-
-           When using :func:`_orm.with_loader_criteria` option in
-           conjunction with the :func:`_orm.contains_eager` loader option,
-           it's important to note that :func:`_orm.with_loader_criteria` only
-           affects the part of the query that determines what SQL is rendered
-           in terms of the WHERE and FROM clauses. The
-           :func:`_orm.contains_eager` option does not affect the rendering of
-           the SELECT statement outside of the columns clause, so does not have
-           any interaction with the :func:`_orm.with_loader_criteria` option.
-           However, the way things "work" is that :func:`_orm.contains_eager`
-           is meant to be used with a query that is already selecting from the
-           additional entities in some way, where
-           :func:`_orm.with_loader_criteria` can apply it's additional
-           criteria.
-
-           In the example below, assuming a mapping relationship as
-           ``A -> A.bs -> B``, the given :func:`_orm.with_loader_criteria`
-           option will affect the way in which the JOIN is rendered::
-
-                stmt = select(A).join(A.bs).options(
-                    contains_eager(A.bs),
-                    with_loader_criteria(B, B.flag == 1)
-                )
-
-           Above, the given :func:`_orm.with_loader_criteria` option will
-           affect the ON clause of the JOIN that is specified by
-           ``.join(A.bs)``, so is applied as expected. The
-           :func:`_orm.contains_eager` option has the effect that columns from
-           ``B`` are added to the columns clause::
-
-                SELECT
-                    b.id, b.a_id, b.data, b.flag,
-                    a.id AS id_1,
-                    a.data AS data_1
-                FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
-
-
-           The use of the :func:`_orm.contains_eager` option within the above
-           statement has no effect on the behavior of the
-           :func:`_orm.with_loader_criteria` option. If the
-           :func:`_orm.contains_eager` option were omitted, the SQL would be
-           the same as regards the FROM and WHERE clauses, where
-           :func:`_orm.with_loader_criteria` continues to add its criteria to
-           the ON clause of the JOIN. The addition of
-           :func:`_orm.contains_eager` only affects the columns clause, in that
-           additional columns against ``b`` are added which are then consumed
-           by the ORM to produce ``B`` instances.
-
-        .. warning:: The use of a lambda inside of the call to
-          :func:`_orm.with_loader_criteria` is only invoked **once per unique
-          class**. Custom functions should not be invoked within this lambda.
-          See :ref:`engine_lambda_caching` for an overview of the "lambda SQL"
-          feature, which is for advanced use only.
-
-        :param entity_or_base: a mapped class, or a class that is a super
-         class of a particular set of mapped classes, to which the rule
-         will apply.
-
-        :param where_criteria: a Core SQL expression that applies limiting
-         criteria.   This may also be a "lambda:" or Python function that
-         accepts a target class as an argument, when the given class is
-         a base with many different mapped subclasses.
-
-        :param include_aliases: if True, apply the rule to :func:`_orm.aliased`
-         constructs as well.
-
-        :param propagate_to_loaders: defaults to True, apply to relationship
-         loaders such as lazy loaders.
-
-
-         .. seealso::
-
-            :ref:`examples_session_orm_events` - includes examples of using
-            :func:`_orm.with_loader_criteria`.
-
-            :ref:`do_orm_execute_global_criteria` - basic example on how to
-            combine :func:`_orm.with_loader_criteria` with the
-            :meth:`_orm.SessionEvents.do_orm_execute` event.
-
-        :param track_closure_variables: when False, closure variables inside
-         of a lambda expression will not be used as part of
-         any cache key.    This allows more complex expressions to be used
-         inside of a lambda expression but requires that the lambda ensures
-         it returns the identical SQL every time given a particular class.
-
-         .. versionadded:: 1.4.0b2
-
-        """
-
         entity = inspection.inspect(entity_or_base, False)
         if entity is None:
             self.root_entity = entity_or_base
index 9d66c8f61d8a3995012802cdf77e26f3a7554e9a..b558f9bf56362987a112e47c311cc44cb5801907 100644 (file)
 # This module is part of SQLAlchemy and is released under
 # the MIT License: https://www.opensource.org/licenses/mit-license.php
 
-from .base import Executable
-from .compiler import COLLECT_CARTESIAN_PRODUCTS
-from .compiler import FROM_LINTING
-from .compiler import NO_LINTING
-from .compiler import WARN_LINTING
-from .expression import Alias
-from .expression import alias
-from .expression import all_
-from .expression import and_
-from .expression import any_
-from .expression import asc
-from .expression import between
-from .expression import bindparam
-from .expression import case
-from .expression import cast
-from .expression import ClauseElement
-from .expression import collate
-from .expression import column
-from .expression import ColumnCollection
-from .expression import ColumnElement
-from .expression import CompoundSelect
-from .expression import cte
-from .expression import Delete
-from .expression import delete
-from .expression import desc
-from .expression import distinct
-from .expression import except_
-from .expression import except_all
-from .expression import exists
-from .expression import extract
-from .expression import false
-from .expression import False_
-from .expression import FromClause
-from .expression import func
-from .expression import funcfilter
-from .expression import Insert
-from .expression import insert
-from .expression import intersect
-from .expression import intersect_all
-from .expression import Join
-from .expression import join
-from .expression import label
-from .expression import LABEL_STYLE_DEFAULT
-from .expression import LABEL_STYLE_DISAMBIGUATE_ONLY
-from .expression import LABEL_STYLE_NONE
-from .expression import LABEL_STYLE_TABLENAME_PLUS_COL
-from .expression import lambda_stmt
-from .expression import LambdaElement
-from .expression import lateral
-from .expression import literal
-from .expression import literal_column
-from .expression import modifier
-from .expression import not_
-from .expression import null
-from .expression import nulls_first
-from .expression import nulls_last
-from .expression import nullsfirst
-from .expression import nullslast
-from .expression import or_
-from .expression import outerjoin
-from .expression import outparam
-from .expression import over
-from .expression import quoted_name
-from .expression import Select
-from .expression import select
-from .expression import Selectable
-from .expression import StatementLambdaElement
-from .expression import Subquery
-from .expression import table
-from .expression import TableClause
-from .expression import TableSample
-from .expression import tablesample
-from .expression import text
-from .expression import true
-from .expression import True_
-from .expression import tuple_
-from .expression import type_coerce
-from .expression import union
-from .expression import union_all
-from .expression import Update
-from .expression import update
-from .expression import Values
-from .expression import values
-from .expression import within_group
-from .visitors import ClauseVisitor
+from .base import Executable as Executable
+from .compiler import COLLECT_CARTESIAN_PRODUCTS as COLLECT_CARTESIAN_PRODUCTS
+from .compiler import FROM_LINTING as FROM_LINTING
+from .compiler import NO_LINTING as NO_LINTING
+from .compiler import WARN_LINTING as WARN_LINTING
+from .expression import Alias as Alias
+from .expression import alias as alias
+from .expression import all_ as all_
+from .expression import and_ as and_
+from .expression import any_ as any_
+from .expression import asc as asc
+from .expression import between as between
+from .expression import bindparam as bindparam
+from .expression import case as case
+from .expression import cast as cast
+from .expression import ClauseElement as ClauseElement
+from .expression import collate as collate
+from .expression import column as column
+from .expression import ColumnCollection as ColumnCollection
+from .expression import ColumnElement as ColumnElement
+from .expression import CompoundSelect as CompoundSelect
+from .expression import cte as cte
+from .expression import Delete as Delete
+from .expression import delete as delete
+from .expression import desc as desc
+from .expression import distinct as distinct
+from .expression import except_ as except_
+from .expression import except_all as except_all
+from .expression import exists as exists
+from .expression import extract as extract
+from .expression import false as false
+from .expression import False_ as False_
+from .expression import FromClause as FromClause
+from .expression import func as func
+from .expression import funcfilter as funcfilter
+from .expression import Insert as Insert
+from .expression import insert as insert
+from .expression import intersect as intersect
+from .expression import intersect_all as intersect_all
+from .expression import Join as Join
+from .expression import join as join
+from .expression import label as label
+from .expression import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
+from .expression import lambda_stmt as lambda_stmt
+from .expression import LambdaElement as LambdaElement
+from .expression import lateral as lateral
+from .expression import literal as literal
+from .expression import literal_column as literal_column
+from .expression import modifier as modifier
+from .expression import not_ as not_
+from .expression import null as null
+from .expression import nulls_first as nulls_first
+from .expression import nulls_last as nulls_last
+from .expression import nullsfirst as nullsfirst
+from .expression import nullslast as nullslast
+from .expression import or_ as or_
+from .expression import outerjoin as outerjoin
+from .expression import outparam as outparam
+from .expression import over as over
+from .expression import quoted_name as quoted_name
+from .expression import Select as Select
+from .expression import select as select
+from .expression import Selectable as Selectable
+from .expression import StatementLambdaElement as StatementLambdaElement
+from .expression import Subquery as Subquery
+from .expression import table as table
+from .expression import TableClause as TableClause
+from .expression import TableSample as TableSample
+from .expression import tablesample as tablesample
+from .expression import text as text
+from .expression import true as true
+from .expression import True_ as True_
+from .expression import tuple_ as tuple_
+from .expression import type_coerce as type_coerce
+from .expression import union as union
+from .expression import union_all as union_all
+from .expression import Update as Update
+from .expression import update as update
+from .expression import Values as Values
+from .expression import values as values
+from .expression import within_group as within_group
+from .visitors import ClauseVisitor as ClauseVisitor
 
-
-def __go(lcls):
-    global __all__
-    from .. import util as _sa_util
-
-    import inspect as _inspect
-
-    __all__ = sorted(
-        name
-        for name, obj in lcls.items()
-        if not (name.startswith("_") or _inspect.ismodule(obj))
+if True:
+    # work around zimports bug
+    from .expression import (
+        LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
+    )
+    from .expression import LABEL_STYLE_NONE as LABEL_STYLE_NONE
+    from .expression import (
+        LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
     )
 
-    from .annotation import _prepare_annotations
-    from .annotation import Annotated
-    from .elements import AnnotatedColumnElement
-    from .elements import ClauseList
-    from .selectable import AnnotatedFromClause
 
-    # from .traversals import _preconfigure_traversals
+def __go(lcls):
+    from .. import util as _sa_util
 
     from . import base
     from . import coercions
     from . import elements
-    from . import events
     from . import lambdas
     from . import selectable
     from . import schema
-    from . import sqltypes
     from . import traversals
     from . import type_api
 
@@ -130,20 +118,19 @@ def __go(lcls):
     coercions.lambdas = lambdas
     coercions.schema = schema
     coercions.selectable = selectable
-    coercions.sqltypes = sqltypes
     coercions.traversals = traversals
 
+    from .annotation import _prepare_annotations
+    from .annotation import Annotated
+    from .elements import AnnotatedColumnElement
+    from .elements import ClauseList
+    from .selectable import AnnotatedFromClause
+
     _prepare_annotations(ColumnElement, AnnotatedColumnElement)
     _prepare_annotations(FromClause, AnnotatedFromClause)
     _prepare_annotations(ClauseList, Annotated)
 
-    # this is expensive at import time; elements that are used can create
-    # their traversals on demand
-    # _preconfigure_traversals(ClauseElement)
-
     _sa_util.preloaded.import_prefix("sqlalchemy.sql")
 
-    from . import naming
-
 
 __go(locals())
diff --git a/lib/sqlalchemy/sql/_dml_constructors.py b/lib/sqlalchemy/sql/_dml_constructors.py
new file mode 100644 (file)
index 0000000..e62edf5
--- /dev/null
@@ -0,0 +1,231 @@
+# sql/_dml_constructors.py
+# Copyright (C) 2005-2022 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 .dml import Delete
+from .dml import Insert
+from .dml import Update
+
+
+def insert(table):
+    """Construct an :class:`_expression.Insert` object.
+
+    E.g.::
+
+        from sqlalchemy import insert
+
+        stmt = (
+            insert(user_table).
+            values(name='username', fullname='Full Username')
+        )
+
+    Similar functionality is available via the
+    :meth:`_expression.TableClause.insert` method on
+    :class:`_schema.Table`.
+
+    .. seealso::
+
+        :ref:`coretutorial_insert_expressions` - in the
+        :ref:`1.x tutorial <sqlexpression_toplevel>`
+
+        :ref:`tutorial_core_insert` - in the :ref:`unified_tutorial`
+
+
+    :param table: :class:`_expression.TableClause`
+     which is the subject of the
+     insert.
+
+    :param values: collection of values to be inserted; see
+     :meth:`_expression.Insert.values`
+     for a description of allowed formats here.
+     Can be omitted entirely; a :class:`_expression.Insert` construct
+     will also dynamically render the VALUES clause at execution time
+     based on the parameters passed to :meth:`_engine.Connection.execute`.
+
+    :param inline: if True, no attempt will be made to retrieve the
+     SQL-generated default values to be provided within the statement;
+     in particular,
+     this allows SQL expressions to be rendered 'inline' within the
+     statement without the need to pre-execute them beforehand; for
+     backends that support "returning", this turns off the "implicit
+     returning" feature for the statement.
+
+    If both :paramref:`_expression.Insert.values` and compile-time bind
+    parameters are present, the compile-time bind parameters override the
+    information specified within :paramref:`_expression.Insert.values` on a
+    per-key basis.
+
+    The keys within :paramref:`_expression.Insert.values` can be either
+    :class:`~sqlalchemy.schema.Column` objects or their string
+    identifiers. Each key may reference one of:
+
+    * a literal data value (i.e. string, number, etc.);
+    * a Column object;
+    * a SELECT statement.
+
+    If a ``SELECT`` statement is specified which references this
+    ``INSERT`` statement's table, the statement will be correlated
+    against the ``INSERT`` statement.
+
+    .. seealso::
+
+        :ref:`coretutorial_insert_expressions` - SQL Expression Tutorial
+
+        :ref:`inserts_and_updates` - SQL Expression Tutorial
+
+    """
+    return Insert(table)
+
+
+def update(table):
+    r"""Construct an :class:`_expression.Update` object.
+
+    E.g.::
+
+        from sqlalchemy import update
+
+        stmt = (
+            update(user_table).
+            where(user_table.c.id == 5).
+            values(name='user #5')
+        )
+
+    Similar functionality is available via the
+    :meth:`_expression.TableClause.update` method on
+    :class:`_schema.Table`.
+
+    .. seealso::
+
+        :ref:`inserts_and_updates` - in the
+        :ref:`1.x tutorial <sqlexpression_toplevel>`
+
+        :ref:`tutorial_core_update_delete` - in the :ref:`unified_tutorial`
+
+
+
+    :param table: A :class:`_schema.Table`
+     object representing the database
+     table to be updated.
+
+    :param whereclause: Optional SQL expression describing the ``WHERE``
+     condition of the ``UPDATE`` statement; is equivalent to using the
+     more modern :meth:`~Update.where()` method to specify the ``WHERE``
+     clause.
+
+    :param values:
+      Optional dictionary which specifies the ``SET`` conditions of the
+      ``UPDATE``.  If left as ``None``, the ``SET``
+      conditions are determined from those parameters passed to the
+      statement during the execution and/or compilation of the
+      statement.   When compiled standalone without any parameters,
+      the ``SET`` clause generates for all columns.
+
+      Modern applications may prefer to use the generative
+      :meth:`_expression.Update.values` method to set the values of the
+      UPDATE statement.
+
+    :param inline:
+      if True, SQL defaults present on :class:`_schema.Column` objects via
+      the ``default`` keyword will be compiled 'inline' into the statement
+      and not pre-executed.  This means that their values will not
+      be available in the dictionary returned from
+      :meth:`_engine.CursorResult.last_updated_params`.
+
+    :param preserve_parameter_order: if True, the update statement is
+      expected to receive parameters **only** via the
+      :meth:`_expression.Update.values` method,
+      and they must be passed as a Python
+      ``list`` of 2-tuples. The rendered UPDATE statement will emit the SET
+      clause for each referenced column maintaining this order.
+
+      .. versionadded:: 1.0.10
+
+      .. seealso::
+
+        :ref:`updates_order_parameters` - illustrates the
+        :meth:`_expression.Update.ordered_values` method.
+
+    If both ``values`` and compile-time bind parameters are present, the
+    compile-time bind parameters override the information specified
+    within ``values`` on a per-key basis.
+
+    The keys within ``values`` can be either :class:`_schema.Column`
+    objects or their string identifiers (specifically the "key" of the
+    :class:`_schema.Column`, normally but not necessarily equivalent to
+    its "name").  Normally, the
+    :class:`_schema.Column` objects used here are expected to be
+    part of the target :class:`_schema.Table` that is the table
+    to be updated.  However when using MySQL, a multiple-table
+    UPDATE statement can refer to columns from any of
+    the tables referred to in the WHERE clause.
+
+    The values referred to in ``values`` are typically:
+
+    * a literal data value (i.e. string, number, etc.)
+    * a SQL expression, such as a related :class:`_schema.Column`,
+      a scalar-returning :func:`_expression.select` construct,
+      etc.
+
+    When combining :func:`_expression.select` constructs within the
+    values clause of an :func:`_expression.update`
+    construct, the subquery represented
+    by the :func:`_expression.select` should be *correlated* to the
+    parent table, that is, providing criterion which links the table inside
+    the subquery to the outer table being updated::
+
+        users.update().values(
+                name=select(addresses.c.email_address).\
+                        where(addresses.c.user_id==users.c.id).\
+                        scalar_subquery()
+            )
+
+    .. seealso::
+
+        :ref:`inserts_and_updates` - SQL Expression
+        Language Tutorial
+
+
+    """
+    return Update(table)
+
+
+def delete(table):
+    r"""Construct :class:`_expression.Delete` object.
+
+    E.g.::
+
+        from sqlalchemy import delete
+
+        stmt = (
+            delete(user_table).
+            where(user_table.c.id == 5)
+        )
+
+    Similar functionality is available via the
+    :meth:`_expression.TableClause.delete` method on
+    :class:`_schema.Table`.
+
+    .. seealso::
+
+        :ref:`inserts_and_updates` - in the
+        :ref:`1.x tutorial <sqlexpression_toplevel>`
+
+        :ref:`tutorial_core_update_delete` - in the :ref:`unified_tutorial`
+
+
+    :param table: The table to delete rows from.
+
+    :param whereclause: Optional SQL expression describing the ``WHERE``
+     condition of the ``DELETE`` statement; is equivalent to using the
+     more modern :meth:`~Delete.where()` method to specify the ``WHERE``
+     clause.
+
+    .. seealso::
+
+        :ref:`deletes` - SQL Expression Tutorial
+
+    """
+    return Delete(table)
diff --git a/lib/sqlalchemy/sql/_elements_constructors.py b/lib/sqlalchemy/sql/_elements_constructors.py
new file mode 100644 (file)
index 0000000..a8c9372
--- /dev/null
@@ -0,0 +1,1637 @@
+# sql/_elements_constructors.py
+# Copyright (C) 2005-2022 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
+
+import typing
+from typing import Any
+from typing import cast as _typing_cast
+from typing import Optional
+from typing import overload
+from typing import Type
+from typing import TypeVar
+from typing import Union
+
+from . import coercions
+from . import operators
+from . import roles
+from .base import NO_ARG
+from .coercions import _document_text_coercion
+from .elements import BindParameter
+from .elements import BooleanClauseList
+from .elements import Case
+from .elements import Cast
+from .elements import CollationClause
+from .elements import CollectionAggregate
+from .elements import ColumnClause
+from .elements import ColumnElement
+from .elements import Extract
+from .elements import False_
+from .elements import FunctionFilter
+from .elements import Label
+from .elements import Null
+from .elements import Over
+from .elements import TextClause
+from .elements import True_
+from .elements import Tuple
+from .elements import TypeCoerce
+from .elements import UnaryExpression
+from .elements import WithinGroup
+
+if typing.TYPE_CHECKING:
+    from elements import BinaryExpression
+
+    from . import sqltypes
+    from .functions import FunctionElement
+    from .selectable import FromClause
+    from .type_api import TypeEngine
+
+_T = TypeVar("_T")
+
+
+def all_(expr):
+    """Produce an ALL expression.
+
+    For dialects such as that of PostgreSQL, this operator applies
+    to usage of the :class:`_types.ARRAY` datatype, for that of
+    MySQL, it may apply to a subquery.  e.g.::
+
+        # renders on PostgreSQL:
+        # '5 = ALL (somearray)'
+        expr = 5 == all_(mytable.c.somearray)
+
+        # renders on MySQL:
+        # '5 = ALL (SELECT value FROM table)'
+        expr = 5 == all_(select(table.c.value))
+
+    Comparison to NULL may work using ``None``::
+
+        None == all_(mytable.c.somearray)
+
+    The any_() / all_() operators also feature a special "operand flipping"
+    behavior such that if any_() / all_() are used on the left side of a
+    comparison using a standalone operator such as ``==``, ``!=``, etc.
+    (not including operator methods such as
+    :meth:`_sql.ColumnOperators.is_`) the rendered expression is flipped::
+
+        # would render '5 = ALL (column)`
+        all_(mytable.c.column) == 5
+
+    Or with ``None``, which note will not perform
+    the usual step of rendering "IS" as is normally the case for NULL::
+
+        # would render 'NULL = ALL(somearray)'
+        all_(mytable.c.somearray) == None
+
+    .. versionchanged:: 1.4.26  repaired the use of any_() / all_()
+       comparing to NULL on the right side to be flipped to the left.
+
+    The column-level :meth:`_sql.ColumnElement.all_` method (not to be
+    confused with :class:`_types.ARRAY` level
+    :meth:`_types.ARRAY.Comparator.all`) is shorthand for
+    ``all_(col)``::
+
+        5 == mytable.c.somearray.all_()
+
+    .. seealso::
+
+        :meth:`_sql.ColumnOperators.all_`
+
+        :func:`_expression.any_`
+
+    """
+    return CollectionAggregate._create_all(expr)
+
+
+def and_(*clauses):
+    r"""Produce a conjunction of expressions joined by ``AND``.
+
+    E.g.::
+
+        from sqlalchemy import and_
+
+        stmt = select(users_table).where(
+                        and_(
+                            users_table.c.name == 'wendy',
+                            users_table.c.enrolled == True
+                        )
+                    )
+
+    The :func:`.and_` conjunction is also available using the
+    Python ``&`` operator (though note that compound expressions
+    need to be parenthesized in order to function with Python
+    operator precedence behavior)::
+
+        stmt = select(users_table).where(
+                        (users_table.c.name == 'wendy') &
+                        (users_table.c.enrolled == True)
+                    )
+
+    The :func:`.and_` operation is also implicit in some cases;
+    the :meth:`_expression.Select.where`
+    method for example can be invoked multiple
+    times against a statement, which will have the effect of each
+    clause being combined using :func:`.and_`::
+
+        stmt = select(users_table).\
+                where(users_table.c.name == 'wendy').\
+                where(users_table.c.enrolled == True)
+
+    The :func:`.and_` construct must be given at least one positional
+    argument in order to be valid; a :func:`.and_` construct with no
+    arguments is ambiguous.   To produce an "empty" or dynamically
+    generated :func:`.and_`  expression, from a given list of expressions,
+    a "default" element of ``True`` should be specified::
+
+        criteria = and_(True, *expressions)
+
+    The above expression will compile to SQL as the expression ``true``
+    or ``1 = 1``, depending on backend, if no other expressions are
+    present.  If expressions are present, then the ``True`` value is
+    ignored as it does not affect the outcome of an AND expression that
+    has other elements.
+
+    .. deprecated:: 1.4  The :func:`.and_` element now requires that at
+       least one argument is passed; creating the :func:`.and_` construct
+       with no arguments is deprecated, and will emit a deprecation warning
+       while continuing to produce a blank SQL string.
+
+    .. seealso::
+
+        :func:`.or_`
+
+    """
+    return BooleanClauseList.and_(*clauses)
+
+
+def any_(expr):
+    """Produce an ANY expression.
+
+    For dialects such as that of PostgreSQL, this operator applies
+    to usage of the :class:`_types.ARRAY` datatype, for that of
+    MySQL, it may apply to a subquery.  e.g.::
+
+        # renders on PostgreSQL:
+        # '5 = ANY (somearray)'
+        expr = 5 == any_(mytable.c.somearray)
+
+        # renders on MySQL:
+        # '5 = ANY (SELECT value FROM table)'
+        expr = 5 == any_(select(table.c.value))
+
+    Comparison to NULL may work using ``None`` or :func:`_sql.null`::
+
+        None == any_(mytable.c.somearray)
+
+    The any_() / all_() operators also feature a special "operand flipping"
+    behavior such that if any_() / all_() are used on the left side of a
+    comparison using a standalone operator such as ``==``, ``!=``, etc.
+    (not including operator methods such as
+    :meth:`_sql.ColumnOperators.is_`) the rendered expression is flipped::
+
+        # would render '5 = ANY (column)`
+        any_(mytable.c.column) == 5
+
+    Or with ``None``, which note will not perform
+    the usual step of rendering "IS" as is normally the case for NULL::
+
+        # would render 'NULL = ANY(somearray)'
+        any_(mytable.c.somearray) == None
+
+    .. versionchanged:: 1.4.26  repaired the use of any_() / all_()
+       comparing to NULL on the right side to be flipped to the left.
+
+    The column-level :meth:`_sql.ColumnElement.any_` method (not to be
+    confused with :class:`_types.ARRAY` level
+    :meth:`_types.ARRAY.Comparator.any`) is shorthand for
+    ``any_(col)``::
+
+        5 = mytable.c.somearray.any_()
+
+    .. seealso::
+
+        :meth:`_sql.ColumnOperators.any_`
+
+        :func:`_expression.all_`
+
+    """
+    return CollectionAggregate._create_any(expr)
+
+
+def asc(column):
+    """Produce an ascending ``ORDER BY`` clause element.
+
+    e.g.::
+
+        from sqlalchemy import asc
+        stmt = select(users_table).order_by(asc(users_table.c.name))
+
+    will produce SQL as::
+
+        SELECT id, name FROM user ORDER BY name ASC
+
+    The :func:`.asc` function is a standalone version of the
+    :meth:`_expression.ColumnElement.asc`
+    method available on all SQL expressions,
+    e.g.::
+
+
+        stmt = select(users_table).order_by(users_table.c.name.asc())
+
+    :param column: A :class:`_expression.ColumnElement` (e.g.
+     scalar SQL expression)
+     with which to apply the :func:`.asc` operation.
+
+    .. seealso::
+
+        :func:`.desc`
+
+        :func:`.nulls_first`
+
+        :func:`.nulls_last`
+
+        :meth:`_expression.Select.order_by`
+
+    """
+    return UnaryExpression._create_asc(column)
+
+
+def collate(expression, collation):
+    """Return the clause ``expression COLLATE collation``.
+
+    e.g.::
+
+        collate(mycolumn, 'utf8_bin')
+
+    produces::
+
+        mycolumn COLLATE utf8_bin
+
+    The collation expression is also quoted if it is a case sensitive
+    identifier, e.g. contains uppercase characters.
+
+    .. versionchanged:: 1.2 quoting is automatically applied to COLLATE
+       expressions if they are case sensitive.
+
+    """
+    return CollationClause._create_collation_expression(expression, collation)
+
+
+def between(expr, lower_bound, upper_bound, symmetric=False):
+    """Produce a ``BETWEEN`` predicate clause.
+
+    E.g.::
+
+        from sqlalchemy import between
+        stmt = select(users_table).where(between(users_table.c.id, 5, 7))
+
+    Would produce SQL resembling::
+
+        SELECT id, name FROM user WHERE id BETWEEN :id_1 AND :id_2
+
+    The :func:`.between` function is a standalone version of the
+    :meth:`_expression.ColumnElement.between` method available on all
+    SQL expressions, as in::
+
+        stmt = select(users_table).where(users_table.c.id.between(5, 7))
+
+    All arguments passed to :func:`.between`, including the left side
+    column expression, are coerced from Python scalar values if a
+    the value is not a :class:`_expression.ColumnElement` subclass.
+    For example,
+    three fixed values can be compared as in::
+
+        print(between(5, 3, 7))
+
+    Which would produce::
+
+        :param_1 BETWEEN :param_2 AND :param_3
+
+    :param expr: a column expression, typically a
+     :class:`_expression.ColumnElement`
+     instance or alternatively a Python scalar expression to be coerced
+     into a column expression, serving as the left side of the ``BETWEEN``
+     expression.
+
+    :param lower_bound: a column or Python scalar expression serving as the
+     lower bound of the right side of the ``BETWEEN`` expression.
+
+    :param upper_bound: a column or Python scalar expression serving as the
+     upper bound of the right side of the ``BETWEEN`` expression.
+
+    :param symmetric: if True, will render " BETWEEN SYMMETRIC ". Note
+     that not all databases support this syntax.
+
+     .. versionadded:: 0.9.5
+
+    .. seealso::
+
+        :meth:`_expression.ColumnElement.between`
+
+    """
+    expr = coercions.expect(roles.ExpressionElementRole, expr)
+    return expr.between(lower_bound, upper_bound, symmetric=symmetric)
+
+
+def outparam(key, type_=None):
+    """Create an 'OUT' parameter for usage in functions (stored procedures),
+    for databases which support them.
+
+    The ``outparam`` can be used like a regular function parameter.
+    The "output" value will be available from the
+    :class:`~sqlalchemy.engine.CursorResult` object via its ``out_parameters``
+    attribute, which returns a dictionary containing the values.
+
+    """
+    return BindParameter(key, None, type_=type_, unique=False, isoutparam=True)
+
+
+@overload
+def not_(clause: "BinaryExpression[_T]") -> "BinaryExpression[_T]":
+    ...
+
+
+@overload
+def not_(clause: "ColumnElement[_T]") -> "UnaryExpression[_T]":
+    ...
+
+
+def not_(clause: "ColumnElement[_T]") -> "ColumnElement[_T]":
+    """Return a negation of the given clause, i.e. ``NOT(clause)``.
+
+    The ``~`` operator is also overloaded on all
+    :class:`_expression.ColumnElement` subclasses to produce the
+    same result.
+
+    """
+
+    return operators.inv(
+        _typing_cast(
+            "ColumnElement[_T]",
+            coercions.expect(roles.ExpressionElementRole, clause),
+        )
+    )
+
+
+def bindparam(
+    key,
+    value=NO_ARG,
+    type_: Optional[Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]] = None,
+    unique=False,
+    required=NO_ARG,
+    quote=None,
+    callable_=None,
+    expanding=False,
+    isoutparam=False,
+    literal_execute=False,
+    _compared_to_operator=None,
+    _compared_to_type=None,
+    _is_crud=False,
+) -> "BindParameter[_T]":
+    r"""Produce a "bound expression".
+
+    The return value is an instance of :class:`.BindParameter`; this
+    is a :class:`_expression.ColumnElement`
+    subclass which represents a so-called
+    "placeholder" value in a SQL expression, the value of which is
+    supplied at the point at which the statement in executed against a
+    database connection.
+
+    In SQLAlchemy, the :func:`.bindparam` construct has
+    the ability to carry along the actual value that will be ultimately
+    used at expression time.  In this way, it serves not just as
+    a "placeholder" for eventual population, but also as a means of
+    representing so-called "unsafe" values which should not be rendered
+    directly in a SQL statement, but rather should be passed along
+    to the :term:`DBAPI` as values which need to be correctly escaped
+    and potentially handled for type-safety.
+
+    When using :func:`.bindparam` explicitly, the use case is typically
+    one of traditional deferment of parameters; the :func:`.bindparam`
+    construct accepts a name which can then be referred to at execution
+    time::
+
+        from sqlalchemy import bindparam
+
+        stmt = select(users_table).\
+                    where(users_table.c.name == bindparam('username'))
+
+    The above statement, when rendered, will produce SQL similar to::
+
+        SELECT id, name FROM user WHERE name = :username
+
+    In order to populate the value of ``:username`` above, the value
+    would typically be applied at execution time to a method
+    like :meth:`_engine.Connection.execute`::
+
+        result = connection.execute(stmt, username='wendy')
+
+    Explicit use of :func:`.bindparam` is also common when producing
+    UPDATE or DELETE statements that are to be invoked multiple times,
+    where the WHERE criterion of the statement is to change on each
+    invocation, such as::
+
+        stmt = (users_table.update().
+                where(user_table.c.name == bindparam('username')).
+                values(fullname=bindparam('fullname'))
+                )
+
+        connection.execute(
+            stmt, [{"username": "wendy", "fullname": "Wendy Smith"},
+                   {"username": "jack", "fullname": "Jack Jones"},
+                   ]
+        )
+
+    SQLAlchemy's Core expression system makes wide use of
+    :func:`.bindparam` in an implicit sense.   It is typical that Python
+    literal values passed to virtually all SQL expression functions are
+    coerced into fixed :func:`.bindparam` constructs.  For example, given
+    a comparison operation such as::
+
+        expr = users_table.c.name == 'Wendy'
+
+    The above expression will produce a :class:`.BinaryExpression`
+    construct, where the left side is the :class:`_schema.Column` object
+    representing the ``name`` column, and the right side is a
+    :class:`.BindParameter` representing the literal value::
+
+        print(repr(expr.right))
+        BindParameter('%(4327771088 name)s', 'Wendy', type_=String())
+
+    The expression above will render SQL such as::
+
+        user.name = :name_1
+
+    Where the ``:name_1`` parameter name is an anonymous name.  The
+    actual string ``Wendy`` is not in the rendered string, but is carried
+    along where it is later used within statement execution.  If we
+    invoke a statement like the following::
+
+        stmt = select(users_table).where(users_table.c.name == 'Wendy')
+        result = connection.execute(stmt)
+
+    We would see SQL logging output as::
+
+        SELECT "user".id, "user".name
+        FROM "user"
+        WHERE "user".name = %(name_1)s
+        {'name_1': 'Wendy'}
+
+    Above, we see that ``Wendy`` is passed as a parameter to the database,
+    while the placeholder ``:name_1`` is rendered in the appropriate form
+    for the target database, in this case the PostgreSQL database.
+
+    Similarly, :func:`.bindparam` is invoked automatically when working
+    with :term:`CRUD` statements as far as the "VALUES" portion is
+    concerned.   The :func:`_expression.insert` construct produces an
+    ``INSERT`` expression which will, at statement execution time, generate
+    bound placeholders based on the arguments passed, as in::
+
+        stmt = users_table.insert()
+        result = connection.execute(stmt, name='Wendy')
+
+    The above will produce SQL output as::
+
+        INSERT INTO "user" (name) VALUES (%(name)s)
+        {'name': 'Wendy'}
+
+    The :class:`_expression.Insert` construct, at
+    compilation/execution time, rendered a single :func:`.bindparam`
+    mirroring the column name ``name`` as a result of the single ``name``
+    parameter we passed to the :meth:`_engine.Connection.execute` method.
+
+    :param key:
+      the key (e.g. the name) for this bind param.
+      Will be used in the generated
+      SQL statement for dialects that use named parameters.  This
+      value may be modified when part of a compilation operation,
+      if other :class:`BindParameter` objects exist with the same
+      key, or if its length is too long and truncation is
+      required.
+
+    :param value:
+      Initial value for this bind param.  Will be used at statement
+      execution time as the value for this parameter passed to the
+      DBAPI, if no other value is indicated to the statement execution
+      method for this particular parameter name.  Defaults to ``None``.
+
+    :param callable\_:
+      A callable function that takes the place of "value".  The function
+      will be called at statement execution time to determine the
+      ultimate value.   Used for scenarios where the actual bind
+      value cannot be determined at the point at which the clause
+      construct is created, but embedded bind values are still desirable.
+
+    :param type\_:
+      A :class:`.TypeEngine` class or instance representing an optional
+      datatype for this :func:`.bindparam`.  If not passed, a type
+      may be determined automatically for the bind, based on the given
+      value; for example, trivial Python types such as ``str``,
+      ``int``, ``bool``
+      may result in the :class:`.String`, :class:`.Integer` or
+      :class:`.Boolean` types being automatically selected.
+
+      The type of a :func:`.bindparam` is significant especially in that
+      the type will apply pre-processing to the value before it is
+      passed to the database.  For example, a :func:`.bindparam` which
+      refers to a datetime value, and is specified as holding the
+      :class:`.DateTime` type, may apply conversion needed to the
+      value (such as stringification on SQLite) before passing the value
+      to the database.
+
+    :param unique:
+      if True, the key name of this :class:`.BindParameter` will be
+      modified if another :class:`.BindParameter` of the same name
+      already has been located within the containing
+      expression.  This flag is used generally by the internals
+      when producing so-called "anonymous" bound expressions, it
+      isn't generally applicable to explicitly-named :func:`.bindparam`
+      constructs.
+
+    :param required:
+      If ``True``, a value is required at execution time.  If not passed,
+      it defaults to ``True`` if neither :paramref:`.bindparam.value`
+      or :paramref:`.bindparam.callable` were passed.  If either of these
+      parameters are present, then :paramref:`.bindparam.required`
+      defaults to ``False``.
+
+    :param quote:
+      True if this parameter name requires quoting and is not
+      currently known as a SQLAlchemy reserved word; this currently
+      only applies to the Oracle backend, where bound names must
+      sometimes be quoted.
+
+    :param isoutparam:
+      if True, the parameter should be treated like a stored procedure
+      "OUT" parameter.  This applies to backends such as Oracle which
+      support OUT parameters.
+
+    :param expanding:
+      if True, this parameter will be treated as an "expanding" parameter
+      at execution time; the parameter value is expected to be a sequence,
+      rather than a scalar value, and the string SQL statement will
+      be transformed on a per-execution basis to accommodate the sequence
+      with a variable number of parameter slots passed to the DBAPI.
+      This is to allow statement caching to be used in conjunction with
+      an IN clause.
+
+      .. seealso::
+
+        :meth:`.ColumnOperators.in_`
+
+        :ref:`baked_in` - with baked queries
+
+      .. note:: The "expanding" feature does not support "executemany"-
+         style parameter sets.
+
+      .. versionadded:: 1.2
+
+      .. versionchanged:: 1.3 the "expanding" bound parameter feature now
+         supports empty lists.
+
+
+    .. seealso::
+
+        :ref:`coretutorial_bind_param`
+
+        :ref:`coretutorial_insert_expressions`
+
+        :func:`.outparam`
+
+    :param literal_execute:
+      if True, the bound parameter will be rendered in the compile phase
+      with a special "POSTCOMPILE" token, and the SQLAlchemy compiler will
+      render the final value of the parameter into the SQL statement at
+      statement execution time, omitting the value from the parameter
+      dictionary / list passed to DBAPI ``cursor.execute()``.  This
+      produces a similar effect as that of using the ``literal_binds``,
+      compilation flag,  however takes place as the statement is sent to
+      the DBAPI ``cursor.execute()`` method, rather than when the statement
+      is compiled.   The primary use of this
+      capability is for rendering LIMIT / OFFSET clauses for database
+      drivers that can't accommodate for bound parameters in these
+      contexts, while allowing SQL constructs to be cacheable at the
+      compilation level.
+
+      .. versionadded:: 1.4 Added "post compile" bound parameters
+
+        .. seealso::
+
+            :ref:`change_4808`.
+
+    """
+    return BindParameter(
+        key,
+        value,
+        type_,
+        unique,
+        required,
+        quote,
+        callable_,
+        expanding,
+        isoutparam,
+        literal_execute,
+        _compared_to_operator,
+        _compared_to_type,
+        _is_crud,
+    )
+
+
+def case(*whens, value=None, else_=None) -> "Case[Any]":
+    r"""Produce a ``CASE`` expression.
+
+    The ``CASE`` construct in SQL is a conditional object that
+    acts somewhat analogously to an "if/then" construct in other
+    languages.  It returns an instance of :class:`.Case`.
+
+    :func:`.case` in its usual form is passed a series of "when"
+    constructs, that is, a list of conditions and results as tuples::
+
+        from sqlalchemy import case
+
+        stmt = select(users_table).\
+                    where(
+                        case(
+                            (users_table.c.name == 'wendy', 'W'),
+                            (users_table.c.name == 'jack', 'J'),
+                            else_='E'
+                        )
+                    )
+
+    The above statement will produce SQL resembling::
+
+        SELECT id, name FROM user
+        WHERE CASE
+            WHEN (name = :name_1) THEN :param_1
+            WHEN (name = :name_2) THEN :param_2
+            ELSE :param_3
+        END
+
+    When simple equality expressions of several values against a single
+    parent column are needed, :func:`.case` also has a "shorthand" format
+    used via the
+    :paramref:`.case.value` parameter, which is passed a column
+    expression to be compared.  In this form, the :paramref:`.case.whens`
+    parameter is passed as a dictionary containing expressions to be
+    compared against keyed to result expressions.  The statement below is
+    equivalent to the preceding statement::
+
+        stmt = select(users_table).\
+                    where(
+                        case(
+                            {"wendy": "W", "jack": "J"},
+                            value=users_table.c.name,
+                            else_='E'
+                        )
+                    )
+
+    The values which are accepted as result values in
+    :paramref:`.case.whens` as well as with :paramref:`.case.else_` are
+    coerced from Python literals into :func:`.bindparam` constructs.
+    SQL expressions, e.g. :class:`_expression.ColumnElement` constructs,
+    are accepted
+    as well.  To coerce a literal string expression into a constant
+    expression rendered inline, use the :func:`_expression.literal_column`
+    construct,
+    as in::
+
+        from sqlalchemy import case, literal_column
+
+        case(
+            (
+                orderline.c.qty > 100,
+                literal_column("'greaterthan100'")
+            ),
+            (
+                orderline.c.qty > 10,
+                literal_column("'greaterthan10'")
+            ),
+            else_=literal_column("'lessthan10'")
+        )
+
+    The above will render the given constants without using bound
+    parameters for the result values (but still for the comparison
+    values), as in::
+
+        CASE
+            WHEN (orderline.qty > :qty_1) THEN 'greaterthan100'
+            WHEN (orderline.qty > :qty_2) THEN 'greaterthan10'
+            ELSE 'lessthan10'
+        END
+
+    :param \*whens: The criteria to be compared against,
+     :paramref:`.case.whens` accepts two different forms, based on
+     whether or not :paramref:`.case.value` is used.
+
+     .. versionchanged:: 1.4 the :func:`_sql.case`
+        function now accepts the series of WHEN conditions positionally
+
+     In the first form, it accepts a list of 2-tuples; each 2-tuple
+     consists of ``(<sql expression>, <value>)``, where the SQL
+     expression is a boolean expression and "value" is a resulting value,
+     e.g.::
+
+        case(
+            (users_table.c.name == 'wendy', 'W'),
+            (users_table.c.name == 'jack', 'J')
+        )
+
+     In the second form, it accepts a Python dictionary of comparison
+     values mapped to a resulting value; this form requires
+     :paramref:`.case.value` to be present, and values will be compared
+     using the ``==`` operator, e.g.::
+
+        case(
+            {"wendy": "W", "jack": "J"},
+            value=users_table.c.name
+        )
+
+    :param value: An optional SQL expression which will be used as a
+      fixed "comparison point" for candidate values within a dictionary
+      passed to :paramref:`.case.whens`.
+
+    :param else\_: An optional SQL expression which will be the evaluated
+      result of the ``CASE`` construct if all expressions within
+      :paramref:`.case.whens` evaluate to false.  When omitted, most
+      databases will produce a result of NULL if none of the "when"
+      expressions evaluate to true.
+
+
+    """
+    return Case(*whens, value=value, else_=else_)
+
+
+def cast(
+    expression: ColumnElement,
+    type_: Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"],
+) -> "Cast[_T]":
+    r"""Produce a ``CAST`` expression.
+
+    :func:`.cast` returns an instance of :class:`.Cast`.
+
+    E.g.::
+
+        from sqlalchemy import cast, Numeric
+
+        stmt = select(cast(product_table.c.unit_price, Numeric(10, 4)))
+
+    The above statement will produce SQL resembling::
+
+        SELECT CAST(unit_price AS NUMERIC(10, 4)) FROM product
+
+    The :func:`.cast` function performs two distinct functions when
+    used.  The first is that it renders the ``CAST`` expression within
+    the resulting SQL string.  The second is that it associates the given
+    type (e.g. :class:`.TypeEngine` class or instance) with the column
+    expression on the Python side, which means the expression will take
+    on the expression operator behavior associated with that type,
+    as well as the bound-value handling and result-row-handling behavior
+    of the type.
+
+    .. versionchanged:: 0.9.0 :func:`.cast` now applies the given type
+       to the expression such that it takes effect on the bound-value,
+       e.g. the Python-to-database direction, in addition to the
+       result handling, e.g. database-to-Python, direction.
+
+    An alternative to :func:`.cast` is the :func:`.type_coerce` function.
+    This function performs the second task of associating an expression
+    with a specific type, but does not render the ``CAST`` expression
+    in SQL.
+
+    :param expression: A SQL expression, such as a
+     :class:`_expression.ColumnElement`
+     expression or a Python string which will be coerced into a bound
+     literal value.
+
+    :param type\_: A :class:`.TypeEngine` class or instance indicating
+     the type to which the ``CAST`` should apply.
+
+    .. seealso::
+
+        :ref:`coretutorial_casts`
+
+        :func:`.type_coerce` - an alternative to CAST that coerces the type
+        on the Python side only, which is often sufficient to generate the
+        correct SQL and data coercion.
+
+
+    """
+    return Cast(expression, type_)
+
+
+def column(
+    text: str,
+    type_: Optional[Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]] = None,
+    is_literal: bool = False,
+    _selectable: Optional["FromClause"] = None,
+) -> "ColumnClause[_T]":
+    """Produce a :class:`.ColumnClause` object.
+
+    The :class:`.ColumnClause` is a lightweight analogue to the
+    :class:`_schema.Column` class.  The :func:`_expression.column`
+    function can
+    be invoked with just a name alone, as in::
+
+        from sqlalchemy import column
+
+        id, name = column("id"), column("name")
+        stmt = select(id, name).select_from("user")
+
+    The above statement would produce SQL like::
+
+        SELECT id, name FROM user
+
+    Once constructed, :func:`_expression.column`
+    may be used like any other SQL
+    expression element such as within :func:`_expression.select`
+    constructs::
+
+        from sqlalchemy.sql import column
+
+        id, name = column("id"), column("name")
+        stmt = select(id, name).select_from("user")
+
+    The text handled by :func:`_expression.column`
+    is assumed to be handled
+    like the name of a database column; if the string contains mixed case,
+    special characters, or matches a known reserved word on the target
+    backend, the column expression will render using the quoting
+    behavior determined by the backend.  To produce a textual SQL
+    expression that is rendered exactly without any quoting,
+    use :func:`_expression.literal_column` instead,
+    or pass ``True`` as the
+    value of :paramref:`_expression.column.is_literal`.   Additionally,
+    full SQL
+    statements are best handled using the :func:`_expression.text`
+    construct.
+
+    :func:`_expression.column` can be used in a table-like
+    fashion by combining it with the :func:`.table` function
+    (which is the lightweight analogue to :class:`_schema.Table`
+    ) to produce
+    a working table construct with minimal boilerplate::
+
+        from sqlalchemy import table, column, select
+
+        user = table("user",
+                column("id"),
+                column("name"),
+                column("description"),
+        )
+
+        stmt = select(user.c.description).where(user.c.name == 'wendy')
+
+    A :func:`_expression.column` / :func:`.table`
+    construct like that illustrated
+    above can be created in an
+    ad-hoc fashion and is not associated with any
+    :class:`_schema.MetaData`, DDL, or events, unlike its
+    :class:`_schema.Table` counterpart.
+
+    .. versionchanged:: 1.0.0 :func:`_expression.column` can now
+       be imported from the plain ``sqlalchemy`` namespace like any
+       other SQL element.
+
+    :param text: the text of the element.
+
+    :param type: :class:`_types.TypeEngine` object which can associate
+      this :class:`.ColumnClause` with a type.
+
+    :param is_literal: if True, the :class:`.ColumnClause` is assumed to
+      be an exact expression that will be delivered to the output with no
+      quoting rules applied regardless of case sensitive settings. the
+      :func:`_expression.literal_column()` function essentially invokes
+      :func:`_expression.column` while passing ``is_literal=True``.
+
+    .. seealso::
+
+        :class:`_schema.Column`
+
+        :func:`_expression.literal_column`
+
+        :func:`.table`
+
+        :func:`_expression.text`
+
+        :ref:`sqlexpression_literal_column`
+
+    """
+    self = ColumnClause.__new__(ColumnClause)
+    self.__init__(text, type_, is_literal, _selectable)
+    return self
+
+
+def desc(column):
+    """Produce a descending ``ORDER BY`` clause element.
+
+    e.g.::
+
+        from sqlalchemy import desc
+
+        stmt = select(users_table).order_by(desc(users_table.c.name))
+
+    will produce SQL as::
+
+        SELECT id, name FROM user ORDER BY name DESC
+
+    The :func:`.desc` function is a standalone version of the
+    :meth:`_expression.ColumnElement.desc`
+    method available on all SQL expressions,
+    e.g.::
+
+
+        stmt = select(users_table).order_by(users_table.c.name.desc())
+
+    :param column: A :class:`_expression.ColumnElement` (e.g.
+     scalar SQL expression)
+     with which to apply the :func:`.desc` operation.
+
+    .. seealso::
+
+        :func:`.asc`
+
+        :func:`.nulls_first`
+
+        :func:`.nulls_last`
+
+        :meth:`_expression.Select.order_by`
+
+    """
+    return UnaryExpression._create_desc(column)
+
+
+def distinct(expr):
+    """Produce an column-expression-level unary ``DISTINCT`` clause.
+
+    This applies the ``DISTINCT`` keyword to an individual column
+    expression, and is typically contained within an aggregate function,
+    as in::
+
+        from sqlalchemy import distinct, func
+        stmt = select(func.count(distinct(users_table.c.name)))
+
+    The above would produce an expression resembling::
+
+        SELECT COUNT(DISTINCT name) FROM user
+
+    The :func:`.distinct` function is also available as a column-level
+    method, e.g. :meth:`_expression.ColumnElement.distinct`, as in::
+
+        stmt = select(func.count(users_table.c.name.distinct()))
+
+    The :func:`.distinct` operator is different from the
+    :meth:`_expression.Select.distinct` method of
+    :class:`_expression.Select`,
+    which produces a ``SELECT`` statement
+    with ``DISTINCT`` applied to the result set as a whole,
+    e.g. a ``SELECT DISTINCT`` expression.  See that method for further
+    information.
+
+    .. seealso::
+
+        :meth:`_expression.ColumnElement.distinct`
+
+        :meth:`_expression.Select.distinct`
+
+        :data:`.func`
+
+    """
+    return UnaryExpression._create_distinct(expr)
+
+
+def extract(field: str, expr: ColumnElement) -> "Extract[sqltypes.Integer]":
+    """Return a :class:`.Extract` construct.
+
+    This is typically available as :func:`.extract`
+    as well as ``func.extract`` from the
+    :data:`.func` namespace.
+
+    :param field: The field to extract.
+
+    :param expr: A column or Python scalar expression serving as the
+      right side of the ``EXTRACT`` expression.
+
+    E.g.::
+
+        from sqlalchemy import extract
+        from sqlalchemy import table, column
+
+        logged_table = table("user",
+                column("id"),
+                column("date_created"),
+        )
+
+        stmt = select(logged_table.c.id).where(
+            extract("YEAR", logged_table.c.date_created) == 2021
+        )
+
+    In the above example, the statement is used to select ids from the
+    database where the ``YEAR`` component matches a specific value.
+
+    Similarly, one can also select an extracted component::
+
+        stmt = select(
+            extract("YEAR", logged_table.c.date_created)
+        ).where(logged_table.c.id == 1)
+
+    The implementation of ``EXTRACT`` may vary across database backends.
+    Users are reminded to consult their database documentation.
+    """
+    return Extract(field, expr)
+
+
+def false():
+    """Return a :class:`.False_` construct.
+
+    E.g.::
+
+        >>> from sqlalchemy import false
+        >>> print(select(t.c.x).where(false()))
+        SELECT x FROM t WHERE false
+
+    A backend which does not support true/false constants will render as
+    an expression against 1 or 0::
+
+        >>> print(select(t.c.x).where(false()))
+        SELECT x FROM t WHERE 0 = 1
+
+    The :func:`.true` and :func:`.false` constants also feature
+    "short circuit" operation within an :func:`.and_` or :func:`.or_`
+    conjunction::
+
+        >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
+        SELECT x FROM t WHERE true
+
+        >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
+        SELECT x FROM t WHERE false
+
+    .. versionchanged:: 0.9 :func:`.true` and :func:`.false` feature
+       better integrated behavior within conjunctions and on dialects
+       that don't support true/false constants.
+
+    .. seealso::
+
+        :func:`.true`
+
+    """
+
+    return False_._instance()
+
+
+def funcfilter(func, *criterion) -> "FunctionFilter":
+    """Produce a :class:`.FunctionFilter` object against a function.
+
+    Used against aggregate and window functions,
+    for database backends that support the "FILTER" clause.
+
+    E.g.::
+
+        from sqlalchemy import funcfilter
+        funcfilter(func.count(1), MyClass.name == 'some name')
+
+    Would produce "COUNT(1) FILTER (WHERE myclass.name = 'some name')".
+
+    This function is also available from the :data:`~.expression.func`
+    construct itself via the :meth:`.FunctionElement.filter` method.
+
+    .. versionadded:: 1.0.0
+
+    .. seealso::
+
+        :ref:`tutorial_functions_within_group` - in the
+        :ref:`unified_tutorial`
+
+        :meth:`.FunctionElement.filter`
+
+    """
+    return FunctionFilter(func, *criterion)
+
+
+def label(
+    name: str,
+    element: ColumnElement[_T],
+    type_: Optional[Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]] = None,
+) -> "Label[_T]":
+    """Return a :class:`Label` object for the
+    given :class:`_expression.ColumnElement`.
+
+    A label changes the name of an element in the columns clause of a
+    ``SELECT`` statement, typically via the ``AS`` SQL keyword.
+
+    This functionality is more conveniently available via the
+    :meth:`_expression.ColumnElement.label` method on
+    :class:`_expression.ColumnElement`.
+
+    :param name: label name
+
+    :param obj: a :class:`_expression.ColumnElement`.
+
+    """
+    return Label(name, element, type_)
+
+
+def null():
+    """Return a constant :class:`.Null` construct."""
+
+    return Null._instance()
+
+
+def nulls_first(column):
+    """Produce the ``NULLS FIRST`` modifier for an ``ORDER BY`` expression.
+
+    :func:`.nulls_first` is intended to modify the expression produced
+    by :func:`.asc` or :func:`.desc`, and indicates how NULL values
+    should be handled when they are encountered during ordering::
+
+
+        from sqlalchemy import desc, nulls_first
+
+        stmt = select(users_table).order_by(
+            nulls_first(desc(users_table.c.name)))
+
+    The SQL expression from the above would resemble::
+
+        SELECT id, name FROM user ORDER BY name DESC NULLS FIRST
+
+    Like :func:`.asc` and :func:`.desc`, :func:`.nulls_first` is typically
+    invoked from the column expression itself using
+    :meth:`_expression.ColumnElement.nulls_first`,
+    rather than as its standalone
+    function version, as in::
+
+        stmt = select(users_table).order_by(
+            users_table.c.name.desc().nulls_first())
+
+    .. versionchanged:: 1.4 :func:`.nulls_first` is renamed from
+        :func:`.nullsfirst` in previous releases.
+        The previous name remains available for backwards compatibility.
+
+    .. seealso::
+
+        :func:`.asc`
+
+        :func:`.desc`
+
+        :func:`.nulls_last`
+
+        :meth:`_expression.Select.order_by`
+
+    """
+    return UnaryExpression._create_nulls_first(column)
+
+
+def nulls_last(column):
+    """Produce the ``NULLS LAST`` modifier for an ``ORDER BY`` expression.
+
+    :func:`.nulls_last` is intended to modify the expression produced
+    by :func:`.asc` or :func:`.desc`, and indicates how NULL values
+    should be handled when they are encountered during ordering::
+
+
+        from sqlalchemy import desc, nulls_last
+
+        stmt = select(users_table).order_by(
+            nulls_last(desc(users_table.c.name)))
+
+    The SQL expression from the above would resemble::
+
+        SELECT id, name FROM user ORDER BY name DESC NULLS LAST
+
+    Like :func:`.asc` and :func:`.desc`, :func:`.nulls_last` is typically
+    invoked from the column expression itself using
+    :meth:`_expression.ColumnElement.nulls_last`,
+    rather than as its standalone
+    function version, as in::
+
+        stmt = select(users_table).order_by(
+            users_table.c.name.desc().nulls_last())
+
+    .. versionchanged:: 1.4 :func:`.nulls_last` is renamed from
+        :func:`.nullslast` in previous releases.
+        The previous name remains available for backwards compatibility.
+
+    .. seealso::
+
+        :func:`.asc`
+
+        :func:`.desc`
+
+        :func:`.nulls_first`
+
+        :meth:`_expression.Select.order_by`
+
+    """
+    return UnaryExpression._create_nulls_last(column)
+
+
+def or_(*clauses):
+    """Produce a conjunction of expressions joined by ``OR``.
+
+    E.g.::
+
+        from sqlalchemy import or_
+
+        stmt = select(users_table).where(
+                        or_(
+                            users_table.c.name == 'wendy',
+                            users_table.c.name == 'jack'
+                        )
+                    )
+
+    The :func:`.or_` conjunction is also available using the
+    Python ``|`` operator (though note that compound expressions
+    need to be parenthesized in order to function with Python
+    operator precedence behavior)::
+
+        stmt = select(users_table).where(
+                        (users_table.c.name == 'wendy') |
+                        (users_table.c.name == 'jack')
+                    )
+
+    The :func:`.or_` construct must be given at least one positional
+    argument in order to be valid; a :func:`.or_` construct with no
+    arguments is ambiguous.   To produce an "empty" or dynamically
+    generated :func:`.or_`  expression, from a given list of expressions,
+    a "default" element of ``False`` should be specified::
+
+        or_criteria = or_(False, *expressions)
+
+    The above expression will compile to SQL as the expression ``false``
+    or ``0 = 1``, depending on backend, if no other expressions are
+    present.  If expressions are present, then the ``False`` value is
+    ignored as it does not affect the outcome of an OR expression which
+    has other elements.
+
+    .. deprecated:: 1.4  The :func:`.or_` element now requires that at
+       least one argument is passed; creating the :func:`.or_` construct
+       with no arguments is deprecated, and will emit a deprecation warning
+       while continuing to produce a blank SQL string.
+
+    .. seealso::
+
+        :func:`.and_`
+
+    """
+    return BooleanClauseList.or_(*clauses)
+
+
+def over(
+    element: "FunctionElement[_T]",
+    partition_by=None,
+    order_by=None,
+    range_=None,
+    rows=None,
+) -> "Over[_T]":
+    r"""Produce an :class:`.Over` object against a function.
+
+    Used against aggregate or so-called "window" functions,
+    for database backends that support window functions.
+
+    :func:`_expression.over` is usually called using
+    the :meth:`.FunctionElement.over` method, e.g.::
+
+        func.row_number().over(order_by=mytable.c.some_column)
+
+    Would produce::
+
+        ROW_NUMBER() OVER(ORDER BY some_column)
+
+    Ranges are also possible using the :paramref:`.expression.over.range_`
+    and :paramref:`.expression.over.rows` parameters.  These
+    mutually-exclusive parameters each accept a 2-tuple, which contains
+    a combination of integers and None::
+
+        func.row_number().over(
+            order_by=my_table.c.some_column, range_=(None, 0))
+
+    The above would produce::
+
+        ROW_NUMBER() OVER(ORDER BY some_column
+        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
+
+    A value of ``None`` indicates "unbounded", a
+    value of zero indicates "current row", and negative / positive
+    integers indicate "preceding" and "following":
+
+    * RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING::
+
+        func.row_number().over(order_by='x', range_=(-5, 10))
+
+    * ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW::
+
+        func.row_number().over(order_by='x', rows=(None, 0))
+
+    * RANGE BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING::
+
+        func.row_number().over(order_by='x', range_=(-2, None))
+
+    * RANGE BETWEEN 1 FOLLOWING AND 3 FOLLOWING::
+
+        func.row_number().over(order_by='x', range_=(1, 3))
+
+    .. versionadded:: 1.1 support for RANGE / ROWS within a window
+
+
+    :param element: a :class:`.FunctionElement`, :class:`.WithinGroup`,
+     or other compatible construct.
+    :param partition_by: a column element or string, or a list
+     of such, that will be used as the PARTITION BY clause
+     of the OVER construct.
+    :param order_by: a column element or string, or a list
+     of such, that will be used as the ORDER BY clause
+     of the OVER construct.
+    :param range\_: optional range clause for the window.  This is a
+     tuple value which can contain integer values or ``None``,
+     and will render a RANGE BETWEEN PRECEDING / FOLLOWING clause.
+
+     .. versionadded:: 1.1
+
+    :param rows: optional rows clause for the window.  This is a tuple
+     value which can contain integer values or None, and will render
+     a ROWS BETWEEN PRECEDING / FOLLOWING clause.
+
+     .. versionadded:: 1.1
+
+    This function is also available from the :data:`~.expression.func`
+    construct itself via the :meth:`.FunctionElement.over` method.
+
+    .. seealso::
+
+        :ref:`tutorial_window_functions` - in the :ref:`unified_tutorial`
+
+        :data:`.expression.func`
+
+        :func:`_expression.within_group`
+
+    """
+    return Over(element, partition_by, order_by, range_, rows)
+
+
+@_document_text_coercion("text", ":func:`.text`", ":paramref:`.text.text`")
+def text(text):
+    r"""Construct a new :class:`_expression.TextClause` clause,
+    representing
+    a textual SQL string directly.
+
+    E.g.::
+
+        from sqlalchemy import text
+
+        t = text("SELECT * FROM users")
+        result = connection.execute(t)
+
+    The advantages :func:`_expression.text`
+    provides over a plain string are
+    backend-neutral support for bind parameters, per-statement
+    execution options, as well as
+    bind parameter and result-column typing behavior, allowing
+    SQLAlchemy type constructs to play a role when executing
+    a statement that is specified literally.  The construct can also
+    be provided with a ``.c`` collection of column elements, allowing
+    it to be embedded in other SQL expression constructs as a subquery.
+
+    Bind parameters are specified by name, using the format ``:name``.
+    E.g.::
+
+        t = text("SELECT * FROM users WHERE id=:user_id")
+        result = connection.execute(t, user_id=12)
+
+    For SQL statements where a colon is required verbatim, as within
+    an inline string, use a backslash to escape::
+
+        t = text("SELECT * FROM users WHERE name='\:username'")
+
+    The :class:`_expression.TextClause`
+    construct includes methods which can
+    provide information about the bound parameters as well as the column
+    values which would be returned from the textual statement, assuming
+    it's an executable SELECT type of statement.  The
+    :meth:`_expression.TextClause.bindparams`
+    method is used to provide bound
+    parameter detail, and :meth:`_expression.TextClause.columns`
+    method allows
+    specification of return columns including names and types::
+
+        t = text("SELECT * FROM users WHERE id=:user_id").\
+                bindparams(user_id=7).\
+                columns(id=Integer, name=String)
+
+        for id, name in connection.execute(t):
+            print(id, name)
+
+    The :func:`_expression.text` construct is used in cases when
+    a literal string SQL fragment is specified as part of a larger query,
+    such as for the WHERE clause of a SELECT statement::
+
+        s = select(users.c.id, users.c.name).where(text("id=:user_id"))
+        result = connection.execute(s, user_id=12)
+
+    :func:`_expression.text` is also used for the construction
+    of a full, standalone statement using plain text.
+    As such, SQLAlchemy refers
+    to it as an :class:`.Executable` object and may be used
+    like any other statement passed to an ``.execute()`` method.
+
+    :param text:
+      the text of the SQL statement to be created.  Use ``:<param>``
+      to specify bind parameters; they will be compiled to their
+      engine-specific format.
+
+    .. seealso::
+
+        :ref:`sqlexpression_text` - in the Core tutorial
+
+
+    """
+    return TextClause(text)
+
+
+def true():
+    """Return a constant :class:`.True_` construct.
+
+    E.g.::
+
+        >>> from sqlalchemy import true
+        >>> print(select(t.c.x).where(true()))
+        SELECT x FROM t WHERE true
+
+    A backend which does not support true/false constants will render as
+    an expression against 1 or 0::
+
+        >>> print(select(t.c.x).where(true()))
+        SELECT x FROM t WHERE 1 = 1
+
+    The :func:`.true` and :func:`.false` constants also feature
+    "short circuit" operation within an :func:`.and_` or :func:`.or_`
+    conjunction::
+
+        >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
+        SELECT x FROM t WHERE true
+
+        >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
+        SELECT x FROM t WHERE false
+
+    .. versionchanged:: 0.9 :func:`.true` and :func:`.false` feature
+       better integrated behavior within conjunctions and on dialects
+       that don't support true/false constants.
+
+    .. seealso::
+
+        :func:`.false`
+
+    """
+
+    return True_._instance()
+
+
+def tuple_(*clauses: roles.ExpressionElementRole, types=None) -> "Tuple":
+    """Return a :class:`.Tuple`.
+
+    Main usage is to produce a composite IN construct using
+    :meth:`.ColumnOperators.in_` ::
+
+        from sqlalchemy import tuple_
+
+        tuple_(table.c.col1, table.c.col2).in_(
+            [(1, 2), (5, 12), (10, 19)]
+        )
+
+    .. versionchanged:: 1.3.6 Added support for SQLite IN tuples.
+
+    .. warning::
+
+        The composite IN construct is not supported by all backends, and is
+        currently known to work on PostgreSQL, MySQL, and SQLite.
+        Unsupported backends will raise a subclass of
+        :class:`~sqlalchemy.exc.DBAPIError` when such an expression is
+        invoked.
+
+    """
+    return Tuple(*clauses, types=types)
+
+
+def type_coerce(
+    expression: "ColumnElement",
+    type_: Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"],
+) -> "TypeCoerce[_T]":
+    r"""Associate a SQL expression with a particular type, without rendering
+    ``CAST``.
+
+    E.g.::
+
+        from sqlalchemy import type_coerce
+
+        stmt = select(type_coerce(log_table.date_string, StringDateTime()))
+
+    The above construct will produce a :class:`.TypeCoerce` object, which
+    does not modify the rendering in any way on the SQL side, with the
+    possible exception of a generated label if used in a columns clause
+    context::
+
+        SELECT date_string AS date_string FROM log
+
+    When result rows are fetched, the ``StringDateTime`` type processor
+    will be applied to result rows on behalf of the ``date_string`` column.
+
+    .. note:: the :func:`.type_coerce` construct does not render any
+       SQL syntax of its own, including that it does not imply
+       parenthesization.   Please use :meth:`.TypeCoerce.self_group`
+       if explicit parenthesization is required.
+
+    In order to provide a named label for the expression, use
+    :meth:`_expression.ColumnElement.label`::
+
+        stmt = select(
+            type_coerce(log_table.date_string, StringDateTime()).label('date')
+        )
+
+
+    A type that features bound-value handling will also have that behavior
+    take effect when literal values or :func:`.bindparam` constructs are
+    passed to :func:`.type_coerce` as targets.
+    For example, if a type implements the
+    :meth:`.TypeEngine.bind_expression`
+    method or :meth:`.TypeEngine.bind_processor` method or equivalent,
+    these functions will take effect at statement compilation/execution
+    time when a literal value is passed, as in::
+
+        # bound-value handling of MyStringType will be applied to the
+        # literal value "some string"
+        stmt = select(type_coerce("some string", MyStringType))
+
+    When using :func:`.type_coerce` with composed expressions, note that
+    **parenthesis are not applied**.   If :func:`.type_coerce` is being
+    used in an operator context where the parenthesis normally present from
+    CAST are necessary, use the :meth:`.TypeCoerce.self_group` method::
+
+        >>> some_integer = column("someint", Integer)
+        >>> some_string = column("somestr", String)
+        >>> expr = type_coerce(some_integer + 5, String) + some_string
+        >>> print(expr)
+        someint + :someint_1 || somestr
+        >>> expr = type_coerce(some_integer + 5, String).self_group() + some_string
+        >>> print(expr)
+        (someint + :someint_1) || somestr
+
+    :param expression: A SQL expression, such as a
+     :class:`_expression.ColumnElement`
+     expression or a Python string which will be coerced into a bound
+     literal value.
+
+    :param type\_: A :class:`.TypeEngine` class or instance indicating
+     the type to which the expression is coerced.
+
+    .. seealso::
+
+        :ref:`coretutorial_casts`
+
+        :func:`.cast`
+
+    """  # noqa
+    return TypeCoerce(expression, type_)
+
+
+def within_group(
+    element: "FunctionElement[_T]", *order_by: roles.OrderByRole
+) -> "WithinGroup[_T]":
+    r"""Produce a :class:`.WithinGroup` object against a function.
+
+    Used against so-called "ordered set aggregate" and "hypothetical
+    set aggregate" functions, including :class:`.percentile_cont`,
+    :class:`.rank`, :class:`.dense_rank`, etc.
+
+    :func:`_expression.within_group` is usually called using
+    the :meth:`.FunctionElement.within_group` method, e.g.::
+
+        from sqlalchemy import within_group
+        stmt = select(
+            department.c.id,
+            func.percentile_cont(0.5).within_group(
+                department.c.salary.desc()
+            )
+        )
+
+    The above statement would produce SQL similar to
+    ``SELECT department.id, percentile_cont(0.5)
+    WITHIN GROUP (ORDER BY department.salary DESC)``.
+
+    :param element: a :class:`.FunctionElement` construct, typically
+     generated by :data:`~.expression.func`.
+    :param \*order_by: one or more column elements that will be used
+     as the ORDER BY clause of the WITHIN GROUP construct.
+
+    .. versionadded:: 1.1
+
+    .. seealso::
+
+        :ref:`tutorial_functions_within_group` - in the
+        :ref:`unified_tutorial`
+
+        :data:`.expression.func`
+
+        :func:`_expression.over`
+
+    """
+    return WithinGroup(element, *order_by)
diff --git a/lib/sqlalchemy/sql/_selectable_constructors.py b/lib/sqlalchemy/sql/_selectable_constructors.py
new file mode 100644 (file)
index 0000000..4b67c12
--- /dev/null
@@ -0,0 +1,467 @@
+# sql/_selectable_constructors.py
+# Copyright (C) 2005-2022 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 typing import Any
+from typing import Type
+from typing import Union
+
+from . import coercions
+from . import roles
+from .elements import ColumnClause
+from .selectable import Alias
+from .selectable import CompoundSelect
+from .selectable import Exists
+from .selectable import Join
+from .selectable import Lateral
+from .selectable import Select
+from .selectable import TableClause
+from .selectable import TableSample
+from .selectable import Values
+
+
+def alias(selectable, name=None, flat=False):
+    """Return an :class:`_expression.Alias` object.
+
+    An :class:`_expression.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``.
+
+    Similar functionality is available via the
+    :meth:`_expression.FromClause.alias`
+    method available on all :class:`_expression.FromClause` subclasses.
+    In terms of
+    a SELECT object as generated from the :func:`_expression.select`
+    function, the :meth:`_expression.SelectBase.alias` method returns an
+    :class:`_expression.Alias` or similar object which represents a named,
+    parenthesized subquery.
+
+    When an :class:`_expression.Alias` is created from a
+    :class:`_schema.Table` object,
+    this has the effect of the table being rendered
+    as ``tablename AS aliasname`` in a SELECT statement.
+
+    For :func:`_expression.select` objects, the effect is that of
+    creating a named subquery, i.e. ``(select ...) AS aliasname``.
+
+    The ``name`` parameter is optional, and provides the name
+    to use in the rendered SQL.  If blank, an "anonymous" 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 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.
+
+    :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, name=None, recursive=False):
+    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
+    )
+
+
+def except_(*selects):
+    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)
+
+
+def except_all(*selects):
+    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=None):
+    """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::
+
+        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)
+
+
+def intersect(*selects):
+    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)
+
+
+def intersect_all(*selects):
+    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, right, onclause=None, isouter=False, full=False):
+    """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::
+
+        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.
+
+     .. versionadded:: 1.1
+
+    .. seealso::
+
+        :meth:`_expression.FromClause.join` - method form,
+        based on a given left side.
+
+        :class:`_expression.Join` - the type of object produced.
+
+    """
+
+    return Join(left, right, onclause, isouter, full)
+
+
+def lateral(selectable, name=None):
+    """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.
+
+    .. versionadded:: 1.1
+
+    .. seealso::
+
+        :ref:`lateral_selects` -  overview of usage.
+
+    """
+    return Lateral._factory(selectable, name=name)
+
+
+def outerjoin(left, right, onclause=None, full=False):
+    """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)
+
+
+def select(*entities: Union[roles.ColumnsClauseRole, Type]) -> "Select":
+    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:`_future.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:`coretutorial_selecting` - Core Tutorial description of
+        :func:`_expression.select`.
+
+    :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.
+
+    """
+
+    return Select(*entities)
+
+
+def table(name: str, *columns: ColumnClause, **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.
+
+    .. versionchanged:: 1.0.0 :func:`_expression.table` can now
+       be imported from the plain ``sqlalchemy`` namespace like any
+       other SQL element.
+
+
+    :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, sampling, name=None, seed=None):
+    """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::
+
+        SELECT alias.people_id FROM
+        people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
+        REPEATABLE (random())
+
+    .. versionadded:: 1.1
+
+    :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)
+
+
+def union(*selects, **kwargs):
+    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, **kwargs)
+
+
+def union_all(*selects):
+    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, name=None, literal_binds=False) -> "Values":
+    r"""Construct a :class:`_expression.Values` construct.
+
+    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
+
+        value_expr = values(
+            column('id', Integer),
+            column('name', String),
+            name="my_values"
+        ).data(
+            [(1, 'name1'), (2, 'name2'), (3, 'name3')]
+        )
+
+    :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.
+
+    """
+    return Values(*columns, literal_binds=literal_binds, name=name)
index fe2b498c8e1fd24b0a385e49092ab2ef17afaaf4..3bec73f7dc4fbf29af3465a5382dcc46382a62e5 100644 (file)
@@ -8,6 +8,14 @@
 import collections.abc as collections_abc
 import numbers
 import re
+import typing
+from typing import Any
+from typing import Callable
+from typing import Optional
+from typing import overload
+from typing import Type
+from typing import TypeVar
+from typing import Union
 
 from . import operators
 from . import roles
@@ -20,13 +28,24 @@ from .. import exc
 from .. import inspection
 from .. import util
 
+if not typing.TYPE_CHECKING:
+    elements = None
+    lambdas = None
+    schema = None
+    selectable = None
+    traversals = None
 
-elements = None
-lambdas = None
-schema = None
-selectable = None
-sqltypes = None
-traversals = None
+if typing.TYPE_CHECKING:
+    from . import elements
+    from . import lambdas
+    from . import schema
+    from . import selectable
+    from . import traversals
+    from .elements import ClauseElement
+    from .elements import ColumnElement
+
+_SR = TypeVar("_SR", bound=roles.SQLRole)
+_StringOnlyR = TypeVar("_StringOnlyR", bound=roles.StringRole)
 
 
 def _is_literal(element):
@@ -110,14 +129,93 @@ def _expression_collection_was_a_list(attrname, fnname, args):
     return args
 
 
+@overload
 def expect(
-    role,
-    element,
-    apply_propagate_attrs=None,
-    argname=None,
-    post_inspect=False,
-    **kw,
-):
+    role: Type[roles.InElementRole],
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> Union["elements.ColumnElement", "selectable.Select"]:
+    ...
+
+
+@overload
+def expect(
+    role: Type[roles.HasCTERole],
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> "selectable.HasCTE":
+    ...
+
+
+@overload
+def expect(
+    role: Type[roles.ExpressionElementRole],
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> "ColumnElement":
+    ...
+
+
+@overload
+def expect(
+    role: "Type[_StringOnlyR]",
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> str:
+    ...
+
+
+@overload
+def expect(
+    role: Type[_SR],
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> _SR:
+    ...
+
+
+@overload
+def expect(
+    role: Type[_SR],
+    element: Callable[..., Any],
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> "lambdas.LambdaElement":
+    ...
+
+
+def expect(
+    role: Type[_SR],
+    element: Any,
+    *,
+    apply_propagate_attrs: Optional["ClauseElement"] = None,
+    argname: Optional[str] = None,
+    post_inspect: bool = False,
+    **kw: Any,
+) -> Union[str, _SR, "lambdas.LambdaElement"]:
     if (
         role.allows_lambda
         # note callable() will not invoke a __getattr__() method, whereas
index 55a586285d1d45f5b30eca90f3a05e92b315ad37..1759e686ef72e8d2d60a3c96960daa0513bf10fd 100644 (file)
@@ -8,6 +8,15 @@
 """Default implementation of SQL comparison operations.
 """
 
+import typing
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import NoReturn
+from typing import Optional
+from typing import Tuple
+from typing import Type
+from typing import Union
 
 from . import coercions
 from . import operators
@@ -16,28 +25,38 @@ from . import type_api
 from .elements import and_
 from .elements import BinaryExpression
 from .elements import ClauseList
-from .elements import collate
+from .elements import CollationClause
 from .elements import CollectionAggregate
 from .elements import False_
 from .elements import Null
 from .elements import or_
 from .elements import True_
 from .elements import UnaryExpression
+from .operators import OperatorType
 from .. import exc
 from .. import util
 
+_T = typing.TypeVar("_T", bound=Any)
+
+if typing.TYPE_CHECKING:
+    from .elements import ColumnElement
+    from .sqltypes import TypeEngine
+
 
 def _boolean_compare(
-    expr,
-    op,
-    obj,
-    negate=None,
-    reverse=False,
+    expr: "ColumnElement",
+    op: OperatorType,
+    obj: roles.BinaryElementRole,
+    *,
+    negate_op: Optional[OperatorType] = None,
+    reverse: bool = False,
     _python_is_types=(util.NoneType, bool),
     _any_all_expr=False,
-    result_type=None,
-    **kwargs,
-):
+    result_type: Optional[
+        Union[Type["TypeEngine[bool]"], "TypeEngine[bool]"]
+    ] = None,
+    **kwargs: Any,
+) -> BinaryExpression[bool]:
 
     if result_type is None:
         result_type = type_api.BOOLEANTYPE
@@ -54,7 +73,7 @@ def _boolean_compare(
                 coercions.expect(roles.ConstExprRole, obj),
                 op,
                 type_=result_type,
-                negate=negate,
+                negate=negate_op,
                 modifiers=kwargs,
             )
         elif op in (
@@ -66,7 +85,7 @@ def _boolean_compare(
                 coercions.expect(roles.ConstExprRole, obj),
                 op,
                 type_=result_type,
-                negate=negate,
+                negate=negate_op,
                 modifiers=kwargs,
             )
         elif _any_all_expr:
@@ -104,11 +123,21 @@ def _boolean_compare(
 
     if reverse:
         return BinaryExpression(
-            obj, expr, op, type_=result_type, negate=negate, modifiers=kwargs
+            obj,
+            expr,
+            op,
+            type_=result_type,
+            negate=negate_op,
+            modifiers=kwargs,
         )
     else:
         return BinaryExpression(
-            expr, obj, op, type_=result_type, negate=negate, modifiers=kwargs
+            expr,
+            obj,
+            op,
+            type_=result_type,
+            negate=negate_op,
+            modifiers=kwargs,
         )
 
 
@@ -124,15 +153,26 @@ def _custom_op_operate(expr, op, obj, reverse=False, result_type=None, **kw):
     )
 
 
-def _binary_operate(expr, op, obj, reverse=False, result_type=None, **kw):
-    obj = coercions.expect(
+def _binary_operate(
+    expr: "ColumnElement",
+    op: OperatorType,
+    obj: roles.BinaryElementRole,
+    *,
+    reverse=False,
+    result_type: Optional[
+        Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
+    ] = None,
+    **kw: Any,
+) -> BinaryExpression[_T]:
+
+    coerced_obj = coercions.expect(
         roles.BinaryElementRole, obj, expr=expr, operator=op
     )
 
     if reverse:
-        left, right = obj, expr
+        left, right = coerced_obj, expr
     else:
-        left, right = expr, obj
+        left, right = expr, coerced_obj
 
     if result_type is None:
         op, result_type = left.comparator._adapt_expression(
@@ -142,7 +182,7 @@ def _binary_operate(expr, op, obj, reverse=False, result_type=None, **kw):
     return BinaryExpression(left, right, op, type_=result_type, modifiers=kw)
 
 
-def _conjunction_operate(expr, op, other, **kw):
+def _conjunction_operate(expr, op, other, **kw) -> "ColumnElement":
     if op is operators.and_:
         return and_(expr, other)
     elif op is operators.or_:
@@ -151,11 +191,11 @@ def _conjunction_operate(expr, op, other, **kw):
         raise NotImplementedError()
 
 
-def _scalar(expr, op, fn, **kw):
+def _scalar(expr, op, fn, **kw) -> "ColumnElement":
     return fn(expr)
 
 
-def _in_impl(expr, op, seq_or_selectable, negate_op, **kw):
+def _in_impl(expr, op, seq_or_selectable, negate_op, **kw) -> "ColumnElement":
     seq_or_selectable = coercions.expect(
         roles.InElementRole, seq_or_selectable, expr=expr, operator=op
     )
@@ -163,11 +203,11 @@ def _in_impl(expr, op, seq_or_selectable, negate_op, **kw):
         op, negate_op = seq_or_selectable._annotations["in_ops"]
 
     return _boolean_compare(
-        expr, op, seq_or_selectable, negate=negate_op, **kw
+        expr, op, seq_or_selectable, negate_op=negate_op, **kw
     )
 
 
-def _getitem_impl(expr, op, other, **kw):
+def _getitem_impl(expr, op, other, **kw) -> "ColumnElement":
     if isinstance(expr.type, type_api.INDEXABLE):
         other = coercions.expect(
             roles.BinaryElementRole, other, expr=expr, operator=op
@@ -177,13 +217,13 @@ def _getitem_impl(expr, op, other, **kw):
         _unsupported_impl(expr, op, other, **kw)
 
 
-def _unsupported_impl(expr, op, *arg, **kw):
+def _unsupported_impl(expr, op, *arg, **kw) -> NoReturn:
     raise NotImplementedError(
         "Operator '%s' is not supported on " "this expression" % op.__name__
     )
 
 
-def _inv_impl(expr, op, **kw):
+def _inv_impl(expr, op, **kw) -> "ColumnElement":
     """See :meth:`.ColumnOperators.__inv__`."""
 
     # undocumented element currently used by the ORM for
@@ -194,12 +234,12 @@ def _inv_impl(expr, op, **kw):
         return expr._negate()
 
 
-def _neg_impl(expr, op, **kw):
+def _neg_impl(expr, op, **kw) -> "ColumnElement":
     """See :meth:`.ColumnOperators.__neg__`."""
     return UnaryExpression(expr, operator=operators.neg, type_=expr.type)
 
 
-def _match_impl(expr, op, other, **kw):
+def _match_impl(expr, op, other, **kw) -> "ColumnElement":
     """See :meth:`.ColumnOperators.match`."""
 
     return _boolean_compare(
@@ -212,21 +252,21 @@ def _match_impl(expr, op, other, **kw):
             operator=operators.match_op,
         ),
         result_type=type_api.MATCHTYPE,
-        negate=operators.not_match_op
+        negate_op=operators.not_match_op
         if op is operators.match_op
         else operators.match_op,
         **kw,
     )
 
 
-def _distinct_impl(expr, op, **kw):
+def _distinct_impl(expr, op, **kw) -> "ColumnElement":
     """See :meth:`.ColumnOperators.distinct`."""
     return UnaryExpression(
         expr, operator=operators.distinct_op, type_=expr.type
     )
 
 
-def _between_impl(expr, op, cleft, cright, **kw):
+def _between_impl(expr, op, cleft, cright, **kw) -> "ColumnElement":
     """See :meth:`.ColumnOperators.between`."""
     return BinaryExpression(
         expr,
@@ -255,11 +295,11 @@ def _between_impl(expr, op, cleft, cright, **kw):
     )
 
 
-def _collate_impl(expr, op, other, **kw):
-    return collate(expr, other)
+def _collate_impl(expr, op, collation, **kw) -> "ColumnElement":
+    return CollationClause._create_collation_expression(expr, collation)
 
 
-def _regexp_match_impl(expr, op, pattern, flags, **kw):
+def _regexp_match_impl(expr, op, pattern, flags, **kw) -> "ColumnElement":
     if flags is not None:
         flags = coercions.expect(
             roles.BinaryElementRole,
@@ -272,14 +312,16 @@ def _regexp_match_impl(expr, op, pattern, flags, **kw):
         op,
         pattern,
         flags=flags,
-        negate=operators.not_regexp_match_op
+        negate_op=operators.not_regexp_match_op
         if op is operators.regexp_match_op
         else operators.regexp_match_op,
         **kw,
     )
 
 
-def _regexp_replace_impl(expr, op, pattern, replacement, flags, **kw):
+def _regexp_replace_impl(
+    expr, op, pattern, replacement, flags, **kw
+) -> "ColumnElement":
     replacement = coercions.expect(
         roles.BinaryElementRole,
         replacement,
@@ -299,59 +341,118 @@ def _regexp_replace_impl(expr, op, pattern, replacement, flags, **kw):
 
 
 # a mapping of operators with the method they use, along with
-# their negated operator for comparison operators
-operator_lookup = {
-    "and_": (_conjunction_operate,),
-    "or_": (_conjunction_operate,),
-    "inv": (_inv_impl,),
-    "add": (_binary_operate,),
-    "mul": (_binary_operate,),
-    "sub": (_binary_operate,),
-    "div": (_binary_operate,),
-    "mod": (_binary_operate,),
-    "truediv": (_binary_operate,),
-    "floordiv": (_binary_operate,),
-    "custom_op": (_custom_op_operate,),
-    "json_path_getitem_op": (_binary_operate,),
-    "json_getitem_op": (_binary_operate,),
-    "concat_op": (_binary_operate,),
-    "any_op": (_scalar, CollectionAggregate._create_any),
-    "all_op": (_scalar, CollectionAggregate._create_all),
-    "lt": (_boolean_compare, operators.ge),
-    "le": (_boolean_compare, operators.gt),
-    "ne": (_boolean_compare, operators.eq),
-    "gt": (_boolean_compare, operators.le),
-    "ge": (_boolean_compare, operators.lt),
-    "eq": (_boolean_compare, operators.ne),
-    "is_distinct_from": (_boolean_compare, operators.is_not_distinct_from),
-    "is_not_distinct_from": (_boolean_compare, operators.is_distinct_from),
-    "like_op": (_boolean_compare, operators.not_like_op),
-    "ilike_op": (_boolean_compare, operators.not_ilike_op),
-    "not_like_op": (_boolean_compare, operators.like_op),
-    "not_ilike_op": (_boolean_compare, operators.ilike_op),
-    "contains_op": (_boolean_compare, operators.not_contains_op),
-    "startswith_op": (_boolean_compare, operators.not_startswith_op),
-    "endswith_op": (_boolean_compare, operators.not_endswith_op),
-    "desc_op": (_scalar, UnaryExpression._create_desc),
-    "asc_op": (_scalar, UnaryExpression._create_asc),
-    "nulls_first_op": (_scalar, UnaryExpression._create_nulls_first),
-    "nulls_last_op": (_scalar, UnaryExpression._create_nulls_last),
-    "in_op": (_in_impl, operators.not_in_op),
-    "not_in_op": (_in_impl, operators.in_op),
-    "is_": (_boolean_compare, operators.is_),
-    "is_not": (_boolean_compare, operators.is_not),
-    "collate": (_collate_impl,),
-    "match_op": (_match_impl,),
-    "not_match_op": (_match_impl,),
-    "distinct_op": (_distinct_impl,),
-    "between_op": (_between_impl,),
-    "not_between_op": (_between_impl,),
-    "neg": (_neg_impl,),
-    "getitem": (_getitem_impl,),
-    "lshift": (_unsupported_impl,),
-    "rshift": (_unsupported_impl,),
-    "contains": (_unsupported_impl,),
-    "regexp_match_op": (_regexp_match_impl,),
-    "not_regexp_match_op": (_regexp_match_impl,),
-    "regexp_replace_op": (_regexp_replace_impl,),
+# additional keyword arguments to be passed
+operator_lookup: Dict[
+    str, Tuple[Callable[..., "ColumnElement"], util.immutabledict]
+] = {
+    "and_": (_conjunction_operate, util.EMPTY_DICT),
+    "or_": (_conjunction_operate, util.EMPTY_DICT),
+    "inv": (_inv_impl, util.EMPTY_DICT),
+    "add": (_binary_operate, util.EMPTY_DICT),
+    "mul": (_binary_operate, util.EMPTY_DICT),
+    "sub": (_binary_operate, util.EMPTY_DICT),
+    "div": (_binary_operate, util.EMPTY_DICT),
+    "mod": (_binary_operate, util.EMPTY_DICT),
+    "truediv": (_binary_operate, util.EMPTY_DICT),
+    "floordiv": (_binary_operate, util.EMPTY_DICT),
+    "custom_op": (_custom_op_operate, util.EMPTY_DICT),
+    "json_path_getitem_op": (_binary_operate, util.EMPTY_DICT),
+    "json_getitem_op": (_binary_operate, util.EMPTY_DICT),
+    "concat_op": (_binary_operate, util.EMPTY_DICT),
+    "any_op": (
+        _scalar,
+        util.immutabledict({"fn": CollectionAggregate._create_any}),
+    ),
+    "all_op": (
+        _scalar,
+        util.immutabledict({"fn": CollectionAggregate._create_all}),
+    ),
+    "lt": (_boolean_compare, util.immutabledict({"negate_op": operators.ge})),
+    "le": (_boolean_compare, util.immutabledict({"negate_op": operators.gt})),
+    "ne": (_boolean_compare, util.immutabledict({"negate_op": operators.eq})),
+    "gt": (_boolean_compare, util.immutabledict({"negate_op": operators.le})),
+    "ge": (_boolean_compare, util.immutabledict({"negate_op": operators.lt})),
+    "eq": (_boolean_compare, util.immutabledict({"negate_op": operators.ne})),
+    "is_distinct_from": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.is_not_distinct_from}),
+    ),
+    "is_not_distinct_from": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.is_distinct_from}),
+    ),
+    "like_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.not_like_op}),
+    ),
+    "ilike_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.not_ilike_op}),
+    ),
+    "not_like_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.like_op}),
+    ),
+    "not_ilike_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.ilike_op}),
+    ),
+    "contains_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.not_contains_op}),
+    ),
+    "startswith_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.not_startswith_op}),
+    ),
+    "endswith_op": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.not_endswith_op}),
+    ),
+    "desc_op": (
+        _scalar,
+        util.immutabledict({"fn": UnaryExpression._create_desc}),
+    ),
+    "asc_op": (
+        _scalar,
+        util.immutabledict({"fn": UnaryExpression._create_asc}),
+    ),
+    "nulls_first_op": (
+        _scalar,
+        util.immutabledict({"fn": UnaryExpression._create_nulls_first}),
+    ),
+    "nulls_last_op": (
+        _scalar,
+        util.immutabledict({"fn": UnaryExpression._create_nulls_last}),
+    ),
+    "in_op": (
+        _in_impl,
+        util.immutabledict({"negate_op": operators.not_in_op}),
+    ),
+    "not_in_op": (
+        _in_impl,
+        util.immutabledict({"negate_op": operators.in_op}),
+    ),
+    "is_": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.is_}),
+    ),
+    "is_not": (
+        _boolean_compare,
+        util.immutabledict({"negate_op": operators.is_not}),
+    ),
+    "collate": (_collate_impl, util.EMPTY_DICT),
+    "match_op": (_match_impl, util.EMPTY_DICT),
+    "not_match_op": (_match_impl, util.EMPTY_DICT),
+    "distinct_op": (_distinct_impl, util.EMPTY_DICT),
+    "between_op": (_between_impl, util.EMPTY_DICT),
+    "not_between_op": (_between_impl, util.EMPTY_DICT),
+    "neg": (_neg_impl, util.EMPTY_DICT),
+    "getitem": (_getitem_impl, util.EMPTY_DICT),
+    "lshift": (_unsupported_impl, util.EMPTY_DICT),
+    "rshift": (_unsupported_impl, util.EMPTY_DICT),
+    "contains": (_unsupported_impl, util.EMPTY_DICT),
+    "regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
+    "not_regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
+    "regexp_replace_op": (_regexp_replace_impl, util.EMPTY_DICT),
 }
index 5f2424466eda667c8cb847ddef571a8652530898..33dca66cd5109328ec38ddd97f3695ba1976cd43 100644 (file)
@@ -763,76 +763,7 @@ class Insert(ValuesBase):
         + HasCTE._has_ctes_traverse_internals
     )
 
-    def __init__(
-        self,
-        table,
-    ):
-        """Construct an :class:`_expression.Insert` object.
-
-        E.g.::
-
-            from sqlalchemy import insert
-
-            stmt = (
-                insert(user_table).
-                values(name='username', fullname='Full Username')
-            )
-
-        Similar functionality is available via the
-        :meth:`_expression.TableClause.insert` method on
-        :class:`_schema.Table`.
-
-        .. seealso::
-
-            :ref:`coretutorial_insert_expressions` - in the
-            :ref:`1.x tutorial <sqlexpression_toplevel>`
-
-            :ref:`tutorial_core_insert` - in the :ref:`unified_tutorial`
-
-
-        :param table: :class:`_expression.TableClause`
-         which is the subject of the
-         insert.
-
-        :param values: collection of values to be inserted; see
-         :meth:`_expression.Insert.values`
-         for a description of allowed formats here.
-         Can be omitted entirely; a :class:`_expression.Insert` construct
-         will also dynamically render the VALUES clause at execution time
-         based on the parameters passed to :meth:`_engine.Connection.execute`.
-
-        :param inline: if True, no attempt will be made to retrieve the
-         SQL-generated default values to be provided within the statement;
-         in particular,
-         this allows SQL expressions to be rendered 'inline' within the
-         statement without the need to pre-execute them beforehand; for
-         backends that support "returning", this turns off the "implicit
-         returning" feature for the statement.
-
-        If both :paramref:`_expression.Insert.values` and compile-time bind
-        parameters are present, the compile-time bind parameters override the
-        information specified within :paramref:`_expression.Insert.values` on a
-        per-key basis.
-
-        The keys within :paramref:`_expression.Insert.values` can be either
-        :class:`~sqlalchemy.schema.Column` objects or their string
-        identifiers. Each key may reference one of:
-
-        * a literal data value (i.e. string, number, etc.);
-        * a Column object;
-        * a SELECT statement.
-
-        If a ``SELECT`` statement is specified which references this
-        ``INSERT`` statement's table, the statement will be correlated
-        against the ``INSERT`` statement.
-
-        .. seealso::
-
-            :ref:`coretutorial_insert_expressions` - SQL Expression Tutorial
-
-            :ref:`inserts_and_updates` - SQL Expression Tutorial
-
-        """
+    def __init__(self, table):
         super(Insert, self).__init__(table)
 
     @_generative
@@ -1045,118 +976,7 @@ class Update(DMLWhereBase, ValuesBase):
         + HasCTE._has_ctes_traverse_internals
     )
 
-    def __init__(
-        self,
-        table,
-    ):
-        r"""Construct an :class:`_expression.Update` object.
-
-        E.g.::
-
-            from sqlalchemy import update
-
-            stmt = (
-                update(user_table).
-                where(user_table.c.id == 5).
-                values(name='user #5')
-            )
-
-        Similar functionality is available via the
-        :meth:`_expression.TableClause.update` method on
-        :class:`_schema.Table`.
-
-        .. seealso::
-
-            :ref:`inserts_and_updates` - in the
-            :ref:`1.x tutorial <sqlexpression_toplevel>`
-
-            :ref:`tutorial_core_update_delete` - in the :ref:`unified_tutorial`
-
-
-
-        :param table: A :class:`_schema.Table`
-         object representing the database
-         table to be updated.
-
-        :param whereclause: Optional SQL expression describing the ``WHERE``
-         condition of the ``UPDATE`` statement; is equivalent to using the
-         more modern :meth:`~Update.where()` method to specify the ``WHERE``
-         clause.
-
-        :param values:
-          Optional dictionary which specifies the ``SET`` conditions of the
-          ``UPDATE``.  If left as ``None``, the ``SET``
-          conditions are determined from those parameters passed to the
-          statement during the execution and/or compilation of the
-          statement.   When compiled standalone without any parameters,
-          the ``SET`` clause generates for all columns.
-
-          Modern applications may prefer to use the generative
-          :meth:`_expression.Update.values` method to set the values of the
-          UPDATE statement.
-
-        :param inline:
-          if True, SQL defaults present on :class:`_schema.Column` objects via
-          the ``default`` keyword will be compiled 'inline' into the statement
-          and not pre-executed.  This means that their values will not
-          be available in the dictionary returned from
-          :meth:`_engine.CursorResult.last_updated_params`.
-
-        :param preserve_parameter_order: if True, the update statement is
-          expected to receive parameters **only** via the
-          :meth:`_expression.Update.values` method,
-          and they must be passed as a Python
-          ``list`` of 2-tuples. The rendered UPDATE statement will emit the SET
-          clause for each referenced column maintaining this order.
-
-          .. versionadded:: 1.0.10
-
-          .. seealso::
-
-            :ref:`updates_order_parameters` - illustrates the
-            :meth:`_expression.Update.ordered_values` method.
-
-        If both ``values`` and compile-time bind parameters are present, the
-        compile-time bind parameters override the information specified
-        within ``values`` on a per-key basis.
-
-        The keys within ``values`` can be either :class:`_schema.Column`
-        objects or their string identifiers (specifically the "key" of the
-        :class:`_schema.Column`, normally but not necessarily equivalent to
-        its "name").  Normally, the
-        :class:`_schema.Column` objects used here are expected to be
-        part of the target :class:`_schema.Table` that is the table
-        to be updated.  However when using MySQL, a multiple-table
-        UPDATE statement can refer to columns from any of
-        the tables referred to in the WHERE clause.
-
-        The values referred to in ``values`` are typically:
-
-        * a literal data value (i.e. string, number, etc.)
-        * a SQL expression, such as a related :class:`_schema.Column`,
-          a scalar-returning :func:`_expression.select` construct,
-          etc.
-
-        When combining :func:`_expression.select` constructs within the
-        values clause of an :func:`_expression.update`
-        construct, the subquery represented
-        by the :func:`_expression.select` should be *correlated* to the
-        parent table, that is, providing criterion which links the table inside
-        the subquery to the outer table being updated::
-
-            users.update().values(
-                    name=select(addresses.c.email_address).\
-                            where(addresses.c.user_id==users.c.id).\
-                            scalar_subquery()
-                )
-
-        .. seealso::
-
-            :ref:`inserts_and_updates` - SQL Expression
-            Language Tutorial
-
-
-        """
+    def __init__(self, table):
         super(Update, self).__init__(table)
 
     @_generative
@@ -1244,45 +1064,7 @@ class Delete(DMLWhereBase, UpdateBase):
         + HasCTE._has_ctes_traverse_internals
     )
 
-    def __init__(
-        self,
-        table,
-    ):
-        r"""Construct :class:`_expression.Delete` object.
-
-        E.g.::
-
-            from sqlalchemy import delete
-
-            stmt = (
-                delete(user_table).
-                where(user_table.c.id == 5)
-            )
-
-        Similar functionality is available via the
-        :meth:`_expression.TableClause.delete` method on
-        :class:`_schema.Table`.
-
-        .. seealso::
-
-            :ref:`inserts_and_updates` - in the
-            :ref:`1.x tutorial <sqlexpression_toplevel>`
-
-            :ref:`tutorial_core_update_delete` - in the :ref:`unified_tutorial`
-
-
-        :param table: The table to delete rows from.
-
-        :param whereclause: Optional SQL expression describing the ``WHERE``
-         condition of the ``DELETE`` statement; is equivalent to using the
-         more modern :meth:`~Delete.where()` method to specify the ``WHERE``
-         clause.
-
-        .. seealso::
-
-            :ref:`deletes` - SQL Expression Tutorial
-
-        """
+    def __init__(self, table):
         self.table = coercions.expect(
             roles.DMLTableRole, table, apply_propagate_attrs=self
         )
index a025cce357fb7bb0e1efb7720663279122aefe5e..705a898899a34db34c8399daa6a2143189f09054 100644 (file)
@@ -14,6 +14,16 @@ import itertools
 import operator
 import re
 import typing
+from typing import Any
+from typing import Callable
+from typing import Generic
+from typing import Optional
+from typing import overload
+from typing import Sequence
+from typing import Text as typing_Text
+from typing import Type
+from typing import TypeVar
+from typing import Union
 
 from . import coercions
 from . import operators
@@ -31,7 +41,7 @@ from .base import NO_ARG
 from .base import SingletonConstant
 from .cache_key import MemoizedHasCacheKey
 from .cache_key import NO_CACHE
-from .coercions import _document_text_coercion
+from .coercions import _document_text_coercion  # noqa
 from .traversals import HasCopyInternals
 from .visitors import cloned_traverse
 from .visitors import InternalTraversal
@@ -41,86 +51,20 @@ from .. import exc
 from .. import inspection
 from .. import util
 
+if typing.TYPE_CHECKING:
+    from decimal import Decimal
 
-def collate(expression, collation):
-    """Return the clause ``expression COLLATE collation``.
+    from .selectable import FromClause
+    from .selectable import Select
+    from .sqltypes import Boolean  # noqa
+    from .type_api import TypeEngine
 
-    e.g.::
+_NUMERIC = Union[complex, "Decimal"]
 
-        collate(mycolumn, 'utf8_bin')
-
-    produces::
-
-        mycolumn COLLATE utf8_bin
-
-    The collation expression is also quoted if it is a case sensitive
-    identifier, e.g. contains uppercase characters.
-
-    .. versionchanged:: 1.2 quoting is automatically applied to COLLATE
-       expressions if they are case sensitive.
-
-    """
-
-    expr = coercions.expect(roles.ExpressionElementRole, expression)
-    return BinaryExpression(
-        expr, CollationClause(collation), operators.collate, type_=expr.type
-    )
-
-
-def between(expr, lower_bound, upper_bound, symmetric=False):
-    """Produce a ``BETWEEN`` predicate clause.
-
-    E.g.::
-
-        from sqlalchemy import between
-        stmt = select(users_table).where(between(users_table.c.id, 5, 7))
-
-    Would produce SQL resembling::
-
-        SELECT id, name FROM user WHERE id BETWEEN :id_1 AND :id_2
-
-    The :func:`.between` function is a standalone version of the
-    :meth:`_expression.ColumnElement.between` method available on all
-    SQL expressions, as in::
-
-        stmt = select(users_table).where(users_table.c.id.between(5, 7))
-
-    All arguments passed to :func:`.between`, including the left side
-    column expression, are coerced from Python scalar values if a
-    the value is not a :class:`_expression.ColumnElement` subclass.
-    For example,
-    three fixed values can be compared as in::
-
-        print(between(5, 3, 7))
-
-    Which would produce::
-
-        :param_1 BETWEEN :param_2 AND :param_3
-
-    :param expr: a column expression, typically a
-     :class:`_expression.ColumnElement`
-     instance or alternatively a Python scalar expression to be coerced
-     into a column expression, serving as the left side of the ``BETWEEN``
-     expression.
-
-    :param lower_bound: a column or Python scalar expression serving as the
-     lower bound of the right side of the ``BETWEEN`` expression.
-
-    :param upper_bound: a column or Python scalar expression serving as the
-     upper bound of the right side of the ``BETWEEN`` expression.
-
-    :param symmetric: if True, will render " BETWEEN SYMMETRIC ". Note
-     that not all databases support this syntax.
-
-     .. versionadded:: 0.9.5
-
-    .. seealso::
-
-        :meth:`_expression.ColumnElement.between`
-
-    """
-    expr = coercions.expect(roles.ExpressionElementRole, expr)
-    return expr.between(lower_bound, upper_bound, symmetric=symmetric)
+_T = TypeVar("_T", bound="Any")
+_OPT = TypeVar("_OPT", bound="Any")
+_NT = TypeVar("_NT", bound="_NUMERIC")
+_ST = TypeVar("_ST", bound="typing_Text")
 
 
 def literal(value, type_=None):
@@ -145,28 +89,40 @@ def literal(value, type_=None):
     return coercions.expect(roles.LiteralValueRole, value, type_=type_)
 
 
-def outparam(key, type_=None):
-    """Create an 'OUT' parameter for usage in functions (stored procedures),
-    for databases which support them.
+def literal_column(text, type_=None):
+    r"""Produce a :class:`.ColumnClause` object that has the
+    :paramref:`_expression.column.is_literal` flag set to True.
+
+    :func:`_expression.literal_column` is similar to
+    :func:`_expression.column`, except that
+    it is more often used as a "standalone" column expression that renders
+    exactly as stated; while :func:`_expression.column`
+    stores a string name that
+    will be assumed to be part of a table and may be quoted as such,
+    :func:`_expression.literal_column` can be that,
+    or any other arbitrary column-oriented
+    expression.
+
+    :param text: the text of the expression; can be any SQL expression.
+      Quoting rules will not be applied. To specify a column-name expression
+      which should be subject to quoting rules, use the :func:`column`
+      function.
 
-    The ``outparam`` can be used like a regular function parameter.
-    The "output" value will be available from the
-    :class:`~sqlalchemy.engine.CursorResult` object via its ``out_parameters``
-    attribute, which returns a dictionary containing the values.
+    :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine`
+      object which will
+      provide result-set translation and additional expression semantics for
+      this column. If left as ``None`` the type will be :class:`.NullType`.
 
-    """
-    return BindParameter(key, None, type_=type_, unique=False, isoutparam=True)
+    .. seealso::
 
+        :func:`_expression.column`
 
-def not_(clause):
-    """Return a negation of the given clause, i.e. ``NOT(clause)``.
+        :func:`_expression.text`
 
-    The ``~`` operator is also overloaded on all
-    :class:`_expression.ColumnElement` subclasses to produce the
-    same result.
+        :ref:`sqlexpression_literal_column`
 
     """
-    return operators.inv(coercions.expect(roles.ExpressionElementRole, clause))
+    return ColumnClause(text, type_=type_, is_literal=True)
 
 
 class CompilerElement(Traversible):
@@ -258,6 +214,9 @@ class CompilerElement(Traversible):
         return str(self.compile())
 
 
+SelfClauseElement = TypeVar("SelfClauseElement", bound="ClauseElement")
+
+
 @inspection._self_inspects
 class ClauseElement(
     SupportsWrappingAnnotations,
@@ -313,7 +272,7 @@ class ClauseElement(
         self._propagate_attrs = util.immutabledict(values)
         return self
 
-    def _clone(self, **kw):
+    def _clone(self: SelfClauseElement, **kw) -> SelfClauseElement:
         """Create a shallow copy of this ClauseElement.
 
         This method may be used by a generative API.  Its also used as
@@ -624,8 +583,9 @@ class ColumnElement(
     roles.DMLColumnRole,
     roles.DDLConstraintColumnRole,
     roles.DDLExpressionRole,
-    operators.ColumnOperators,
+    operators.ColumnOperators["ColumnElement"],
     ClauseElement,
+    Generic[_T],
 ):
     """Represent a column-oriented SQL expression suitable for usage in the
     "columns" clause, WHERE clause etc. of a statement.
@@ -841,11 +801,11 @@ class ColumnElement(
             return super(ColumnElement, self)._negate()
 
     @util.memoized_property
-    def type(self):
+    def type(self) -> "TypeEngine[_T]":
         return type_api.NULLTYPE
 
     @HasMemoized.memoized_attribute
-    def comparator(self):
+    def comparator(self) -> "TypeEngine.Comparator[_T]":
         try:
             comparator_factory = self.type.comparator_factory
         except AttributeError as err:
@@ -869,10 +829,347 @@ class ColumnElement(
                 )
             ) from err
 
-    def operate(self, op, *other, **kwargs):
+    # annotations for comparison methods
+    # these are from operators->Operators / ColumnOperators,
+    # redefined with the specific types returned by ColumnElement hierarchies
+    if typing.TYPE_CHECKING:
+
+        def op(
+            self,
+            opstring: Any,
+            precedence: int = 0,
+            is_comparison: bool = False,
+            return_type: Optional[
+                Union[Type["TypeEngine[_OPT]"], "TypeEngine[_OPT]"]
+            ] = None,
+            python_impl=None,
+        ) -> Callable[[Any], "BinaryExpression[_OPT]"]:
+            ...
+
+        def bool_op(
+            self, opstring: Any, precedence: int = 0, python_impl=None
+        ) -> Callable[[Any], "BinaryExpression[bool]"]:
+            ...
+
+        def __and__(self, other: Any) -> "BooleanClauseList":
+            ...
+
+        def __or__(self, other: Any) -> "BooleanClauseList":
+            ...
+
+        def __invert__(self) -> "UnaryExpression[_T]":
+            ...
+
+        def __lt__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __le__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __eq__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __ne__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def is_distinct_from(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def is_not_distinct_from(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __gt__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __ge__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __neg__(self) -> "UnaryExpression[_T]":
+            ...
+
+        def __contains__(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def __getitem__(self, index: Any) -> "ColumnElement":
+            ...
+
+        @overload
+        def concat(self, other: Any) -> "BinaryExpression[_ST]":
+            ...
+
+        @overload
+        def concat(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def concat(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def like(self, other: Any, escape=None) -> "BinaryExpression[bool]":
+            ...
+
+        def ilike(self, other: Any, escape=None) -> "BinaryExpression[bool]":
+            ...
+
+        def in_(
+            self,
+            other: Union[Sequence[Any], "BindParameter", "Select"],
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def not_in(
+            self,
+            other: Union[Sequence[Any], "BindParameter", "Select"],
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def not_like(
+            self, other: Any, escape=None
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def not_ilike(
+            self, other: Any, escape=None
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def is_(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def is_not(self, other: Any) -> "BinaryExpression[bool]":
+            ...
+
+        def startswith(
+            self, other: Any, escape=None, autoescape=False
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def endswith(
+            self, other: Any, escape=None, autoescape=False
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def contains(
+            self, other: Any, escape=None, autoescape=False
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def match(self, other: Any, **kwargs) -> "BinaryExpression[bool]":
+            ...
+
+        def regexp_match(
+            self, pattern, flags=None
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def regexp_replace(
+            self, pattern, replacement, flags=None
+        ) -> "BinaryExpression":
+            ...
+
+        def desc(self) -> "UnaryExpression[_T]":
+            ...
+
+        def asc(self) -> "UnaryExpression[_T]":
+            ...
+
+        def nulls_first(self) -> "UnaryExpression[_T]":
+            ...
+
+        def nulls_last(self) -> "UnaryExpression[_T]":
+            ...
+
+        def collate(self, collation) -> "CollationClause":
+            ...
+
+        def between(
+            self, cleft, cright, symmetric=False
+        ) -> "BinaryExpression[bool]":
+            ...
+
+        def distinct(self: "ColumnElement[_T]") -> "UnaryExpression[_T]":
+            ...
+
+        def any_(self) -> "CollectionAggregate":
+            ...
+
+        def all_(self) -> "CollectionAggregate":
+            ...
+
+        # numeric overloads.  These need more tweaking
+
+        @overload
+        def __add__(
+            self: "ColumnElement[_NT]", other: "Union[ColumnElement[_NT], _NT]"
+        ) -> "BinaryExpression[_NT]":
+            ...
+
+        @overload
+        def __add__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __add__(
+            self: "ColumnElement[_ST]", other: Any
+        ) -> "BinaryExpression[_ST]":
+            ...
+
+        def __add__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __radd__(self, other: Any) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __radd__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __radd__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __sub__(
+            self: "ColumnElement[_NT]", other: "Union[ColumnElement[_NT], _NT]"
+        ) -> "BinaryExpression[_NT]":
+            ...
+
+        @overload
+        def __sub__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __sub__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __rsub__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __rsub__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __rsub__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __mul__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __mul__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __mul__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __rmul__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __rmul__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __rmul__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __mod__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __mod__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __mod__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __rmod__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __rmod__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __rmod__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __truediv__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __truediv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __truediv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __rtruediv__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __rtruediv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __rtruediv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __floordiv__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __floordiv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __floordiv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        @overload
+        def __rfloordiv__(
+            self: "ColumnElement[_NT]", other: Any
+        ) -> "BinaryExpression[_NUMERIC]":
+            ...
+
+        @overload
+        def __rfloordiv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+        def __rfloordiv__(self, other: Any) -> "BinaryExpression":
+            ...
+
+    def operate(
+        self,
+        op: operators.OperatorType,
+        *other: Any,
+        **kwargs,
+    ) -> "ColumnElement":
         return op(self.comparator, *other, **kwargs)
 
-    def reverse_operate(self, op, other, **kwargs):
+    def reverse_operate(
+        self, op: operators.OperatorType, other: Any, **kwargs
+    ) -> "ColumnElement":
         return op(other, self.comparator, **kwargs)
 
     def _bind_param(self, operator, obj, type_=None, expanding=False):
@@ -975,7 +1272,12 @@ class ColumnElement(
             return None
 
     def _make_proxy(
-        self, selectable, name=None, key=None, name_is_truncatable=False, **kw
+        self,
+        selectable,
+        name: Optional[str] = None,
+        key=None,
+        name_is_truncatable=False,
+        **kw,
     ):
         """Create a new :class:`_expression.ColumnElement` representing this
         :class:`_expression.ColumnElement` as it appears in the select list of
@@ -1031,7 +1333,7 @@ class ColumnElement(
         """
         return Label(name, self, self.type)
 
-    def _anon_label(self, seed, add_hash=None):
+    def _anon_label(self, seed, add_hash=None) -> "_anonymous_label":
         while self._is_clone_of is not None:
             self = self._is_clone_of
 
@@ -1066,7 +1368,7 @@ class ColumnElement(
         return _anonymous_label.safe_construct(hash_value, seed or "anon")
 
     @util.memoized_property
-    def _anon_name_label(self):
+    def _anon_name_label(self) -> "_anonymous_label":
         """Provides a constant 'anonymous label' for this ColumnElement.
 
         This is a label() expression which will be named at compile time.
@@ -1214,7 +1516,10 @@ class WrapsColumnExpression:
             return self._dedupe_anon_tq_label_idx(idx)
 
 
-class BindParameter(roles.InElementRole, ColumnElement):
+SelfBindParameter = TypeVar("SelfBindParameter", bound="BindParameter")
+
+
+class BindParameter(roles.InElementRole, ColumnElement[_T]):
     r"""Represent a "bound expression".
 
     :class:`.BindParameter` is invoked explicitly using the
@@ -1267,238 +1572,6 @@ class BindParameter(roles.InElementRole, ColumnElement):
         _compared_to_type=None,
         _is_crud=False,
     ):
-        r"""Produce a "bound expression".
-
-        The return value is an instance of :class:`.BindParameter`; this
-        is a :class:`_expression.ColumnElement`
-        subclass which represents a so-called
-        "placeholder" value in a SQL expression, the value of which is
-        supplied at the point at which the statement in executed against a
-        database connection.
-
-        In SQLAlchemy, the :func:`.bindparam` construct has
-        the ability to carry along the actual value that will be ultimately
-        used at expression time.  In this way, it serves not just as
-        a "placeholder" for eventual population, but also as a means of
-        representing so-called "unsafe" values which should not be rendered
-        directly in a SQL statement, but rather should be passed along
-        to the :term:`DBAPI` as values which need to be correctly escaped
-        and potentially handled for type-safety.
-
-        When using :func:`.bindparam` explicitly, the use case is typically
-        one of traditional deferment of parameters; the :func:`.bindparam`
-        construct accepts a name which can then be referred to at execution
-        time::
-
-            from sqlalchemy import bindparam
-
-            stmt = select(users_table).\
-                        where(users_table.c.name == bindparam('username'))
-
-        The above statement, when rendered, will produce SQL similar to::
-
-            SELECT id, name FROM user WHERE name = :username
-
-        In order to populate the value of ``:username`` above, the value
-        would typically be applied at execution time to a method
-        like :meth:`_engine.Connection.execute`::
-
-            result = connection.execute(stmt, username='wendy')
-
-        Explicit use of :func:`.bindparam` is also common when producing
-        UPDATE or DELETE statements that are to be invoked multiple times,
-        where the WHERE criterion of the statement is to change on each
-        invocation, such as::
-
-            stmt = (users_table.update().
-                    where(user_table.c.name == bindparam('username')).
-                    values(fullname=bindparam('fullname'))
-                    )
-
-            connection.execute(
-                stmt, [{"username": "wendy", "fullname": "Wendy Smith"},
-                       {"username": "jack", "fullname": "Jack Jones"},
-                       ]
-            )
-
-        SQLAlchemy's Core expression system makes wide use of
-        :func:`.bindparam` in an implicit sense.   It is typical that Python
-        literal values passed to virtually all SQL expression functions are
-        coerced into fixed :func:`.bindparam` constructs.  For example, given
-        a comparison operation such as::
-
-            expr = users_table.c.name == 'Wendy'
-
-        The above expression will produce a :class:`.BinaryExpression`
-        construct, where the left side is the :class:`_schema.Column` object
-        representing the ``name`` column, and the right side is a
-        :class:`.BindParameter` representing the literal value::
-
-            print(repr(expr.right))
-            BindParameter('%(4327771088 name)s', 'Wendy', type_=String())
-
-        The expression above will render SQL such as::
-
-            user.name = :name_1
-
-        Where the ``:name_1`` parameter name is an anonymous name.  The
-        actual string ``Wendy`` is not in the rendered string, but is carried
-        along where it is later used within statement execution.  If we
-        invoke a statement like the following::
-
-            stmt = select(users_table).where(users_table.c.name == 'Wendy')
-            result = connection.execute(stmt)
-
-        We would see SQL logging output as::
-
-            SELECT "user".id, "user".name
-            FROM "user"
-            WHERE "user".name = %(name_1)s
-            {'name_1': 'Wendy'}
-
-        Above, we see that ``Wendy`` is passed as a parameter to the database,
-        while the placeholder ``:name_1`` is rendered in the appropriate form
-        for the target database, in this case the PostgreSQL database.
-
-        Similarly, :func:`.bindparam` is invoked automatically when working
-        with :term:`CRUD` statements as far as the "VALUES" portion is
-        concerned.   The :func:`_expression.insert` construct produces an
-        ``INSERT`` expression which will, at statement execution time, generate
-        bound placeholders based on the arguments passed, as in::
-
-            stmt = users_table.insert()
-            result = connection.execute(stmt, name='Wendy')
-
-        The above will produce SQL output as::
-
-            INSERT INTO "user" (name) VALUES (%(name)s)
-            {'name': 'Wendy'}
-
-        The :class:`_expression.Insert` construct, at
-        compilation/execution time, rendered a single :func:`.bindparam`
-        mirroring the column name ``name`` as a result of the single ``name``
-        parameter we passed to the :meth:`_engine.Connection.execute` method.
-
-        :param key:
-          the key (e.g. the name) for this bind param.
-          Will be used in the generated
-          SQL statement for dialects that use named parameters.  This
-          value may be modified when part of a compilation operation,
-          if other :class:`BindParameter` objects exist with the same
-          key, or if its length is too long and truncation is
-          required.
-
-        :param value:
-          Initial value for this bind param.  Will be used at statement
-          execution time as the value for this parameter passed to the
-          DBAPI, if no other value is indicated to the statement execution
-          method for this particular parameter name.  Defaults to ``None``.
-
-        :param callable\_:
-          A callable function that takes the place of "value".  The function
-          will be called at statement execution time to determine the
-          ultimate value.   Used for scenarios where the actual bind
-          value cannot be determined at the point at which the clause
-          construct is created, but embedded bind values are still desirable.
-
-        :param type\_:
-          A :class:`.TypeEngine` class or instance representing an optional
-          datatype for this :func:`.bindparam`.  If not passed, a type
-          may be determined automatically for the bind, based on the given
-          value; for example, trivial Python types such as ``str``,
-          ``int``, ``bool``
-          may result in the :class:`.String`, :class:`.Integer` or
-          :class:`.Boolean` types being automatically selected.
-
-          The type of a :func:`.bindparam` is significant especially in that
-          the type will apply pre-processing to the value before it is
-          passed to the database.  For example, a :func:`.bindparam` which
-          refers to a datetime value, and is specified as holding the
-          :class:`.DateTime` type, may apply conversion needed to the
-          value (such as stringification on SQLite) before passing the value
-          to the database.
-
-        :param unique:
-          if True, the key name of this :class:`.BindParameter` will be
-          modified if another :class:`.BindParameter` of the same name
-          already has been located within the containing
-          expression.  This flag is used generally by the internals
-          when producing so-called "anonymous" bound expressions, it
-          isn't generally applicable to explicitly-named :func:`.bindparam`
-          constructs.
-
-        :param required:
-          If ``True``, a value is required at execution time.  If not passed,
-          it defaults to ``True`` if neither :paramref:`.bindparam.value`
-          or :paramref:`.bindparam.callable` were passed.  If either of these
-          parameters are present, then :paramref:`.bindparam.required`
-          defaults to ``False``.
-
-        :param quote:
-          True if this parameter name requires quoting and is not
-          currently known as a SQLAlchemy reserved word; this currently
-          only applies to the Oracle backend, where bound names must
-          sometimes be quoted.
-
-        :param isoutparam:
-          if True, the parameter should be treated like a stored procedure
-          "OUT" parameter.  This applies to backends such as Oracle which
-          support OUT parameters.
-
-        :param expanding:
-          if True, this parameter will be treated as an "expanding" parameter
-          at execution time; the parameter value is expected to be a sequence,
-          rather than a scalar value, and the string SQL statement will
-          be transformed on a per-execution basis to accommodate the sequence
-          with a variable number of parameter slots passed to the DBAPI.
-          This is to allow statement caching to be used in conjunction with
-          an IN clause.
-
-          .. seealso::
-
-            :meth:`.ColumnOperators.in_`
-
-            :ref:`baked_in` - with baked queries
-
-          .. note:: The "expanding" feature does not support "executemany"-
-             style parameter sets.
-
-          .. versionadded:: 1.2
-
-          .. versionchanged:: 1.3 the "expanding" bound parameter feature now
-             supports empty lists.
-
-
-        .. seealso::
-
-            :ref:`coretutorial_bind_param`
-
-            :ref:`coretutorial_insert_expressions`
-
-            :func:`.outparam`
-
-        :param literal_execute:
-          if True, the bound parameter will be rendered in the compile phase
-          with a special "POSTCOMPILE" token, and the SQLAlchemy compiler will
-          render the final value of the parameter into the SQL statement at
-          statement execution time, omitting the value from the parameter
-          dictionary / list passed to DBAPI ``cursor.execute()``.  This
-          produces a similar effect as that of using the ``literal_binds``,
-          compilation flag,  however takes place as the statement is sent to
-          the DBAPI ``cursor.execute()`` method, rather than when the statement
-          is compiled.   The primary use of this
-          capability is for rendering LIMIT / OFFSET clauses for database
-          drivers that can't accommodate for bound parameters in these
-          contexts, while allowing SQL constructs to be cacheable at the
-          compilation level.
-
-          .. versionadded:: 1.4 Added "post compile" bound parameters
-
-            .. seealso::
-
-                :ref:`change_4808`.
-
-        """
         if required is NO_ARG:
             required = value is NO_ARG and callable_ is None
         if value is NO_ARG:
@@ -1641,7 +1714,9 @@ class BindParameter(roles.InElementRole, ColumnElement):
         c.type = type_
         return c
 
-    def _clone(self, maintain_key=False, **kw):
+    def _clone(
+        self: SelfBindParameter, maintain_key=False, **kw
+    ) -> SelfBindParameter:
         c = ClauseElement._clone(self, **kw)
         if not maintain_key and self.unique:
             c.key = _anonymous_label.safe_construct(
@@ -1799,85 +1874,6 @@ class TextClause(
         # to the list of bindparams
         self.text = self._bind_params_regex.sub(repl, text)
 
-    @classmethod
-    @_document_text_coercion("text", ":func:`.text`", ":paramref:`.text.text`")
-    def _create_text(cls, text):
-        r"""Construct a new :class:`_expression.TextClause` clause,
-        representing
-        a textual SQL string directly.
-
-        E.g.::
-
-            from sqlalchemy import text
-
-            t = text("SELECT * FROM users")
-            result = connection.execute(t)
-
-        The advantages :func:`_expression.text`
-        provides over a plain string are
-        backend-neutral support for bind parameters, per-statement
-        execution options, as well as
-        bind parameter and result-column typing behavior, allowing
-        SQLAlchemy type constructs to play a role when executing
-        a statement that is specified literally.  The construct can also
-        be provided with a ``.c`` collection of column elements, allowing
-        it to be embedded in other SQL expression constructs as a subquery.
-
-        Bind parameters are specified by name, using the format ``:name``.
-        E.g.::
-
-            t = text("SELECT * FROM users WHERE id=:user_id")
-            result = connection.execute(t, user_id=12)
-
-        For SQL statements where a colon is required verbatim, as within
-        an inline string, use a backslash to escape::
-
-            t = text("SELECT * FROM users WHERE name='\:username'")
-
-        The :class:`_expression.TextClause`
-        construct includes methods which can
-        provide information about the bound parameters as well as the column
-        values which would be returned from the textual statement, assuming
-        it's an executable SELECT type of statement.  The
-        :meth:`_expression.TextClause.bindparams`
-        method is used to provide bound
-        parameter detail, and :meth:`_expression.TextClause.columns`
-        method allows
-        specification of return columns including names and types::
-
-            t = text("SELECT * FROM users WHERE id=:user_id").\
-                    bindparams(user_id=7).\
-                    columns(id=Integer, name=String)
-
-            for id, name in connection.execute(t):
-                print(id, name)
-
-        The :func:`_expression.text` construct is used in cases when
-        a literal string SQL fragment is specified as part of a larger query,
-        such as for the WHERE clause of a SELECT statement::
-
-            s = select(users.c.id, users.c.name).where(text("id=:user_id"))
-            result = connection.execute(s, user_id=12)
-
-        :func:`_expression.text` is also used for the construction
-        of a full, standalone statement using plain text.
-        As such, SQLAlchemy refers
-        to it as an :class:`.Executable` object and may be used
-        like any other statement passed to an ``.execute()`` method.
-
-        :param text:
-          the text of the SQL statement to be created.  Use ``:<param>``
-          to specify bind parameters; they will be compiled to their
-          engine-specific format.
-
-        .. seealso::
-
-            :ref:`sqlexpression_text` - in the Core tutorial
-
-
-        """
-        return TextClause(text)
-
     @_generative
     def bindparams(
         self: SelfTextClause, *binds, **names_to_values
@@ -2204,40 +2200,6 @@ class False_(SingletonConstant, roles.ConstExprRole, ColumnElement):
 
     @classmethod
     def _instance(cls):
-        """Return a :class:`.False_` construct.
-
-        E.g.::
-
-            >>> from sqlalchemy import false
-            >>> print(select(t.c.x).where(false()))
-            SELECT x FROM t WHERE false
-
-        A backend which does not support true/false constants will render as
-        an expression against 1 or 0::
-
-            >>> print(select(t.c.x).where(false()))
-            SELECT x FROM t WHERE 0 = 1
-
-        The :func:`.true` and :func:`.false` constants also feature
-        "short circuit" operation within an :func:`.and_` or :func:`.or_`
-        conjunction::
-
-            >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
-            SELECT x FROM t WHERE true
-
-            >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
-            SELECT x FROM t WHERE false
-
-        .. versionchanged:: 0.9 :func:`.true` and :func:`.false` feature
-           better integrated behavior within conjunctions and on dialects
-           that don't support true/false constants.
-
-        .. seealso::
-
-            :func:`.true`
-
-        """
-
         return False_()
 
 
@@ -2272,40 +2234,6 @@ class True_(SingletonConstant, roles.ConstExprRole, ColumnElement):
 
     @classmethod
     def _instance(cls):
-        """Return a constant :class:`.True_` construct.
-
-        E.g.::
-
-            >>> from sqlalchemy import true
-            >>> print(select(t.c.x).where(true()))
-            SELECT x FROM t WHERE true
-
-        A backend which does not support true/false constants will render as
-        an expression against 1 or 0::
-
-            >>> print(select(t.c.x).where(true()))
-            SELECT x FROM t WHERE 1 = 1
-
-        The :func:`.true` and :func:`.false` constants also feature
-        "short circuit" operation within an :func:`.and_` or :func:`.or_`
-        conjunction::
-
-            >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
-            SELECT x FROM t WHERE true
-
-            >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
-            SELECT x FROM t WHERE false
-
-        .. versionchanged:: 0.9 :func:`.true` and :func:`.false` feature
-           better integrated behavior within conjunctions and on dialects
-           that don't support true/false constants.
-
-        .. seealso::
-
-            :func:`.false`
-
-        """
-
         return True_()
 
 
@@ -2334,15 +2262,23 @@ class ClauseList(
         ("operator", InternalTraversal.dp_operator),
     ]
 
-    def __init__(self, *clauses, **kwargs):
-        self.operator = kwargs.pop("operator", operators.comma_op)
-        self.group = kwargs.pop("group", True)
-        self.group_contents = kwargs.pop("group_contents", True)
-        if kwargs.pop("_flatten_sub_clauses", False):
+    def __init__(
+        self,
+        *clauses,
+        operator=operators.comma_op,
+        group=True,
+        group_contents=True,
+        _flatten_sub_clauses=False,
+        _literal_as_text_role: Type[roles.SQLRole] = roles.WhereHavingRole,
+    ):
+        self.operator = operator
+        self.group = group
+        self.group_contents = group_contents
+        if _flatten_sub_clauses:
             clauses = util.flatten_iterator(clauses)
-        self._text_converter_role = text_converter_role = kwargs.pop(
-            "_literal_as_text_role", roles.WhereHavingRole
-        )
+        self._text_converter_role: Type[roles.SQLRole] = _literal_as_text_role
+        text_converter_role: Type[roles.SQLRole] = _literal_as_text_role
+
         if self.group_contents:
             self.clauses = [
                 coercions.expect(
@@ -2404,7 +2340,7 @@ class ClauseList(
             return self
 
 
-class BooleanClauseList(ClauseList, ColumnElement):
+class BooleanClauseList(ClauseList, ColumnElement[bool]):
     __visit_name__ = "clauselist"
     inherit_cache = True
 
@@ -2531,60 +2467,7 @@ class BooleanClauseList(ClauseList, ColumnElement):
     def and_(cls, *clauses):
         r"""Produce a conjunction of expressions joined by ``AND``.
 
-        E.g.::
-
-            from sqlalchemy import and_
-
-            stmt = select(users_table).where(
-                            and_(
-                                users_table.c.name == 'wendy',
-                                users_table.c.enrolled == True
-                            )
-                        )
-
-        The :func:`.and_` conjunction is also available using the
-        Python ``&`` operator (though note that compound expressions
-        need to be parenthesized in order to function with Python
-        operator precedence behavior)::
-
-            stmt = select(users_table).where(
-                            (users_table.c.name == 'wendy') &
-                            (users_table.c.enrolled == True)
-                        )
-
-        The :func:`.and_` operation is also implicit in some cases;
-        the :meth:`_expression.Select.where`
-        method for example can be invoked multiple
-        times against a statement, which will have the effect of each
-        clause being combined using :func:`.and_`::
-
-            stmt = select(users_table).\
-                    where(users_table.c.name == 'wendy').\
-                    where(users_table.c.enrolled == True)
-
-        The :func:`.and_` construct must be given at least one positional
-        argument in order to be valid; a :func:`.and_` construct with no
-        arguments is ambiguous.   To produce an "empty" or dynamically
-        generated :func:`.and_`  expression, from a given list of expressions,
-        a "default" element of ``True`` should be specified::
-
-            criteria = and_(True, *expressions)
-
-        The above expression will compile to SQL as the expression ``true``
-        or ``1 = 1``, depending on backend, if no other expressions are
-        present.  If expressions are present, then the ``True`` value is
-        ignored as it does not affect the outcome of an AND expression that
-        has other elements.
-
-        .. deprecated:: 1.4  The :func:`.and_` element now requires that at
-           least one argument is passed; creating the :func:`.and_` construct
-           with no arguments is deprecated, and will emit a deprecation warning
-           while continuing to produce a blank SQL string.
-
-        .. seealso::
-
-            :func:`.or_`
-
+        See :func:`_sql.and_` for full documentation.
         """
         return cls._construct(
             operators.and_, True_._singleton, False_._singleton, *clauses
@@ -2594,50 +2477,7 @@ class BooleanClauseList(ClauseList, ColumnElement):
     def or_(cls, *clauses):
         """Produce a conjunction of expressions joined by ``OR``.
 
-        E.g.::
-
-            from sqlalchemy import or_
-
-            stmt = select(users_table).where(
-                            or_(
-                                users_table.c.name == 'wendy',
-                                users_table.c.name == 'jack'
-                            )
-                        )
-
-        The :func:`.or_` conjunction is also available using the
-        Python ``|`` operator (though note that compound expressions
-        need to be parenthesized in order to function with Python
-        operator precedence behavior)::
-
-            stmt = select(users_table).where(
-                            (users_table.c.name == 'wendy') |
-                            (users_table.c.name == 'jack')
-                        )
-
-        The :func:`.or_` construct must be given at least one positional
-        argument in order to be valid; a :func:`.or_` construct with no
-        arguments is ambiguous.   To produce an "empty" or dynamically
-        generated :func:`.or_`  expression, from a given list of expressions,
-        a "default" element of ``False`` should be specified::
-
-            or_criteria = or_(False, *expressions)
-
-        The above expression will compile to SQL as the expression ``false``
-        or ``0 = 1``, depending on backend, if no other expressions are
-        present.  If expressions are present, then the ``False`` value is
-        ignored as it does not affect the outcome of an OR expression which
-        has other elements.
-
-        .. deprecated:: 1.4  The :func:`.or_` element now requires that at
-           least one argument is passed; creating the :func:`.or_` construct
-           with no arguments is deprecated, and will emit a deprecation warning
-           while continuing to produce a blank SQL string.
-
-        .. seealso::
-
-            :func:`.and_`
-
+        See :func:`_sql.or_` for full documentation.
         """
         return cls._construct(
             operators.or_, False_._singleton, True_._singleton, *clauses
@@ -2669,32 +2509,9 @@ class Tuple(ClauseList, ColumnElement):
     _traverse_internals = ClauseList._traverse_internals + []
 
     @util.preload_module("sqlalchemy.sql.sqltypes")
-    def __init__(self, *clauses, **kw):
-        """Return a :class:`.Tuple`.
-
-        Main usage is to produce a composite IN construct using
-        :meth:`.ColumnOperators.in_` ::
-
-            from sqlalchemy import tuple_
-
-            tuple_(table.c.col1, table.c.col2).in_(
-                [(1, 2), (5, 12), (10, 19)]
-            )
-
-        .. versionchanged:: 1.3.6 Added support for SQLite IN tuples.
-
-        .. warning::
-
-            The composite IN construct is not supported by all backends, and is
-            currently known to work on PostgreSQL, MySQL, and SQLite.
-            Unsupported backends will raise a subclass of
-            :class:`~sqlalchemy.exc.DBAPIError` when such an expression is
-            invoked.
-
-        """
+    def __init__(self, *clauses, types=None):
         sqltypes = util.preloaded.sql_sqltypes
 
-        types = kw.pop("types", None)
         if types is None:
             clauses = [
                 coercions.expect(roles.ExpressionElementRole, c)
@@ -2716,7 +2533,7 @@ class Tuple(ClauseList, ColumnElement):
             ]
 
         self.type = sqltypes.TupleType(*[arg.type for arg in clauses])
-        super(Tuple, self).__init__(*clauses, **kw)
+        super(Tuple, self).__init__(*clauses)
 
     @property
     def _select_iterable(self):
@@ -2752,7 +2569,7 @@ class Tuple(ClauseList, ColumnElement):
         return self
 
 
-class Case(ColumnElement):
+class Case(ColumnElement[_T]):
     """Represent a ``CASE`` expression.
 
     :class:`.Case` is produced using the :func:`.case` factory function,
@@ -2785,152 +2602,35 @@ class Case(ColumnElement):
         ("else_", InternalTraversal.dp_clauseelement),
     ]
 
+    # for case(), the type is derived from the whens.  so for the moment
+    # users would have to cast() the case to get a specific type
+
     def __init__(self, *whens, value=None, else_=None):
-        r"""Produce a ``CASE`` expression.
 
-        The ``CASE`` construct in SQL is a conditional object that
-        acts somewhat analogously to an "if/then" construct in other
-        languages.  It returns an instance of :class:`.Case`.
+        whens = coercions._expression_collection_was_a_list(
+            "whens", "case", whens
+        )
+        try:
+            whens = util.dictlike_iteritems(whens)
+        except TypeError:
+            pass
 
-        :func:`.case` in its usual form is passed a series of "when"
-        constructs, that is, a list of conditions and results as tuples::
+        whenlist = [
+            (
+                coercions.expect(
+                    roles.ExpressionElementRole,
+                    c,
+                    apply_propagate_attrs=self,
+                ).self_group(),
+                coercions.expect(roles.ExpressionElementRole, r),
+            )
+            for (c, r) in whens
+        ]
 
-            from sqlalchemy import case
-
-            stmt = select(users_table).\
-                        where(
-                            case(
-                                (users_table.c.name == 'wendy', 'W'),
-                                (users_table.c.name == 'jack', 'J'),
-                                else_='E'
-                            )
-                        )
-
-        The above statement will produce SQL resembling::
-
-            SELECT id, name FROM user
-            WHERE CASE
-                WHEN (name = :name_1) THEN :param_1
-                WHEN (name = :name_2) THEN :param_2
-                ELSE :param_3
-            END
-
-        When simple equality expressions of several values against a single
-        parent column are needed, :func:`.case` also has a "shorthand" format
-        used via the
-        :paramref:`.case.value` parameter, which is passed a column
-        expression to be compared.  In this form, the :paramref:`.case.whens`
-        parameter is passed as a dictionary containing expressions to be
-        compared against keyed to result expressions.  The statement below is
-        equivalent to the preceding statement::
-
-            stmt = select(users_table).\
-                        where(
-                            case(
-                                {"wendy": "W", "jack": "J"},
-                                value=users_table.c.name,
-                                else_='E'
-                            )
-                        )
-
-        The values which are accepted as result values in
-        :paramref:`.case.whens` as well as with :paramref:`.case.else_` are
-        coerced from Python literals into :func:`.bindparam` constructs.
-        SQL expressions, e.g. :class:`_expression.ColumnElement` constructs,
-        are accepted
-        as well.  To coerce a literal string expression into a constant
-        expression rendered inline, use the :func:`_expression.literal_column`
-        construct,
-        as in::
-
-            from sqlalchemy import case, literal_column
-
-            case(
-                (
-                    orderline.c.qty > 100,
-                    literal_column("'greaterthan100'")
-                ),
-                (
-                    orderline.c.qty > 10,
-                    literal_column("'greaterthan10'")
-                ),
-                else_=literal_column("'lessthan10'")
-            )
-
-        The above will render the given constants without using bound
-        parameters for the result values (but still for the comparison
-        values), as in::
-
-            CASE
-                WHEN (orderline.qty > :qty_1) THEN 'greaterthan100'
-                WHEN (orderline.qty > :qty_2) THEN 'greaterthan10'
-                ELSE 'lessthan10'
-            END
-
-        :param \*whens: The criteria to be compared against,
-         :paramref:`.case.whens` accepts two different forms, based on
-         whether or not :paramref:`.case.value` is used.
-
-         .. versionchanged:: 1.4 the :func:`_sql.case`
-            function now accepts the series of WHEN conditions positionally
-
-         In the first form, it accepts a list of 2-tuples; each 2-tuple
-         consists of ``(<sql expression>, <value>)``, where the SQL
-         expression is a boolean expression and "value" is a resulting value,
-         e.g.::
-
-            case(
-                (users_table.c.name == 'wendy', 'W'),
-                (users_table.c.name == 'jack', 'J')
-            )
-
-         In the second form, it accepts a Python dictionary of comparison
-         values mapped to a resulting value; this form requires
-         :paramref:`.case.value` to be present, and values will be compared
-         using the ``==`` operator, e.g.::
-
-            case(
-                {"wendy": "W", "jack": "J"},
-                value=users_table.c.name
-            )
-
-        :param value: An optional SQL expression which will be used as a
-          fixed "comparison point" for candidate values within a dictionary
-          passed to :paramref:`.case.whens`.
-
-        :param else\_: An optional SQL expression which will be the evaluated
-          result of the ``CASE`` construct if all expressions within
-          :paramref:`.case.whens` evaluate to false.  When omitted, most
-          databases will produce a result of NULL if none of the "when"
-          expressions evaluate to true.
-
-
-        """
-
-        whens = coercions._expression_collection_was_a_list(
-            "whens", "case", whens
-        )
-        try:
-            whens = util.dictlike_iteritems(whens)
-        except TypeError:
-            pass
-
-        whenlist = [
-            (
-                coercions.expect(
-                    roles.ExpressionElementRole,
-                    c,
-                    apply_propagate_attrs=self,
-                ).self_group(),
-                coercions.expect(roles.ExpressionElementRole, r),
-            )
-            for (c, r) in whens
-        ]
-
-        if whenlist:
-            type_ = list(whenlist[-1])[-1].type
-        else:
-            type_ = None
+        if whenlist:
+            type_ = list(whenlist[-1])[-1].type
+        else:
+            type_ = None
 
         if value is None:
             self.value = None
@@ -2952,43 +2652,7 @@ class Case(ColumnElement):
         )
 
 
-def literal_column(text, type_=None):
-    r"""Produce a :class:`.ColumnClause` object that has the
-    :paramref:`_expression.column.is_literal` flag set to True.
-
-    :func:`_expression.literal_column` is similar to
-    :func:`_expression.column`, except that
-    it is more often used as a "standalone" column expression that renders
-    exactly as stated; while :func:`_expression.column`
-    stores a string name that
-    will be assumed to be part of a table and may be quoted as such,
-    :func:`_expression.literal_column` can be that,
-    or any other arbitrary column-oriented
-    expression.
-
-    :param text: the text of the expression; can be any SQL expression.
-      Quoting rules will not be applied. To specify a column-name expression
-      which should be subject to quoting rules, use the :func:`column`
-      function.
-
-    :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine`
-      object which will
-      provide result-set translation and additional expression semantics for
-      this column. If left as ``None`` the type will be :class:`.NullType`.
-
-    .. seealso::
-
-        :func:`_expression.column`
-
-        :func:`_expression.text`
-
-        :ref:`sqlexpression_literal_column`
-
-    """
-    return ColumnClause(text, type_=type_, is_literal=True)
-
-
-class Cast(WrapsColumnExpression, ColumnElement):
+class Cast(WrapsColumnExpression, ColumnElement[_T]):
     """Represent a ``CAST`` expression.
 
     :class:`.Cast` is produced using the :func:`.cast` factory function,
@@ -3020,57 +2684,6 @@ class Cast(WrapsColumnExpression, ColumnElement):
     ]
 
     def __init__(self, expression, type_):
-        r"""Produce a ``CAST`` expression.
-
-        :func:`.cast` returns an instance of :class:`.Cast`.
-
-        E.g.::
-
-            from sqlalchemy import cast, Numeric
-
-            stmt = select(cast(product_table.c.unit_price, Numeric(10, 4)))
-
-        The above statement will produce SQL resembling::
-
-            SELECT CAST(unit_price AS NUMERIC(10, 4)) FROM product
-
-        The :func:`.cast` function performs two distinct functions when
-        used.  The first is that it renders the ``CAST`` expression within
-        the resulting SQL string.  The second is that it associates the given
-        type (e.g. :class:`.TypeEngine` class or instance) with the column
-        expression on the Python side, which means the expression will take
-        on the expression operator behavior associated with that type,
-        as well as the bound-value handling and result-row-handling behavior
-        of the type.
-
-        .. versionchanged:: 0.9.0 :func:`.cast` now applies the given type
-           to the expression such that it takes effect on the bound-value,
-           e.g. the Python-to-database direction, in addition to the
-           result handling, e.g. database-to-Python, direction.
-
-        An alternative to :func:`.cast` is the :func:`.type_coerce` function.
-        This function performs the second task of associating an expression
-        with a specific type, but does not render the ``CAST`` expression
-        in SQL.
-
-        :param expression: A SQL expression, such as a
-         :class:`_expression.ColumnElement`
-         expression or a Python string which will be coerced into a bound
-         literal value.
-
-        :param type\_: A :class:`.TypeEngine` class or instance indicating
-         the type to which the ``CAST`` should apply.
-
-        .. seealso::
-
-            :ref:`coretutorial_casts`
-
-            :func:`.type_coerce` - an alternative to CAST that coerces the type
-            on the Python side only, which is often sufficient to generate the
-            correct SQL and data coercion.
-
-
-        """
         self.type = type_api.to_instance(type_)
         self.clause = coercions.expect(
             roles.ExpressionElementRole,
@@ -3089,7 +2702,7 @@ class Cast(WrapsColumnExpression, ColumnElement):
         return self.clause
 
 
-class TypeCoerce(WrapsColumnExpression, ColumnElement):
+class TypeCoerce(WrapsColumnExpression, ColumnElement[_T]):
     """Represent a Python-side type-coercion wrapper.
 
     :class:`.TypeCoerce` supplies the :func:`_expression.type_coerce`
@@ -3115,80 +2728,6 @@ class TypeCoerce(WrapsColumnExpression, ColumnElement):
     ]
 
     def __init__(self, expression, type_):
-        r"""Associate a SQL expression with a particular type, without rendering
-        ``CAST``.
-
-        E.g.::
-
-            from sqlalchemy import type_coerce
-
-            stmt = select(type_coerce(log_table.date_string, StringDateTime()))
-
-        The above construct will produce a :class:`.TypeCoerce` object, which
-        does not modify the rendering in any way on the SQL side, with the
-        possible exception of a generated label if used in a columns clause
-        context::
-
-            SELECT date_string AS date_string FROM log
-
-        When result rows are fetched, the ``StringDateTime`` type processor
-        will be applied to result rows on behalf of the ``date_string`` column.
-
-        .. note:: the :func:`.type_coerce` construct does not render any
-           SQL syntax of its own, including that it does not imply
-           parenthesization.   Please use :meth:`.TypeCoerce.self_group`
-           if explicit parenthesization is required.
-
-        In order to provide a named label for the expression, use
-        :meth:`_expression.ColumnElement.label`::
-
-            stmt = select(
-                type_coerce(log_table.date_string, StringDateTime()).label('date')
-            )
-
-
-        A type that features bound-value handling will also have that behavior
-        take effect when literal values or :func:`.bindparam` constructs are
-        passed to :func:`.type_coerce` as targets.
-        For example, if a type implements the
-        :meth:`.TypeEngine.bind_expression`
-        method or :meth:`.TypeEngine.bind_processor` method or equivalent,
-        these functions will take effect at statement compilation/execution
-        time when a literal value is passed, as in::
-
-            # bound-value handling of MyStringType will be applied to the
-            # literal value "some string"
-            stmt = select(type_coerce("some string", MyStringType))
-
-        When using :func:`.type_coerce` with composed expressions, note that
-        **parenthesis are not applied**.   If :func:`.type_coerce` is being
-        used in an operator context where the parenthesis normally present from
-        CAST are necessary, use the :meth:`.TypeCoerce.self_group` method::
-
-            >>> some_integer = column("someint", Integer)
-            >>> some_string = column("somestr", String)
-            >>> expr = type_coerce(some_integer + 5, String) + some_string
-            >>> print(expr)
-            someint + :someint_1 || somestr
-            >>> expr = type_coerce(some_integer + 5, String).self_group() + some_string
-            >>> print(expr)
-            (someint + :someint_1) || somestr
-
-        :param expression: A SQL expression, such as a
-         :class:`_expression.ColumnElement`
-         expression or a Python string which will be coerced into a bound
-         literal value.
-
-        :param type\_: A :class:`.TypeEngine` class or instance indicating
-         the type to which the expression is coerced.
-
-        .. seealso::
-
-            :ref:`coretutorial_casts`
-
-            :func:`.cast`
-
-        """  # noqa
         self.type = type_api.to_instance(type_)
         self.clause = coercions.expect(
             roles.ExpressionElementRole,
@@ -3222,7 +2761,7 @@ class TypeCoerce(WrapsColumnExpression, ColumnElement):
             return self
 
 
-class Extract(ColumnElement):
+class Extract(ColumnElement[_T]):
     """Represent a SQL EXTRACT clause, ``extract(field FROM expr)``."""
 
     __visit_name__ = "extract"
@@ -3232,44 +2771,7 @@ class Extract(ColumnElement):
         ("field", InternalTraversal.dp_string),
     ]
 
-    def __init__(self, field, expr, **kwargs):
-        """Return a :class:`.Extract` construct.
-
-        This is typically available as :func:`.extract`
-        as well as ``func.extract`` from the
-        :data:`.func` namespace.
-
-        :param field: The field to extract.
-
-        :param expr: A column or Python scalar expression serving as the
-          right side of the ``EXTRACT`` expression.
-
-        E.g.::
-
-            from sqlalchemy import extract
-            from sqlalchemy import table, column
-
-            logged_table = table("user",
-                    column("id"),
-                    column("date_created"),
-            )
-
-            stmt = select(logged_table.c.id).where(
-                extract("YEAR", logged_table.c.date_created) == 2021
-            )
-
-        In the above example, the statement is used to select ids from the
-        database where the ``YEAR`` component matches a specific value.
-
-        Similarly, one can also select an extracted component::
-
-            stmt = select(
-                extract("YEAR", logged_table.c.date_created)
-            ).where(logged_table.c.id == 1)
-
-        The implementation of ``EXTRACT`` may vary across database backends.
-        Users are reminded to consult their database documentation.
-        """
+    def __init__(self, field, expr):
         self.type = type_api.INTEGERTYPE
         self.field = field
         self.expr = coercions.expect(roles.ExpressionElementRole, expr)
@@ -3314,10 +2816,10 @@ class _textual_label_reference(ColumnElement):
 
     @util.memoized_property
     def _text_clause(self):
-        return TextClause._create_text(self.element)
+        return TextClause(self.element)
 
 
-class UnaryExpression(ColumnElement):
+class UnaryExpression(ColumnElement[_T]):
     """Define a 'unary' expression.
 
     A unary expression has a single column expression
@@ -3344,7 +2846,7 @@ class UnaryExpression(ColumnElement):
         element,
         operator=None,
         modifier=None,
-        type_=None,
+        type_: Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"] = None,
         wraps_column_expression=False,
     ):
         self.operator = operator
@@ -3353,51 +2855,11 @@ class UnaryExpression(ColumnElement):
         self.element = element.self_group(
             against=self.operator or self.modifier
         )
-        self.type = type_api.to_instance(type_)
+        self.type: TypeEngine[_T] = type_api.to_instance(type_)
         self.wraps_column_expression = wraps_column_expression
 
     @classmethod
     def _create_nulls_first(cls, column):
-        """Produce the ``NULLS FIRST`` modifier for an ``ORDER BY`` expression.
-
-        :func:`.nulls_first` is intended to modify the expression produced
-        by :func:`.asc` or :func:`.desc`, and indicates how NULL values
-        should be handled when they are encountered during ordering::
-
-
-            from sqlalchemy import desc, nulls_first
-
-            stmt = select(users_table).order_by(
-                nulls_first(desc(users_table.c.name)))
-
-        The SQL expression from the above would resemble::
-
-            SELECT id, name FROM user ORDER BY name DESC NULLS FIRST
-
-        Like :func:`.asc` and :func:`.desc`, :func:`.nulls_first` is typically
-        invoked from the column expression itself using
-        :meth:`_expression.ColumnElement.nulls_first`,
-        rather than as its standalone
-        function version, as in::
-
-            stmt = select(users_table).order_by(
-                users_table.c.name.desc().nulls_first())
-
-        .. versionchanged:: 1.4 :func:`.nulls_first` is renamed from
-            :func:`.nullsfirst` in previous releases.
-            The previous name remains available for backwards compatibility.
-
-        .. seealso::
-
-            :func:`.asc`
-
-            :func:`.desc`
-
-            :func:`.nulls_last`
-
-            :meth:`_expression.Select.order_by`
-
-        """
         return UnaryExpression(
             coercions.expect(roles.ByOfRole, column),
             modifier=operators.nulls_first_op,
@@ -3406,46 +2868,6 @@ class UnaryExpression(ColumnElement):
 
     @classmethod
     def _create_nulls_last(cls, column):
-        """Produce the ``NULLS LAST`` modifier for an ``ORDER BY`` expression.
-
-        :func:`.nulls_last` is intended to modify the expression produced
-        by :func:`.asc` or :func:`.desc`, and indicates how NULL values
-        should be handled when they are encountered during ordering::
-
-
-            from sqlalchemy import desc, nulls_last
-
-            stmt = select(users_table).order_by(
-                nulls_last(desc(users_table.c.name)))
-
-        The SQL expression from the above would resemble::
-
-            SELECT id, name FROM user ORDER BY name DESC NULLS LAST
-
-        Like :func:`.asc` and :func:`.desc`, :func:`.nulls_last` is typically
-        invoked from the column expression itself using
-        :meth:`_expression.ColumnElement.nulls_last`,
-        rather than as its standalone
-        function version, as in::
-
-            stmt = select(users_table).order_by(
-                users_table.c.name.desc().nulls_last())
-
-        .. versionchanged:: 1.4 :func:`.nulls_last` is renamed from
-            :func:`.nullslast` in previous releases.
-            The previous name remains available for backwards compatibility.
-
-        .. seealso::
-
-            :func:`.asc`
-
-            :func:`.desc`
-
-            :func:`.nulls_first`
-
-            :meth:`_expression.Select.order_by`
-
-        """
         return UnaryExpression(
             coercions.expect(roles.ByOfRole, column),
             modifier=operators.nulls_last_op,
@@ -3454,41 +2876,6 @@ class UnaryExpression(ColumnElement):
 
     @classmethod
     def _create_desc(cls, column):
-        """Produce a descending ``ORDER BY`` clause element.
-
-        e.g.::
-
-            from sqlalchemy import desc
-
-            stmt = select(users_table).order_by(desc(users_table.c.name))
-
-        will produce SQL as::
-
-            SELECT id, name FROM user ORDER BY name DESC
-
-        The :func:`.desc` function is a standalone version of the
-        :meth:`_expression.ColumnElement.desc`
-        method available on all SQL expressions,
-        e.g.::
-
-
-            stmt = select(users_table).order_by(users_table.c.name.desc())
-
-        :param column: A :class:`_expression.ColumnElement` (e.g.
-         scalar SQL expression)
-         with which to apply the :func:`.desc` operation.
-
-        .. seealso::
-
-            :func:`.asc`
-
-            :func:`.nulls_first`
-
-            :func:`.nulls_last`
-
-            :meth:`_expression.Select.order_by`
-
-        """
         return UnaryExpression(
             coercions.expect(roles.ByOfRole, column),
             modifier=operators.desc_op,
@@ -3497,40 +2884,6 @@ class UnaryExpression(ColumnElement):
 
     @classmethod
     def _create_asc(cls, column):
-        """Produce an ascending ``ORDER BY`` clause element.
-
-        e.g.::
-
-            from sqlalchemy import asc
-            stmt = select(users_table).order_by(asc(users_table.c.name))
-
-        will produce SQL as::
-
-            SELECT id, name FROM user ORDER BY name ASC
-
-        The :func:`.asc` function is a standalone version of the
-        :meth:`_expression.ColumnElement.asc`
-        method available on all SQL expressions,
-        e.g.::
-
-
-            stmt = select(users_table).order_by(users_table.c.name.asc())
-
-        :param column: A :class:`_expression.ColumnElement` (e.g.
-         scalar SQL expression)
-         with which to apply the :func:`.asc` operation.
-
-        .. seealso::
-
-            :func:`.desc`
-
-            :func:`.nulls_first`
-
-            :func:`.nulls_last`
-
-            :meth:`_expression.Select.order_by`
-
-        """
         return UnaryExpression(
             coercions.expect(roles.ByOfRole, column),
             modifier=operators.asc_op,
@@ -3539,41 +2892,6 @@ class UnaryExpression(ColumnElement):
 
     @classmethod
     def _create_distinct(cls, expr):
-        """Produce an column-expression-level unary ``DISTINCT`` clause.
-
-        This applies the ``DISTINCT`` keyword to an individual column
-        expression, and is typically contained within an aggregate function,
-        as in::
-
-            from sqlalchemy import distinct, func
-            stmt = select(func.count(distinct(users_table.c.name)))
-
-        The above would produce an expression resembling::
-
-            SELECT COUNT(DISTINCT name) FROM user
-
-        The :func:`.distinct` function is also available as a column-level
-        method, e.g. :meth:`_expression.ColumnElement.distinct`, as in::
-
-            stmt = select(func.count(users_table.c.name.distinct()))
-
-        The :func:`.distinct` operator is different from the
-        :meth:`_expression.Select.distinct` method of
-        :class:`_expression.Select`,
-        which produces a ``SELECT`` statement
-        with ``DISTINCT`` applied to the result set as a whole,
-        e.g. a ``SELECT DISTINCT`` expression.  See that method for further
-        information.
-
-        .. seealso::
-
-            :meth:`_expression.ColumnElement.distinct`
-
-            :meth:`_expression.Select.distinct`
-
-            :data:`.func`
-
-        """
         expr = coercions.expect(roles.ExpressionElementRole, expr)
         return UnaryExpression(
             expr,
@@ -3625,57 +2943,6 @@ class CollectionAggregate(UnaryExpression):
 
     @classmethod
     def _create_any(cls, expr):
-        """Produce an ANY expression.
-
-        For dialects such as that of PostgreSQL, this operator applies
-        to usage of the :class:`_types.ARRAY` datatype, for that of
-        MySQL, it may apply to a subquery.  e.g.::
-
-            # renders on PostgreSQL:
-            # '5 = ANY (somearray)'
-            expr = 5 == any_(mytable.c.somearray)
-
-            # renders on MySQL:
-            # '5 = ANY (SELECT value FROM table)'
-            expr = 5 == any_(select(table.c.value))
-
-        Comparison to NULL may work using ``None`` or :func:`_sql.null`::
-
-            None == any_(mytable.c.somearray)
-
-        The any_() / all_() operators also feature a special "operand flipping"
-        behavior such that if any_() / all_() are used on the left side of a
-        comparison using a standalone operator such as ``==``, ``!=``, etc.
-        (not including operator methods such as
-        :meth:`_sql.ColumnOperators.is_`) the rendered expression is flipped::
-
-            # would render '5 = ANY (column)`
-            any_(mytable.c.column) == 5
-
-        Or with ``None``, which note will not perform
-        the usual step of rendering "IS" as is normally the case for NULL::
-
-            # would render 'NULL = ANY(somearray)'
-            any_(mytable.c.somearray) == None
-
-        .. versionchanged:: 1.4.26  repaired the use of any_() / all_()
-           comparing to NULL on the right side to be flipped to the left.
-
-        The column-level :meth:`_sql.ColumnElement.any_` method (not to be
-        confused with :class:`_types.ARRAY` level
-        :meth:`_types.ARRAY.Comparator.any`) is shorthand for
-        ``any_(col)``::
-
-            5 = mytable.c.somearray.any_()
-
-        .. seealso::
-
-            :meth:`_sql.ColumnOperators.any_`
-
-            :func:`_expression.all_`
-
-        """
-
         expr = coercions.expect(roles.ExpressionElementRole, expr)
 
         expr = expr.self_group()
@@ -3688,56 +2955,6 @@ class CollectionAggregate(UnaryExpression):
 
     @classmethod
     def _create_all(cls, expr):
-        """Produce an ALL expression.
-
-        For dialects such as that of PostgreSQL, this operator applies
-        to usage of the :class:`_types.ARRAY` datatype, for that of
-        MySQL, it may apply to a subquery.  e.g.::
-
-            # renders on PostgreSQL:
-            # '5 = ALL (somearray)'
-            expr = 5 == all_(mytable.c.somearray)
-
-            # renders on MySQL:
-            # '5 = ALL (SELECT value FROM table)'
-            expr = 5 == all_(select(table.c.value))
-
-        Comparison to NULL may work using ``None``::
-
-            None == all_(mytable.c.somearray)
-
-        The any_() / all_() operators also feature a special "operand flipping"
-        behavior such that if any_() / all_() are used on the left side of a
-        comparison using a standalone operator such as ``==``, ``!=``, etc.
-        (not including operator methods such as
-        :meth:`_sql.ColumnOperators.is_`) the rendered expression is flipped::
-
-            # would render '5 = ALL (column)`
-            all_(mytable.c.column) == 5
-
-        Or with ``None``, which note will not perform
-        the usual step of rendering "IS" as is normally the case for NULL::
-
-            # would render 'NULL = ALL(somearray)'
-            all_(mytable.c.somearray) == None
-
-        .. versionchanged:: 1.4.26  repaired the use of any_() / all_()
-           comparing to NULL on the right side to be flipped to the left.
-
-        The column-level :meth:`_sql.ColumnElement.all_` method (not to be
-        confused with :class:`_types.ARRAY` level
-        :meth:`_types.ARRAY.Comparator.all`) is shorthand for
-        ``all_(col)``::
-
-            5 == mytable.c.somearray.all_()
-
-        .. seealso::
-
-            :meth:`_sql.ColumnOperators.all_`
-
-            :func:`_expression.any_`
-
-        """
         expr = coercions.expect(roles.ExpressionElementRole, expr)
         expr = expr.self_group()
         return CollectionAggregate(
@@ -3792,7 +3009,7 @@ class AsBoolean(WrapsColumnExpression, UnaryExpression):
             return AsBoolean(self.element, self.negate, self.operator)
 
 
-class BinaryExpression(ColumnElement):
+class BinaryExpression(ColumnElement[_T]):
     """Represent an expression that is ``LEFT <operator> RIGHT``.
 
     A :class:`.BinaryExpression` is generated automatically
@@ -3827,7 +3044,15 @@ class BinaryExpression(ColumnElement):
     """
 
     def __init__(
-        self, left, right, operator, type_=None, negate=None, modifiers=None
+        self,
+        left: ColumnElement,
+        right: Union[ColumnElement, ClauseList],
+        operator,
+        type_: Optional[
+            Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
+        ] = None,
+        negate=None,
+        modifiers=None,
     ):
         # allow compatibility with libraries that
         # refer to BinaryExpression directly and pass strings
@@ -3838,7 +3063,7 @@ class BinaryExpression(ColumnElement):
         self.left = left.self_group(against=operator)
         self.right = right.self_group(against=operator)
         self.operator = operator
-        self.type = type_api.to_instance(type_)
+        self.type: TypeEngine[_T] = type_api.to_instance(type_)
         self.negate = negate
         self._is_implicitly_boolean = operators.is_boolean(operator)
 
@@ -3855,6 +3080,13 @@ class BinaryExpression(ColumnElement):
 
     __nonzero__ = __bool__
 
+    if typing.TYPE_CHECKING:
+
+        def __invert__(
+            self: "BinaryExpression[_T]",
+        ) -> "BinaryExpression[_T]":
+            ...
+
     @property
     def is_comparison(self):
         return operators.is_comparison(self.operator)
@@ -3996,7 +3228,7 @@ RANGE_UNBOUNDED = util.symbol("RANGE_UNBOUNDED")
 RANGE_CURRENT = util.symbol("RANGE_CURRENT")
 
 
-class Over(ColumnElement):
+class Over(ColumnElement[_T]):
     """Represent an OVER clause.
 
     This is a special operator against a so-called
@@ -4026,88 +3258,6 @@ class Over(ColumnElement):
     def __init__(
         self, element, partition_by=None, order_by=None, range_=None, rows=None
     ):
-        r"""Produce an :class:`.Over` object against a function.
-
-        Used against aggregate or so-called "window" functions,
-        for database backends that support window functions.
-
-        :func:`_expression.over` is usually called using
-        the :meth:`.FunctionElement.over` method, e.g.::
-
-            func.row_number().over(order_by=mytable.c.some_column)
-
-        Would produce::
-
-            ROW_NUMBER() OVER(ORDER BY some_column)
-
-        Ranges are also possible using the :paramref:`.expression.over.range_`
-        and :paramref:`.expression.over.rows` parameters.  These
-        mutually-exclusive parameters each accept a 2-tuple, which contains
-        a combination of integers and None::
-
-            func.row_number().over(
-                order_by=my_table.c.some_column, range_=(None, 0))
-
-        The above would produce::
-
-            ROW_NUMBER() OVER(ORDER BY some_column
-            RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
-
-        A value of ``None`` indicates "unbounded", a
-        value of zero indicates "current row", and negative / positive
-        integers indicate "preceding" and "following":
-
-        * RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING::
-
-            func.row_number().over(order_by='x', range_=(-5, 10))
-
-        * ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW::
-
-            func.row_number().over(order_by='x', rows=(None, 0))
-
-        * RANGE BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING::
-
-            func.row_number().over(order_by='x', range_=(-2, None))
-
-        * RANGE BETWEEN 1 FOLLOWING AND 3 FOLLOWING::
-
-            func.row_number().over(order_by='x', range_=(1, 3))
-
-        .. versionadded:: 1.1 support for RANGE / ROWS within a window
-
-
-        :param element: a :class:`.FunctionElement`, :class:`.WithinGroup`,
-         or other compatible construct.
-        :param partition_by: a column element or string, or a list
-         of such, that will be used as the PARTITION BY clause
-         of the OVER construct.
-        :param order_by: a column element or string, or a list
-         of such, that will be used as the ORDER BY clause
-         of the OVER construct.
-        :param range\_: optional range clause for the window.  This is a
-         tuple value which can contain integer values or ``None``,
-         and will render a RANGE BETWEEN PRECEDING / FOLLOWING clause.
-
-         .. versionadded:: 1.1
-
-        :param rows: optional rows clause for the window.  This is a tuple
-         value which can contain integer values or None, and will render
-         a ROWS BETWEEN PRECEDING / FOLLOWING clause.
-
-         .. versionadded:: 1.1
-
-        This function is also available from the :data:`~.expression.func`
-        construct itself via the :meth:`.FunctionElement.over` method.
-
-        .. seealso::
-
-            :ref:`tutorial_window_functions` - in the :ref:`unified_tutorial`
-
-            :data:`.expression.func`
-
-            :func:`_expression.within_group`
-
-        """
         self.element = element
         if order_by is not None:
             self.order_by = ClauseList(
@@ -4191,7 +3341,7 @@ class Over(ColumnElement):
         )
 
 
-class WithinGroup(ColumnElement):
+class WithinGroup(ColumnElement[_T]):
     """Represent a WITHIN GROUP (ORDER BY) clause.
 
     This is a special operator against so-called
@@ -4218,44 +3368,6 @@ class WithinGroup(ColumnElement):
     order_by = None
 
     def __init__(self, element, *order_by):
-        r"""Produce a :class:`.WithinGroup` object against a function.
-
-        Used against so-called "ordered set aggregate" and "hypothetical
-        set aggregate" functions, including :class:`.percentile_cont`,
-        :class:`.rank`, :class:`.dense_rank`, etc.
-
-        :func:`_expression.within_group` is usually called using
-        the :meth:`.FunctionElement.within_group` method, e.g.::
-
-            from sqlalchemy import within_group
-            stmt = select(
-                department.c.id,
-                func.percentile_cont(0.5).within_group(
-                    department.c.salary.desc()
-                )
-            )
-
-        The above statement would produce SQL similar to
-        ``SELECT department.id, percentile_cont(0.5)
-        WITHIN GROUP (ORDER BY department.salary DESC)``.
-
-        :param element: a :class:`.FunctionElement` construct, typically
-         generated by :data:`~.expression.func`.
-        :param \*order_by: one or more column elements that will be used
-         as the ORDER BY clause of the WITHIN GROUP construct.
-
-        .. versionadded:: 1.1
-
-        .. seealso::
-
-            :ref:`tutorial_functions_within_group` - in the
-            :ref:`unified_tutorial`
-
-            :data:`.expression.func`
-
-            :func:`_expression.over`
-
-        """
         self.element = element
         if order_by is not None:
             self.order_by = ClauseList(
@@ -4332,31 +3444,6 @@ class FunctionFilter(ColumnElement):
     criterion = None
 
     def __init__(self, func, *criterion):
-        """Produce a :class:`.FunctionFilter` object against a function.
-
-        Used against aggregate and window functions,
-        for database backends that support the "FILTER" clause.
-
-        E.g.::
-
-            from sqlalchemy import funcfilter
-            funcfilter(func.count(1), MyClass.name == 'some name')
-
-        Would produce "COUNT(1) FILTER (WHERE myclass.name = 'some name')".
-
-        This function is also available from the :data:`~.expression.func`
-        construct itself via the :meth:`.FunctionElement.filter` method.
-
-        .. versionadded:: 1.0.0
-
-        .. seealso::
-
-            :ref:`tutorial_functions_within_group` - in the
-            :ref:`unified_tutorial`
-
-            :meth:`.FunctionElement.filter`
-
-        """
         self.func = func
         self.filter(*criterion)
 
@@ -4431,7 +3518,7 @@ class FunctionFilter(ColumnElement):
         )
 
 
-class Label(roles.LabeledColumnExprRole, ColumnElement):
+class Label(roles.LabeledColumnExprRole, ColumnElement[_T]):
     """Represents a column label (AS).
 
     Represent a label, as typically applied to any column-level
@@ -4448,22 +3535,6 @@ class Label(roles.LabeledColumnExprRole, ColumnElement):
     ]
 
     def __init__(self, name, element, type_=None):
-        """Return a :class:`Label` object for the
-        given :class:`_expression.ColumnElement`.
-
-        A label changes the name of an element in the columns clause of a
-        ``SELECT`` statement, typically via the ``AS`` SQL keyword.
-
-        This functionality is more conveniently available via the
-        :meth:`_expression.ColumnElement.label` method on
-        :class:`_expression.ColumnElement`.
-
-        :param name: label name
-
-        :param obj: a :class:`_expression.ColumnElement`.
-
-        """
-
         orig_element = element
         element = coercions.expect(
             roles.ExpressionElementRole,
@@ -4583,7 +3654,7 @@ class Label(roles.LabeledColumnExprRole, ColumnElement):
         return self.key, e
 
 
-class NamedColumn(ColumnElement):
+class NamedColumn(ColumnElement[_T]):
     is_literal = False
     table = None
 
@@ -4673,7 +3744,7 @@ class ColumnClause(
     roles.LabeledColumnExprRole,
     roles.StrAsPlainColumnRole,
     Immutable,
-    NamedColumn,
+    NamedColumn[_T],
 ):
     """Represents a column expression from any textual string.
 
@@ -4728,101 +3799,18 @@ class ColumnClause(
 
     _is_multiparam_column = False
 
-    def __init__(self, text, type_=None, is_literal=False, _selectable=None):
-        """Produce a :class:`.ColumnClause` object.
-
-        The :class:`.ColumnClause` is a lightweight analogue to the
-        :class:`_schema.Column` class.  The :func:`_expression.column`
-        function can
-        be invoked with just a name alone, as in::
-
-            from sqlalchemy import column
-
-            id, name = column("id"), column("name")
-            stmt = select(id, name).select_from("user")
-
-        The above statement would produce SQL like::
-
-            SELECT id, name FROM user
-
-        Once constructed, :func:`_expression.column`
-        may be used like any other SQL
-        expression element such as within :func:`_expression.select`
-        constructs::
-
-            from sqlalchemy.sql import column
-
-            id, name = column("id"), column("name")
-            stmt = select(id, name).select_from("user")
-
-        The text handled by :func:`_expression.column`
-        is assumed to be handled
-        like the name of a database column; if the string contains mixed case,
-        special characters, or matches a known reserved word on the target
-        backend, the column expression will render using the quoting
-        behavior determined by the backend.  To produce a textual SQL
-        expression that is rendered exactly without any quoting,
-        use :func:`_expression.literal_column` instead,
-        or pass ``True`` as the
-        value of :paramref:`_expression.column.is_literal`.   Additionally,
-        full SQL
-        statements are best handled using the :func:`_expression.text`
-        construct.
-
-        :func:`_expression.column` can be used in a table-like
-        fashion by combining it with the :func:`.table` function
-        (which is the lightweight analogue to :class:`_schema.Table`
-        ) to produce
-        a working table construct with minimal boilerplate::
-
-            from sqlalchemy import table, column, select
-
-            user = table("user",
-                    column("id"),
-                    column("name"),
-                    column("description"),
-            )
-
-            stmt = select(user.c.description).where(user.c.name == 'wendy')
-
-        A :func:`_expression.column` / :func:`.table`
-        construct like that illustrated
-        above can be created in an
-        ad-hoc fashion and is not associated with any
-        :class:`_schema.MetaData`, DDL, or events, unlike its
-        :class:`_schema.Table` counterpart.
-
-        .. versionchanged:: 1.0.0 :func:`_expression.column` can now
-           be imported from the plain ``sqlalchemy`` namespace like any
-           other SQL element.
-
-        :param text: the text of the element.
-
-        :param type: :class:`_types.TypeEngine` object which can associate
-          this :class:`.ColumnClause` with a type.
-
-        :param is_literal: if True, the :class:`.ColumnClause` is assumed to
-          be an exact expression that will be delivered to the output with no
-          quoting rules applied regardless of case sensitive settings. the
-          :func:`_expression.literal_column()` function essentially invokes
-          :func:`_expression.column` while passing ``is_literal=True``.
-
-        .. seealso::
-
-            :class:`_schema.Column`
-
-            :func:`_expression.literal_column`
-
-            :func:`.table`
-
-            :func:`_expression.text`
-
-            :ref:`sqlexpression_literal_column`
-
-        """
+    def __init__(
+        self,
+        text: str,
+        type_: Optional[
+            Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
+        ] = None,
+        is_literal: bool = False,
+        _selectable: Optional["FromClause"] = None,
+    ):
         self.key = self.name = text
         self.table = _selectable
-        self.type = type_api.to_instance(type_)
+        self.type: TypeEngine[_T] = type_api.to_instance(type_)
         self.is_literal = is_literal
 
     def get_children(self, column_tables=False, **kw):
@@ -5010,6 +3998,16 @@ class CollationClause(ColumnElement):
 
     _traverse_internals = [("collation", InternalTraversal.dp_string)]
 
+    @classmethod
+    def _create_collation_expression(cls, expression, collation):
+        expr = coercions.expect(roles.ExpressionElementRole, expression)
+        return BinaryExpression(
+            expr,
+            CollationClause(collation),
+            operators.collate,
+            type_=expression.type,
+        )
+
     def __init__(self, collation):
         self.collation = collation
 
@@ -5280,7 +4278,7 @@ class _anonymous_label(_truncated_label):
     @classmethod
     def safe_construct(
         cls, seed, body, enclosing_label=None, sanitize_key=False
-    ):
+    ) -> "_anonymous_label":
 
         if sanitize_key:
             body = re.sub(r"[%\(\) \$]+", "_", body).strip("_")
index 54f67b930dedfe87d13abd40aa8a5082ad4dcf58..680eae754d68c3c8876c5502404bde6985865818 100644 (file)
 
 """
 
-__all__ = [
-    "Alias",
-    "AliasedReturnsRows",
-    "any_",
-    "all_",
-    "CacheKey",
-    "ClauseElement",
-    "ColumnCollection",
-    "ColumnElement",
-    "CompoundSelect",
-    "Delete",
-    "FromClause",
-    "Insert",
-    "Join",
-    "Lateral",
-    "LambdaElement",
-    "StatementLambdaElement",
-    "Select",
-    "Selectable",
-    "TableClause",
-    "TableValuedAlias",
-    "Update",
-    "Values",
-    "alias",
-    "and_",
-    "asc",
-    "between",
-    "bindparam",
-    "case",
-    "cast",
-    "column",
-    "custom_op",
-    "cte",
-    "delete",
-    "desc",
-    "distinct",
-    "except_",
-    "except_all",
-    "exists",
-    "extract",
-    "func",
-    "modifier",
-    "collate",
-    "insert",
-    "intersect",
-    "intersect_all",
-    "join",
-    "label",
-    "lateral",
-    "lambda_stmt",
-    "literal",
-    "literal_column",
-    "not_",
-    "null",
-    "nulls_first",
-    "nulls_last",
-    "or_",
-    "outparam",
-    "outerjoin",
-    "over",
-    "select",
-    "table",
-    "text",
-    "tuple_",
-    "type_coerce",
-    "quoted_name",
-    "union",
-    "union_all",
-    "update",
-    "quoted_name",
-    "within_group",
-    "Subquery",
-    "TableSample",
-    "tablesample",
-    "values",
-]
 
+from ._dml_constructors import delete as delete
+from ._dml_constructors import insert as insert
+from ._dml_constructors import update as update
+from ._elements_constructors import all_ as all_
+from ._elements_constructors import and_ as and_
+from ._elements_constructors import any_ as any_
+from ._elements_constructors import asc as asc
+from ._elements_constructors import between as between
+from ._elements_constructors import bindparam as bindparam
+from ._elements_constructors import case as case
+from ._elements_constructors import cast as cast
+from ._elements_constructors import collate as collate
+from ._elements_constructors import column as column
+from ._elements_constructors import desc as desc
+from ._elements_constructors import distinct as distinct
+from ._elements_constructors import extract as extract
+from ._elements_constructors import false as false
+from ._elements_constructors import funcfilter as funcfilter
+from ._elements_constructors import label as label
+from ._elements_constructors import not_ as not_
+from ._elements_constructors import null as null
+from ._elements_constructors import nulls_first as nulls_first
+from ._elements_constructors import nulls_last as nulls_last
+from ._elements_constructors import or_ as or_
+from ._elements_constructors import outparam as outparam
+from ._elements_constructors import over as over
+from ._elements_constructors import text as text
+from ._elements_constructors import true as true
+from ._elements_constructors import tuple_ as tuple_
+from ._elements_constructors import type_coerce as type_coerce
+from ._elements_constructors import typing as typing
+from ._elements_constructors import within_group as within_group
+from ._selectable_constructors import alias as alias
+from ._selectable_constructors import cte as cte
+from ._selectable_constructors import except_ as except_
+from ._selectable_constructors import except_all as except_all
+from ._selectable_constructors import exists as exists
+from ._selectable_constructors import intersect as intersect
+from ._selectable_constructors import intersect_all as intersect_all
+from ._selectable_constructors import join as join
+from ._selectable_constructors import lateral as lateral
+from ._selectable_constructors import outerjoin as outerjoin
+from ._selectable_constructors import select as select
+from ._selectable_constructors import table as table
+from ._selectable_constructors import tablesample as tablesample
+from ._selectable_constructors import union as union
+from ._selectable_constructors import union_all as union_all
+from ._selectable_constructors import values as values
+from .base import _from_objects as _from_objects
+from .base import _select_iterables as _select_iterables
+from .base import ColumnCollection as ColumnCollection
+from .base import Executable as Executable
+from .cache_key import CacheKey as CacheKey
+from .dml import Delete as Delete
+from .dml import Insert as Insert
+from .dml import Update as Update
+from .dml import UpdateBase as UpdateBase
+from .dml import ValuesBase as ValuesBase
+from .elements import _truncated_label as _truncated_label
+from .elements import BinaryExpression as BinaryExpression
+from .elements import BindParameter as BindParameter
+from .elements import BooleanClauseList as BooleanClauseList
+from .elements import Case as Case
+from .elements import Cast as Cast
+from .elements import ClauseElement as ClauseElement
+from .elements import ClauseList as ClauseList
+from .elements import CollectionAggregate as CollectionAggregate
+from .elements import ColumnClause as ColumnClause
+from .elements import ColumnElement as ColumnElement
+from .elements import Extract as Extract
+from .elements import False_ as False_
+from .elements import FunctionFilter as FunctionFilter
+from .elements import Grouping as Grouping
+from .elements import Label as Label
+from .elements import literal as literal
+from .elements import literal_column as literal_column
+from .elements import Null as Null
+from .elements import Over as Over
+from .elements import quoted_name as quoted_name
+from .elements import ReleaseSavepointClause as ReleaseSavepointClause
+from .elements import RollbackToSavepointClause as RollbackToSavepointClause
+from .elements import SavepointClause as SavepointClause
+from .elements import TextClause as TextClause
+from .elements import True_ as True_
+from .elements import Tuple as Tuple
+from .elements import TypeClause as TypeClause
+from .elements import TypeCoerce as TypeCoerce
+from .elements import UnaryExpression as UnaryExpression
+from .elements import WithinGroup as WithinGroup
+from .functions import func as func
+from .functions import Function as Function
+from .functions import FunctionElement as FunctionElement
+from .functions import modifier as modifier
+from .lambdas import lambda_stmt as lambda_stmt
+from .lambdas import LambdaElement as LambdaElement
+from .lambdas import StatementLambdaElement as StatementLambdaElement
+from .operators import ColumnOperators as ColumnOperators
+from .operators import custom_op as custom_op
+from .operators import Operators as Operators
+from .selectable import Alias as Alias
+from .selectable import AliasedReturnsRows as AliasedReturnsRows
+from .selectable import CompoundSelect as CompoundSelect
+from .selectable import CTE as CTE
+from .selectable import Exists as Exists
+from .selectable import FromClause as FromClause
+from .selectable import FromGrouping as FromGrouping
+from .selectable import GenerativeSelect as GenerativeSelect
+from .selectable import HasCTE as HasCTE
+from .selectable import HasPrefixes as HasPrefixes
+from .selectable import HasSuffixes as HasSuffixes
+from .selectable import Join as Join
+from .selectable import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
+from .selectable import LABEL_STYLE_NONE as LABEL_STYLE_NONE
+from .selectable import Lateral as Lateral
+from .selectable import ReturnsRows as ReturnsRows
+from .selectable import ScalarSelect as ScalarSelect
+from .selectable import Select as Select
+from .selectable import Selectable as Selectable
+from .selectable import SelectBase as SelectBase
+from .selectable import Subquery as Subquery
+from .selectable import TableClause as TableClause
+from .selectable import TableSample as TableSample
+from .selectable import TableValuedAlias as TableValuedAlias
+from .selectable import TextAsFrom as TextAsFrom
+from .selectable import TextualSelect as TextualSelect
+from .selectable import Values as Values
+from .visitors import Visitable as Visitable
 
-from typing import Callable
+if True:
+    # work around zimports
+    from .selectable import (
+        LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
+    )
+    from .selectable import (
+        LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
+    )
 
-from .base import _from_objects
-from .base import _select_iterables
-from .base import ColumnCollection
-from .base import Executable
-from .cache_key import CacheKey
-from .dml import Delete
-from .dml import Insert
-from .dml import Update
-from .dml import UpdateBase
-from .dml import ValuesBase
-from .elements import _truncated_label
-from .elements import between
-from .elements import BinaryExpression
-from .elements import BindParameter
-from .elements import BooleanClauseList
-from .elements import Case
-from .elements import Cast
-from .elements import ClauseElement
-from .elements import ClauseList
-from .elements import collate
-from .elements import CollectionAggregate
-from .elements import ColumnClause
-from .elements import ColumnElement
-from .elements import Extract
-from .elements import False_
-from .elements import FunctionFilter
-from .elements import Grouping
-from .elements import Label
-from .elements import literal
-from .elements import literal_column
-from .elements import not_
-from .elements import Null
-from .elements import outparam
-from .elements import Over
-from .elements import quoted_name
-from .elements import ReleaseSavepointClause
-from .elements import RollbackToSavepointClause
-from .elements import SavepointClause
-from .elements import TextClause
-from .elements import True_
-from .elements import Tuple
-from .elements import TypeClause
-from .elements import TypeCoerce
-from .elements import UnaryExpression
-from .elements import WithinGroup
-from .functions import func
-from .functions import Function
-from .functions import FunctionElement
-from .functions import modifier
-from .lambdas import lambda_stmt
-from .lambdas import LambdaElement
-from .lambdas import StatementLambdaElement
-from .operators import ColumnOperators
-from .operators import custom_op
-from .operators import Operators
-from .selectable import Alias
-from .selectable import AliasedReturnsRows
-from .selectable import CompoundSelect
-from .selectable import CTE
-from .selectable import Exists
-from .selectable import FromClause
-from .selectable import FromGrouping
-from .selectable import GenerativeSelect
-from .selectable import HasCTE
-from .selectable import HasPrefixes
-from .selectable import HasSuffixes
-from .selectable import Join
-from .selectable import LABEL_STYLE_DEFAULT
-from .selectable import LABEL_STYLE_DISAMBIGUATE_ONLY
-from .selectable import LABEL_STYLE_NONE
-from .selectable import LABEL_STYLE_TABLENAME_PLUS_COL
-from .selectable import Lateral
-from .selectable import ReturnsRows
-from .selectable import ScalarSelect
-from .selectable import Select
-from .selectable import Selectable
-from .selectable import SelectBase
-from .selectable import Subquery
-from .selectable import TableClause
-from .selectable import TableSample
-from .selectable import TableValuedAlias
-from .selectable import TextAsFrom
-from .selectable import TextualSelect
-from .selectable import Values
-from .visitors import Visitable
-from ..util.langhelpers import public_factory
-
-# TODO: proposal is to remove public_factory and replace with traditional
-# functions exported here.
-
-all_ = public_factory(CollectionAggregate._create_all, ".sql.expression.all_")
-any_ = public_factory(CollectionAggregate._create_any, ".sql.expression.any_")
-and_ = public_factory(BooleanClauseList.and_, ".sql.expression.and_")
-alias = public_factory(Alias._factory, ".sql.expression.alias")
-tablesample = public_factory(
-    TableSample._factory, ".sql.expression.tablesample"
-)
-lateral = public_factory(Lateral._factory, ".sql.expression.lateral")
-or_ = public_factory(BooleanClauseList.or_, ".sql.expression.or_")
-bindparam = public_factory(BindParameter, ".sql.expression.bindparam")
-select = public_factory(Select._create, ".sql.expression.select")
-text = public_factory(TextClause._create_text, ".sql.expression.text")
-table = public_factory(TableClause, ".sql.expression.table")
-column = public_factory(ColumnClause, ".sql.expression.column")
-over = public_factory(Over, ".sql.expression.over")
-within_group = public_factory(WithinGroup, ".sql.expression.within_group")
-label = public_factory(Label, ".sql.expression.label")
-case = public_factory(Case, ".sql.expression.case")
-cast = public_factory(Cast, ".sql.expression.cast")
-cte = public_factory(CTE._factory, ".sql.expression.cte")
-values = public_factory(Values, ".sql.expression.values")
-extract = public_factory(Extract, ".sql.expression.extract")
-tuple_ = public_factory(Tuple, ".sql.expression.tuple_")
-except_ = public_factory(
-    CompoundSelect._create_except, ".sql.expression.except_"
-)
-except_all = public_factory(
-    CompoundSelect._create_except_all, ".sql.expression.except_all"
-)
-intersect = public_factory(
-    CompoundSelect._create_intersect, ".sql.expression.intersect"
-)
-intersect_all = public_factory(
-    CompoundSelect._create_intersect_all, ".sql.expression.intersect_all"
-)
-union = public_factory(CompoundSelect._create_union, ".sql.expression.union")
-union_all = public_factory(
-    CompoundSelect._create_union_all, ".sql.expression.union_all"
-)
-exists = public_factory(Exists, ".sql.expression.exists")
-nulls_first = public_factory(
-    UnaryExpression._create_nulls_first, ".sql.expression.nulls_first"
-)
-nullsfirst = nulls_first  # deprecated 1.4; see #5435
-nulls_last = public_factory(
-    UnaryExpression._create_nulls_last, ".sql.expression.nulls_last"
-)
-nullslast = nulls_last  # deprecated 1.4; see #5435
-asc = public_factory(UnaryExpression._create_asc, ".sql.expression.asc")
-desc = public_factory(UnaryExpression._create_desc, ".sql.expression.desc")
-distinct = public_factory(
-    UnaryExpression._create_distinct, ".sql.expression.distinct"
-)
-type_coerce = public_factory(TypeCoerce, ".sql.expression.type_coerce")
-true = public_factory(True_._instance, ".sql.expression.true")
-false = public_factory(False_._instance, ".sql.expression.false")
-null = public_factory(Null._instance, ".sql.expression.null")
-join = public_factory(Join._create_join, ".sql.expression.join")
-outerjoin = public_factory(Join._create_outerjoin, ".sql.expression.outerjoin")
-insert = public_factory(Insert, ".sql.expression.insert")
-update = public_factory(Update, ".sql.expression.update")
-delete = public_factory(Delete, ".sql.expression.delete")
-funcfilter = public_factory(FunctionFilter, ".sql.expression.funcfilter")
-
-
-# internal functions still being called from tests and the ORM,
-# these might be better off in some other namespace
-
-
-# old names for compatibility
-_Executable = Executable
-_BindParamClause = BindParameter
-_Label = Label
-_SelectBase = SelectBase
-_BinaryExpression = BinaryExpression
-_Cast = Cast
-_Null = Null
-_False = False_
-_True = True_
-_TextClause = TextClause
-_UnaryExpression = UnaryExpression
-_Case = Case
-_Tuple = Tuple
-_Over = Over
-_TypeClause = TypeClause
-_Extract = Extract
-_Exists = Exists
-_Grouping = Grouping
-_FromGrouping = FromGrouping
-_ScalarSelect = ScalarSelect
+nullsfirst = nulls_first
+nullslast = nulls_last
index 3b6da71757f997bb975dad9e174b5e739a64478a..7a1e80889d1858e7919fda374810330995ac53ee 100644 (file)
@@ -567,7 +567,7 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative):
             s = select(function_element)
 
         """
-        s = Select._create(self)
+        s = Select(self)
         if self._execution_options:
             s = s.execution_options(**self._execution_options)
         return s
index d7a5d93482584592f754d0b2682ed3d72f071cc3..cf61f263768730cab833650f27859c30cc14b12d 100644 (file)
 
 """Defines operators used in SQL expressions."""
 
-from operator import add
-from operator import and_
-from operator import contains
-from operator import eq
-from operator import floordiv
-from operator import ge
-from operator import getitem
-from operator import gt
-from operator import inv
-from operator import le
-from operator import lshift
-from operator import lt
-from operator import mod
-from operator import mul
-from operator import ne
-from operator import neg
-from operator import or_
-from operator import rshift
-from operator import sub
-from operator import truediv
+from operator import add as _uncast_add
+from operator import and_ as _uncast_and_
+from operator import contains as _uncast_contains
+from operator import eq as _uncast_eq
+from operator import floordiv as _uncast_floordiv
+from operator import ge as _uncast_ge
+from operator import getitem as _uncast_getitem
+from operator import gt as _uncast_gt
+from operator import inv as _uncast_inv
+from operator import le as _uncast_le
+from operator import lshift as _uncast_lshift
+from operator import lt as _uncast_lt
+from operator import mod as _uncast_mod
+from operator import mul as _uncast_mul
+from operator import ne as _uncast_ne
+from operator import neg as _uncast_neg
+from operator import or_ as _uncast_or_
+from operator import rshift as _uncast_rshift
+from operator import sub as _uncast_sub
+from operator import truediv as _uncast_truediv
+import typing
+from typing import Any
+from typing import Callable
+from typing import cast
+from typing import Generic
+from typing import Optional
+from typing import overload
+from typing import Type
+from typing import TypeVar
+from typing import Union
 
 from .. import exc
 from .. import util
-
-
-class Operators:
+from ..util.typing import Protocol
+
+if typing.TYPE_CHECKING:
+    from .elements import BinaryExpression
+    from .elements import ColumnElement
+    from .type_api import TypeEngine
+
+_OP_RETURN = TypeVar("_OP_RETURN", bound=Any, covariant=True)
+_T = TypeVar("_T", bound=Any)
+
+
+class OperatorType(Protocol):
+    """describe an op() function."""
+
+    __name__: str
+
+    def __call__(
+        self, left: "Operators[_OP_RETURN]", *other: Any, **kwargs: Any
+    ) -> "_OP_RETURN":
+        ...
+
+
+add = cast(OperatorType, _uncast_add)
+and_ = cast(OperatorType, _uncast_and_)
+contains = cast(OperatorType, _uncast_contains)
+eq = cast(OperatorType, _uncast_eq)
+floordiv = cast(OperatorType, _uncast_floordiv)
+ge = cast(OperatorType, _uncast_ge)
+getitem = cast(OperatorType, _uncast_getitem)
+gt = cast(OperatorType, _uncast_gt)
+inv = cast(OperatorType, _uncast_inv)
+le = cast(OperatorType, _uncast_le)
+lshift = cast(OperatorType, _uncast_lshift)
+lt = cast(OperatorType, _uncast_lt)
+mod = cast(OperatorType, _uncast_mod)
+mul = cast(OperatorType, _uncast_mul)
+ne = cast(OperatorType, _uncast_ne)
+neg = cast(OperatorType, _uncast_neg)
+or_ = cast(OperatorType, _uncast_or_)
+rshift = cast(OperatorType, _uncast_rshift)
+sub = cast(OperatorType, _uncast_sub)
+truediv = cast(OperatorType, _uncast_truediv)
+
+
+class Operators(Generic[_OP_RETURN]):
     """Base of comparison and logical operators.
 
     Implements base methods
@@ -52,7 +104,7 @@ class Operators:
 
     __slots__ = ()
 
-    def __and__(self, other):
+    def __and__(self, other: Any) -> "Operators":
         """Implement the ``&`` operator.
 
         When used with SQL expressions, results in an
@@ -76,7 +128,7 @@ class Operators:
         """
         return self.operate(and_, other)
 
-    def __or__(self, other):
+    def __or__(self, other: Any) -> "Operators":
         """Implement the ``|`` operator.
 
         When used with SQL expressions, results in an
@@ -100,7 +152,7 @@ class Operators:
         """
         return self.operate(or_, other)
 
-    def __invert__(self):
+    def __invert__(self) -> "Operators":
         """Implement the ``~`` operator.
 
         When used with SQL expressions, results in a
@@ -119,12 +171,14 @@ class Operators:
 
     def op(
         self,
-        opstring,
-        precedence=0,
-        is_comparison=False,
-        return_type=None,
+        opstring: Any,
+        precedence: int = 0,
+        is_comparison: bool = False,
+        return_type: Optional[
+            Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
+        ] = None,
         python_impl=None,
-    ):
+    ) -> Callable[[Any], _OP_RETURN]:
         """Produce a generic operator function.
 
         e.g.::
@@ -205,12 +259,14 @@ class Operators:
             python_impl=python_impl,
         )
 
-        def against(other):
+        def against(other: Any) -> _OP_RETURN:
             return operator(self, other)
 
         return against
 
-    def bool_op(self, opstring, precedence=0, python_impl=None):
+    def bool_op(
+        self, opstring: Any, precedence: int = 0, python_impl=None
+    ) -> Callable[[Any], _OP_RETURN]:
         """Return a custom boolean operator.
 
         This method is shorthand for calling
@@ -230,7 +286,9 @@ class Operators:
             python_impl=python_impl,
         )
 
-    def operate(self, op, *other, **kwargs):
+    def operate(
+        self, op: OperatorType, *other: Any, **kwargs: Any
+    ) -> _OP_RETURN:
         r"""Operate on an argument.
 
         This is the lowest level of operation, raises
@@ -258,7 +316,9 @@ class Operators:
 
     __sa_operate__ = operate
 
-    def reverse_operate(self, op, other, **kwargs):
+    def reverse_operate(
+        self, op: OperatorType, other: Any, **kwargs: Any
+    ) -> _OP_RETURN:
         """Reverse operate on an argument.
 
         Usage is the same as :meth:`operate`.
@@ -267,7 +327,7 @@ class Operators:
         raise NotImplementedError(str(op))
 
 
-class custom_op:
+class custom_op(OperatorType, Generic[_T]):
     """Represent a 'custom' operator.
 
     :class:`.custom_op` is normally instantiated when the
@@ -307,12 +367,14 @@ class custom_op:
 
     def __init__(
         self,
-        opstring,
-        precedence=0,
-        is_comparison=False,
-        return_type=None,
-        natural_self_precedent=False,
-        eager_grouping=False,
+        opstring: str,
+        precedence: int = 0,
+        is_comparison: bool = False,
+        return_type: Optional[
+            Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
+        ] = None,
+        natural_self_precedent: bool = False,
+        eager_grouping: bool = False,
         python_impl=None,
     ):
         self.opstring = opstring
@@ -325,13 +387,27 @@ class custom_op:
         )
         self.python_impl = python_impl
 
-    def __eq__(self, other):
+    def __eq__(self, other: Any) -> bool:
         return isinstance(other, custom_op) and other.opstring == self.opstring
 
-    def __hash__(self):
+    def __hash__(self) -> int:
         return id(self)
 
-    def __call__(self, left, right, **kw):
+    @overload
+    def __call__(
+        self, left: "ColumnElement", right: Any, **kw
+    ) -> "BinaryExpression[_T]":
+        ...
+
+    @overload
+    def __call__(
+        self, left: "Operators[_OP_RETURN]", right: Any, **kw
+    ) -> _OP_RETURN:
+        ...
+
+    def __call__(
+        self, left: "Operators[_OP_RETURN]", right: Any, **kw
+    ) -> _OP_RETURN:
         if hasattr(left, "__sa_operate__"):
             return left.operate(self, right, **kw)
         elif self.python_impl:
@@ -344,7 +420,7 @@ class custom_op:
             )
 
 
-class ColumnOperators(Operators):
+class ColumnOperators(Operators[_OP_RETURN]):
     """Defines boolean, comparison, and other operators for
     :class:`_expression.ColumnElement` expressions.
 
@@ -387,7 +463,19 @@ class ColumnOperators(Operators):
     timetuple = None
     """Hack, allows datetime objects to be compared on the LHS."""
 
-    def __lt__(self, other):
+    if typing.TYPE_CHECKING:
+
+        def operate(
+            self, op: OperatorType, *other: Any, **kwargs: Any
+        ) -> "ColumnOperators":
+            ...
+
+        def reverse_operate(
+            self, op: OperatorType, other: Any, **kwargs: Any
+        ) -> "ColumnOperators":
+            ...
+
+    def __lt__(self, other: Any) -> "ColumnOperators":
         """Implement the ``<`` operator.
 
         In a column context, produces the clause ``a < b``.
@@ -395,7 +483,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(lt, other)
 
-    def __le__(self, other):
+    def __le__(self, other: Any) -> "ColumnOperators":
         """Implement the ``<=`` operator.
 
         In a column context, produces the clause ``a <= b``.
@@ -403,9 +491,10 @@ class ColumnOperators(Operators):
         """
         return self.operate(le, other)
 
-    __hash__ = Operators.__hash__
+    # TODO: not sure why we have this
+    __hash__ = Operators.__hash__  # type: ignore
 
-    def __eq__(self, other):
+    def __eq__(self, other: Any) -> "ColumnOperators":
         """Implement the ``==`` operator.
 
         In a column context, produces the clause ``a = b``.
@@ -414,7 +503,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(eq, other)
 
-    def __ne__(self, other):
+    def __ne__(self, other: Any) -> "ColumnOperators":
         """Implement the ``!=`` operator.
 
         In a column context, produces the clause ``a != b``.
@@ -423,7 +512,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(ne, other)
 
-    def is_distinct_from(self, other):
+    def is_distinct_from(self, other: Any) -> "ColumnOperators":
         """Implement the ``IS DISTINCT FROM`` operator.
 
         Renders "a IS DISTINCT FROM b" on most platforms;
@@ -434,7 +523,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(is_distinct_from, other)
 
-    def is_not_distinct_from(self, other):
+    def is_not_distinct_from(self, other: Any) -> "ColumnOperators":
         """Implement the ``IS NOT DISTINCT FROM`` operator.
 
         Renders "a IS NOT DISTINCT FROM b" on most platforms;
@@ -452,7 +541,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5435
     isnot_distinct_from = is_not_distinct_from
 
-    def __gt__(self, other):
+    def __gt__(self, other: Any) -> "ColumnOperators":
         """Implement the ``>`` operator.
 
         In a column context, produces the clause ``a > b``.
@@ -460,7 +549,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(gt, other)
 
-    def __ge__(self, other):
+    def __ge__(self, other: Any) -> "ColumnOperators":
         """Implement the ``>=`` operator.
 
         In a column context, produces the clause ``a >= b``.
@@ -468,7 +557,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(ge, other)
 
-    def __neg__(self):
+    def __neg__(self) -> "ColumnOperators":
         """Implement the ``-`` operator.
 
         In a column context, produces the clause ``-a``.
@@ -476,10 +565,10 @@ class ColumnOperators(Operators):
         """
         return self.operate(neg)
 
-    def __contains__(self, other):
+    def __contains__(self, other: Any) -> "ColumnOperators":
         return self.operate(contains, other)
 
-    def __getitem__(self, index):
+    def __getitem__(self, index: Any) -> "ColumnOperators":
         """Implement the [] operator.
 
         This can be used by some database-specific types
@@ -488,7 +577,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(getitem, index)
 
-    def __lshift__(self, other):
+    def __lshift__(self, other: Any) -> "ColumnOperators":
         """implement the << operator.
 
         Not used by SQLAlchemy core, this is provided
@@ -497,7 +586,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(lshift, other)
 
-    def __rshift__(self, other):
+    def __rshift__(self, other: Any) -> "ColumnOperators":
         """implement the >> operator.
 
         Not used by SQLAlchemy core, this is provided
@@ -506,7 +595,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(rshift, other)
 
-    def concat(self, other):
+    def concat(self, other: Any) -> "ColumnOperators":
         """Implement the 'concat' operator.
 
         In a column context, produces the clause ``a || b``,
@@ -515,7 +604,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(concat_op, other)
 
-    def like(self, other, escape=None):
+    def like(self, other: Any, escape=None) -> "ColumnOperators":
         r"""Implement the ``like`` operator.
 
         In a column context, produces the expression::
@@ -540,7 +629,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(like_op, other, escape=escape)
 
-    def ilike(self, other, escape=None):
+    def ilike(self, other: Any, escape=None) -> "ColumnOperators":
         r"""Implement the ``ilike`` operator, e.g. case insensitive LIKE.
 
         In a column context, produces an expression either of the form::
@@ -569,7 +658,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(ilike_op, other, escape=escape)
 
-    def in_(self, other):
+    def in_(self, other: Any) -> "ColumnOperators":
         """Implement the ``in`` operator.
 
         In a column context, produces the clause ``column IN <other>``.
@@ -658,7 +747,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(in_op, other)
 
-    def not_in(self, other):
+    def not_in(self, other: Any) -> "ColumnOperators":
         """implement the ``NOT IN`` operator.
 
         This is equivalent to using negation with
@@ -689,7 +778,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5429
     notin_ = not_in
 
-    def not_like(self, other, escape=None):
+    def not_like(self, other: Any, escape=None) -> "ColumnOperators":
         """implement the ``NOT LIKE`` operator.
 
         This is equivalent to using negation with
@@ -709,7 +798,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5435
     notlike = not_like
 
-    def not_ilike(self, other, escape=None):
+    def not_ilike(self, other: Any, escape=None) -> "ColumnOperators":
         """implement the ``NOT ILIKE`` operator.
 
         This is equivalent to using negation with
@@ -729,7 +818,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5435
     notilike = not_ilike
 
-    def is_(self, other):
+    def is_(self, other: Any) -> "ColumnOperators":
         """Implement the ``IS`` operator.
 
         Normally, ``IS`` is generated automatically when comparing to a
@@ -742,7 +831,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(is_, other)
 
-    def is_not(self, other):
+    def is_not(self, other: Any) -> "ColumnOperators":
         """Implement the ``IS NOT`` operator.
 
         Normally, ``IS NOT`` is generated automatically when comparing to a
@@ -762,7 +851,9 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5429
     isnot = is_not
 
-    def startswith(self, other, **kwargs):
+    def startswith(
+        self, other: Any, escape=None, autoescape=False
+    ) -> "ColumnOperators":
         r"""Implement the ``startswith`` operator.
 
         Produces a LIKE expression that tests against a match for the start
@@ -839,9 +930,13 @@ class ColumnOperators(Operators):
             :meth:`.ColumnOperators.like`
 
         """
-        return self.operate(startswith_op, other, **kwargs)
+        return self.operate(
+            startswith_op, other, escape=escape, autoescape=autoescape
+        )
 
-    def endswith(self, other, **kwargs):
+    def endswith(
+        self, other: Any, escape=None, autoescape=False
+    ) -> "ColumnOperators":
         r"""Implement the 'endswith' operator.
 
         Produces a LIKE expression that tests against a match for the end
@@ -918,9 +1013,13 @@ class ColumnOperators(Operators):
             :meth:`.ColumnOperators.like`
 
         """
-        return self.operate(endswith_op, other, **kwargs)
+        return self.operate(
+            endswith_op, other, escape=escape, autoescape=autoescape
+        )
 
-    def contains(self, other, **kwargs):
+    def contains(
+        self, other: Any, escape=None, autoescape=False
+    ) -> "ColumnOperators":
         r"""Implement the 'contains' operator.
 
         Produces a LIKE expression that tests against a match for the middle
@@ -998,9 +1097,11 @@ class ColumnOperators(Operators):
 
 
         """
-        return self.operate(contains_op, other, **kwargs)
+        return self.operate(
+            contains_op, other, escape=escape, autoescape=autoescape
+        )
 
-    def match(self, other, **kwargs):
+    def match(self, other: Any, **kwargs) -> "ColumnOperators":
         """Implements a database-specific 'match' operator.
 
         :meth:`_sql.ColumnOperators.match` attempts to resolve to
@@ -1024,7 +1125,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(match_op, other, **kwargs)
 
-    def regexp_match(self, pattern, flags=None):
+    def regexp_match(self, pattern, flags=None) -> "ColumnOperators":
         """Implements a database-specific 'regexp match' operator.
 
         E.g.::
@@ -1072,7 +1173,9 @@ class ColumnOperators(Operators):
         """
         return self.operate(regexp_match_op, pattern, flags=flags)
 
-    def regexp_replace(self, pattern, replacement, flags=None):
+    def regexp_replace(
+        self, pattern, replacement, flags=None
+    ) -> "ColumnOperators":
         """Implements a database-specific 'regexp replace' operator.
 
         E.g.::
@@ -1111,20 +1214,23 @@ class ColumnOperators(Operators):
 
         """
         return self.operate(
-            regexp_replace_op, pattern, replacement=replacement, flags=flags
+            regexp_replace_op,
+            pattern,
+            replacement=replacement,
+            flags=flags,
         )
 
-    def desc(self):
+    def desc(self) -> "ColumnOperators":
         """Produce a :func:`_expression.desc` clause against the
         parent object."""
         return self.operate(desc_op)
 
-    def asc(self):
+    def asc(self) -> "ColumnOperators":
         """Produce a :func:`_expression.asc` clause against the
         parent object."""
         return self.operate(asc_op)
 
-    def nulls_first(self):
+    def nulls_first(self) -> "ColumnOperators":
         """Produce a :func:`_expression.nulls_first` clause against the
         parent object.
 
@@ -1137,7 +1243,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5435
     nullsfirst = nulls_first
 
-    def nulls_last(self):
+    def nulls_last(self) -> "ColumnOperators":
         """Produce a :func:`_expression.nulls_last` clause against the
         parent object.
 
@@ -1150,7 +1256,7 @@ class ColumnOperators(Operators):
     # deprecated 1.4; see #5429
     nullslast = nulls_last
 
-    def collate(self, collation):
+    def collate(self, collation) -> "ColumnOperators":
         """Produce a :func:`_expression.collate` clause against
         the parent object, given the collation string.
 
@@ -1161,7 +1267,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(collate, collation)
 
-    def __radd__(self, other):
+    def __radd__(self, other: Any) -> "ColumnOperators":
         """Implement the ``+`` operator in reverse.
 
         See :meth:`.ColumnOperators.__add__`.
@@ -1169,7 +1275,7 @@ class ColumnOperators(Operators):
         """
         return self.reverse_operate(add, other)
 
-    def __rsub__(self, other):
+    def __rsub__(self, other: Any) -> "ColumnOperators":
         """Implement the ``-`` operator in reverse.
 
         See :meth:`.ColumnOperators.__sub__`.
@@ -1177,7 +1283,7 @@ class ColumnOperators(Operators):
         """
         return self.reverse_operate(sub, other)
 
-    def __rmul__(self, other):
+    def __rmul__(self, other: Any) -> "ColumnOperators":
         """Implement the ``*`` operator in reverse.
 
         See :meth:`.ColumnOperators.__mul__`.
@@ -1185,7 +1291,7 @@ class ColumnOperators(Operators):
         """
         return self.reverse_operate(mul, other)
 
-    def __rmod__(self, other):
+    def __rmod__(self, other: Any) -> "ColumnOperators":
         """Implement the ``%`` operator in reverse.
 
         See :meth:`.ColumnOperators.__mod__`.
@@ -1193,21 +1299,21 @@ class ColumnOperators(Operators):
         """
         return self.reverse_operate(mod, other)
 
-    def between(self, cleft, cright, symmetric=False):
+    def between(self, cleft, cright, symmetric=False) -> "ColumnOperators":
         """Produce a :func:`_expression.between` clause against
         the parent object, given the lower and upper range.
 
         """
         return self.operate(between_op, cleft, cright, symmetric=symmetric)
 
-    def distinct(self):
+    def distinct(self) -> "ColumnOperators":
         """Produce a :func:`_expression.distinct` clause against the
         parent object.
 
         """
         return self.operate(distinct_op)
 
-    def any_(self):
+    def any_(self) -> "ColumnOperators":
         """Produce an :func:`_expression.any_` clause against the
         parent object.
 
@@ -1224,7 +1330,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(any_op)
 
-    def all_(self):
+    def all_(self) -> "ColumnOperators":
         """Produce an :func:`_expression.all_` clause against the
         parent object.
 
@@ -1242,7 +1348,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(all_op)
 
-    def __add__(self, other):
+    def __add__(self, other: Any) -> "ColumnOperators":
         """Implement the ``+`` operator.
 
         In a column context, produces the clause ``a + b``
@@ -1254,7 +1360,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(add, other)
 
-    def __sub__(self, other):
+    def __sub__(self, other: Any) -> "ColumnOperators":
         """Implement the ``-`` operator.
 
         In a column context, produces the clause ``a - b``.
@@ -1262,7 +1368,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(sub, other)
 
-    def __mul__(self, other):
+    def __mul__(self, other: Any) -> "ColumnOperators":
         """Implement the ``*`` operator.
 
         In a column context, produces the clause ``a * b``.
@@ -1270,7 +1376,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(mul, other)
 
-    def __mod__(self, other):
+    def __mod__(self, other: Any) -> "ColumnOperators":
         """Implement the ``%`` operator.
 
         In a column context, produces the clause ``a % b``.
@@ -1278,7 +1384,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(mod, other)
 
-    def __truediv__(self, other):
+    def __truediv__(self, other: Any) -> "ColumnOperators":
         """Implement the ``/`` operator.
 
         In a column context, produces the clause ``a / b``, and
@@ -1291,7 +1397,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(truediv, other)
 
-    def __rtruediv__(self, other):
+    def __rtruediv__(self, other: Any) -> "ColumnOperators":
         """Implement the ``/`` operator in reverse.
 
         See :meth:`.ColumnOperators.__truediv__`.
@@ -1299,7 +1405,7 @@ class ColumnOperators(Operators):
         """
         return self.reverse_operate(truediv, other)
 
-    def __floordiv__(self, other):
+    def __floordiv__(self, other: Any) -> "ColumnOperators":
         """Implement the ``//`` operator.
 
         In a column context, produces the clause ``a / b``,
@@ -1311,7 +1417,7 @@ class ColumnOperators(Operators):
         """
         return self.operate(floordiv, other)
 
-    def __rfloordiv__(self, other):
+    def __rfloordiv__(self, other: Any) -> "ColumnOperators":
         """Implement the ``//`` operator in reverse.
 
         See :meth:`.ColumnOperators.__floordiv__`.
@@ -1324,6 +1430,10 @@ _commutative = {eq, ne, add, mul}
 _comparison = {eq, ne, lt, gt, ge, le}
 
 
+def _operator_fn(fn):
+    return cast(OperatorType, fn)
+
+
 def commutative_op(fn):
     _commutative.add(fn)
     return fn
@@ -1351,6 +1461,7 @@ def exists():
     raise NotImplementedError()
 
 
+@_operator_fn
 def is_true(a):
     raise NotImplementedError()
 
@@ -1359,6 +1470,7 @@ def is_true(a):
 istrue = is_true
 
 
+@_operator_fn
 def is_false(a):
     raise NotImplementedError()
 
@@ -1368,11 +1480,13 @@ isfalse = is_false
 
 
 @comparison_op
+@_operator_fn
 def is_distinct_from(a, b):
     return a.is_distinct_from(b)
 
 
 @comparison_op
+@_operator_fn
 def is_not_distinct_from(a, b):
     return a.is_not_distinct_from(b)
 
@@ -1382,11 +1496,13 @@ isnot_distinct_from = is_not_distinct_from
 
 
 @comparison_op
+@_operator_fn
 def is_(a, b):
     return a.is_(b)
 
 
 @comparison_op
+@_operator_fn
 def is_not(a, b):
     return a.is_not(b)
 
@@ -1395,20 +1511,24 @@ def is_not(a, b):
 isnot = is_not
 
 
+@_operator_fn
 def collate(a, b):
     return a.collate(b)
 
 
+@_operator_fn
 def op(a, opstring, b):
     return a.op(opstring)(b)
 
 
 @comparison_op
+@_operator_fn
 def like_op(a, b, escape=None):
     return a.like(b, escape=escape)
 
 
 @comparison_op
+@_operator_fn
 def not_like_op(a, b, escape=None):
     return a.notlike(b, escape=escape)
 
@@ -1418,11 +1538,13 @@ notlike_op = not_like_op
 
 
 @comparison_op
+@_operator_fn
 def ilike_op(a, b, escape=None):
     return a.ilike(b, escape=escape)
 
 
 @comparison_op
+@_operator_fn
 def not_ilike_op(a, b, escape=None):
     return a.not_ilike(b, escape=escape)
 
@@ -1432,11 +1554,13 @@ notilike_op = not_ilike_op
 
 
 @comparison_op
+@_operator_fn
 def between_op(a, b, c, symmetric=False):
     return a.between(b, c, symmetric=symmetric)
 
 
 @comparison_op
+@_operator_fn
 def not_between_op(a, b, c, symmetric=False):
     return ~a.between(b, c, symmetric=symmetric)
 
@@ -1446,11 +1570,13 @@ notbetween_op = not_between_op
 
 
 @comparison_op
+@_operator_fn
 def in_op(a, b):
     return a.in_(b)
 
 
 @comparison_op
+@_operator_fn
 def not_in_op(a, b):
     return a.not_in(b)
 
@@ -1459,19 +1585,22 @@ def not_in_op(a, b):
 notin_op = not_in_op
 
 
+@_operator_fn
 def distinct_op(a):
     return a.distinct()
 
 
+@_operator_fn
 def any_op(a):
     return a.any_()
 
 
+@_operator_fn
 def all_op(a):
     return a.all_()
 
 
-def _escaped_like_impl(fn, other, escape, autoescape):
+def _escaped_like_impl(fn, other: Any, escape, autoescape):
     if autoescape:
         if autoescape is not True:
             util.warn(
@@ -1492,11 +1621,13 @@ def _escaped_like_impl(fn, other, escape, autoescape):
 
 
 @comparison_op
+@_operator_fn
 def startswith_op(a, b, escape=None, autoescape=False):
     return _escaped_like_impl(a.startswith, b, escape, autoescape)
 
 
 @comparison_op
+@_operator_fn
 def not_startswith_op(a, b, escape=None, autoescape=False):
     return ~_escaped_like_impl(a.startswith, b, escape, autoescape)
 
@@ -1506,11 +1637,13 @@ notstartswith_op = not_startswith_op
 
 
 @comparison_op
+@_operator_fn
 def endswith_op(a, b, escape=None, autoescape=False):
     return _escaped_like_impl(a.endswith, b, escape, autoescape)
 
 
 @comparison_op
+@_operator_fn
 def not_endswith_op(a, b, escape=None, autoescape=False):
     return ~_escaped_like_impl(a.endswith, b, escape, autoescape)
 
@@ -1520,11 +1653,13 @@ notendswith_op = not_endswith_op
 
 
 @comparison_op
+@_operator_fn
 def contains_op(a, b, escape=None, autoescape=False):
     return _escaped_like_impl(a.contains, b, escape, autoescape)
 
 
 @comparison_op
+@_operator_fn
 def not_contains_op(a, b, escape=None, autoescape=False):
     return ~_escaped_like_impl(a.contains, b, escape, autoescape)
 
@@ -1534,25 +1669,30 @@ notcontains_op = not_contains_op
 
 
 @comparison_op
+@_operator_fn
 def match_op(a, b, **kw):
     return a.match(b, **kw)
 
 
 @comparison_op
+@_operator_fn
 def regexp_match_op(a, b, flags=None):
     return a.regexp_match(b, flags=flags)
 
 
 @comparison_op
+@_operator_fn
 def not_regexp_match_op(a, b, flags=None):
     return ~a.regexp_match(b, flags=flags)
 
 
+@_operator_fn
 def regexp_replace_op(a, b, replacement, flags=None):
     return a.regexp_replace(b, replacement=replacement, flags=flags)
 
 
 @comparison_op
+@_operator_fn
 def not_match_op(a, b, **kw):
     return ~a.match(b, **kw)
 
@@ -1561,26 +1701,32 @@ def not_match_op(a, b, **kw):
 notmatch_op = not_match_op
 
 
+@_operator_fn
 def comma_op(a, b):
     raise NotImplementedError()
 
 
+@_operator_fn
 def filter_op(a, b):
     raise NotImplementedError()
 
 
+@_operator_fn
 def concat_op(a, b):
     return a.concat(b)
 
 
+@_operator_fn
 def desc_op(a):
     return a.desc()
 
 
+@_operator_fn
 def asc_op(a):
     return a.asc()
 
 
+@_operator_fn
 def nulls_first_op(a):
     return a.nulls_first()
 
@@ -1589,6 +1735,7 @@ def nulls_first_op(a):
 nullsfirst_op = nulls_first_op
 
 
+@_operator_fn
 def nulls_last_op(a):
     return a.nulls_last()
 
@@ -1597,10 +1744,12 @@ def nulls_last_op(a):
 nullslast_op = nulls_last_op
 
 
+@_operator_fn
 def json_getitem_op(a, b):
     raise NotImplementedError()
 
 
+@_operator_fn
 def json_path_getitem_op(a, b):
     raise NotImplementedError()
 
index 9172c2dc9dd3c03ebed2abacb8a5a10324efece1..787a1c25ee58ce2acc7f452179f24ee2199d5541 100644 (file)
@@ -71,7 +71,13 @@ class ColumnListRole(SQLRole):
     __slots__ = ()
 
 
-class TruncatedLabelRole(SQLRole):
+class StringRole(SQLRole):
+    """mixin indicating a role that results in strings"""
+
+    __slots__ = ()
+
+
+class TruncatedLabelRole(StringRole, SQLRole):
     __slots__ = ()
     _role_name = "String SQL identifier"
 
index 885cb2754e60f736000c9b37954ddc2280f9ded1..938d2c34a162f7cab253428c9b90acb86a18c240 100644 (file)
@@ -29,6 +29,14 @@ as components in SQL expressions.
 
 """
 import collections
+import typing
+from typing import Any
+from typing import MutableMapping
+from typing import Optional
+from typing import overload
+from typing import Type
+from typing import TypeVar
+from typing import Union
 
 from . import coercions
 from . import ddl
@@ -52,7 +60,13 @@ from .. import event
 from .. import exc
 from .. import inspection
 from .. import util
+from ..util.typing import Literal
 
+if typing.TYPE_CHECKING:
+    from .type_api import TypeEngine
+
+_T = TypeVar("_T", bound="Any")
+_ServerDefaultType = Union["FetchedValue", str, TextClause, ColumnElement]
 
 RETAIN_SCHEMA = util.symbol("retain_schema")
 
@@ -1086,13 +1100,109 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
         return self._schema_item_copy(table)
 
 
-class Column(DialectKWArgs, SchemaItem, ColumnClause):
+class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
     """Represents a column in a database table."""
 
     __visit_name__ = "column"
 
     inherit_cache = True
 
+    @overload
+    def __init__(
+        self: "Column[None]",
+        __name: str,
+        *args: SchemaEventTarget,
+        autoincrement: Union[bool, Literal["auto", "ignore_fk"]] = ...,
+        default: Optional[Any] = ...,
+        doc: Optional[str] = ...,
+        key: Optional[str] = ...,
+        index: Optional[bool] = ...,
+        info: MutableMapping[Any, Any] = ...,
+        nullable: bool = ...,
+        onupdate: Optional[Any] = ...,
+        primary_key: bool = ...,
+        server_default: Optional[_ServerDefaultType] = ...,
+        server_onupdate: Optional["FetchedValue"] = ...,
+        quote: Optional[bool] = ...,
+        unique: Optional[bool] = ...,
+        system: bool = ...,
+        comment: Optional[str] = ...,
+        **kwargs: Any,
+    ) -> None:
+        ...
+
+    @overload
+    def __init__(
+        self: "Column[None]",
+        *args: SchemaEventTarget,
+        autoincrement: Union[bool, Literal["auto", "ignore_fk"]] = ...,
+        default: Optional[Any] = ...,
+        doc: Optional[str] = ...,
+        key: Optional[str] = ...,
+        index: Optional[bool] = ...,
+        info: MutableMapping[Any, Any] = ...,
+        nullable: bool = ...,
+        onupdate: Optional[Any] = ...,
+        primary_key: bool = ...,
+        server_default: Optional[_ServerDefaultType] = ...,
+        server_onupdate: Optional["FetchedValue"] = ...,
+        quote: Optional[bool] = ...,
+        unique: Optional[bool] = ...,
+        system: bool = ...,
+        comment: Optional[str] = ...,
+        **kwargs: Any,
+    ) -> None:
+        ...
+
+    @overload
+    def __init__(
+        self,
+        __name: str,
+        __type: Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"],
+        *args: SchemaEventTarget,
+        autoincrement: Union[bool, Literal["auto", "ignore_fk"]] = ...,
+        default: Optional[Any] = ...,
+        doc: Optional[str] = ...,
+        key: Optional[str] = ...,
+        index: Optional[bool] = ...,
+        info: MutableMapping[Any, Any] = ...,
+        nullable: bool = ...,
+        onupdate: Optional[Any] = ...,
+        primary_key: bool = ...,
+        server_default: Optional[_ServerDefaultType] = ...,
+        server_onupdate: Optional["FetchedValue"] = ...,
+        quote: Optional[bool] = ...,
+        unique: Optional[bool] = ...,
+        system: bool = ...,
+        comment: Optional[str] = ...,
+        **kwargs: Any,
+    ) -> None:
+        ...
+
+    @overload
+    def __init__(
+        self,
+        __type: Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"],
+        *args: SchemaEventTarget,
+        autoincrement: Union[bool, Literal["auto", "ignore_fk"]] = ...,
+        default: Optional[Any] = ...,
+        doc: Optional[str] = ...,
+        key: Optional[str] = ...,
+        index: Optional[bool] = ...,
+        info: MutableMapping[Any, Any] = ...,
+        nullable: bool = ...,
+        onupdate: Optional[Any] = ...,
+        primary_key: bool = ...,
+        server_default: Optional[_ServerDefaultType] = ...,
+        server_onupdate: Optional["FetchedValue"] = ...,
+        quote: Optional[bool] = ...,
+        unique: Optional[bool] = ...,
+        system: bool = ...,
+        comment: Optional[str] = ...,
+        **kwargs: Any,
+    ) -> None:
+        ...
+
     def __init__(self, *args, **kwargs):
         r"""
         Construct a new ``Column`` object.
index e674c4b74d657ec50577a5e57796549fb194d9c1..fd1abd71be021b36bbe6a28bd677288154db1407 100644 (file)
@@ -48,7 +48,6 @@ from .base import Immutable
 from .base import prefix_anon_map
 from .coercions import _document_text_coercion
 from .elements import _anonymous_label
-from .elements import and_
 from .elements import BindParameter
 from .elements import BooleanClauseList
 from .elements import ClauseElement
@@ -64,6 +63,9 @@ from .. import exc
 from .. import util
 
 
+and_ = BooleanClauseList.and_
+
+
 class _OffsetLimitParam(BindParameter):
     inherit_cache = True
 
@@ -472,7 +474,7 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
             method which allows for arbitrary column lists.
 
         """
-        return Select._create(self)
+        return Select(self)
 
     def join(self, right, onclause=None, isouter=False, full=False):
         """Return a :class:`_expression.Join` from this
@@ -990,86 +992,6 @@ class Join(roles.DMLTableRole, FromClause):
         self.isouter = isouter
         self.full = full
 
-    @classmethod
-    def _create_outerjoin(cls, left, right, onclause=None, full=False):
-        """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 cls(left, right, onclause, isouter=True, full=full)
-
-    @classmethod
-    def _create_join(
-        cls, left, right, onclause=None, isouter=False, full=False
-    ):
-        """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::
-
-            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.
-
-         .. versionadded:: 1.1
-
-        .. seealso::
-
-            :meth:`_expression.FromClause.join` - method form,
-            based on a given left side.
-
-            :class:`_expression.Join` - the type of object produced.
-
-        """
-
-        return cls(left, right, onclause, isouter, full)
-
     @property
     def description(self):
         return "Join object on %s(%d) and %s(%d)" % (
@@ -1161,24 +1083,7 @@ class Join(roles.DMLTableRole, FromClause):
     ):
         """Create a join condition between two tables or selectables.
 
-        e.g.::
-
-            join_condition(tablea, tableb)
-
-        would produce an expression along the lines of::
-
-            tablea.c.id==tableb.c.tablea_id
-
-        The join is determined based on the foreign key relationships
-        between the two selectables.   If there are multiple ways
-        to join, or no way to join, an error is raised.
-
-        :param a_subset: An optional expression that is a sub-component
-         of ``a``.  An attempt will be made to join to just this sub-component
-         first before looking at the full ``a`` construct, and if found
-         will be successful even if there are other ways to join to ``a``.
-         This allows the "right side" of a join to be passed thereby
-         providing a "natural join".
+        See sqlalchemy.sql.util.join_condition() for full docs.
 
         """
         constraints = cls._joincond_scan_left_right(
@@ -1331,7 +1236,7 @@ class Join(roles.DMLTableRole, FromClause):
             FROM table_a JOIN table_b ON table_a.id = table_b.a_id
 
         """
-        return Select._create(self.left, self.right).select_from(self)
+        return Select(self.left, self.right).select_from(self)
 
     @util.preload_module("sqlalchemy.sql.util")
     def _anonymous_fromclause(self, name=None, flat=False):
@@ -1503,51 +1408,6 @@ class Alias(roles.DMLTableRole, AliasedReturnsRows):
 
     @classmethod
     def _factory(cls, selectable, name=None, flat=False):
-        """Return an :class:`_expression.Alias` object.
-
-        An :class:`_expression.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``.
-
-        Similar functionality is available via the
-        :meth:`_expression.FromClause.alias`
-        method available on all :class:`_expression.FromClause` subclasses.
-        In terms of
-        a SELECT object as generated from the :func:`_expression.select`
-        function, the :meth:`_expression.SelectBase.alias` method returns an
-        :class:`_expression.Alias` or similar object which represents a named,
-        parenthesized subquery.
-
-        When an :class:`_expression.Alias` is created from a
-        :class:`_schema.Table` object,
-        this has the effect of the table being rendered
-        as ``tablename AS aliasname`` in a SELECT statement.
-
-        For :func:`_expression.select` objects, the effect is that of
-        creating a named subquery, i.e. ``(select ...) AS aliasname``.
-
-        The ``name`` parameter is optional, and provides the name
-        to use in the rendered SQL.  If blank, an "anonymous" 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 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.
-
-        :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 coercions.expect(
             roles.FromClauseRole, selectable, allow_select=True
         ).alias(name=name, flat=flat)
@@ -1724,25 +1584,6 @@ class Lateral(AliasedReturnsRows):
 
     @classmethod
     def _factory(cls, selectable, name=None):
-        """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.
-
-        .. versionadded:: 1.1
-
-        .. seealso::
-
-            :ref:`lateral_selects` -  overview of usage.
-
-        """
         return coercions.expect(
             roles.FromClauseRole, selectable, explicit_subquery=True
         ).lateral(name=name)
@@ -1773,48 +1614,6 @@ class TableSample(AliasedReturnsRows):
 
     @classmethod
     def _factory(cls, selectable, sampling, name=None, seed=None):
-        """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::
-
-            SELECT alias.people_id FROM
-            people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
-            REPEATABLE (random())
-
-        .. versionadded:: 1.1
-
-        :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 coercions.expect(roles.FromClauseRole, selectable).tablesample(
             sampling, name=name, seed=seed
         )
@@ -2493,28 +2292,6 @@ class TableClause(roles.DMLTableRole, Immutable, FromClause):
     """No PK or default support so no autoincrement column."""
 
     def __init__(self, name, *columns, **kw):
-        """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.
-
-        .. versionchanged:: 1.0.0 :func:`_expression.table` can now
-           be imported from the plain ``sqlalchemy`` namespace like any
-           other SQL element.
-
-
-        :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.
-        """
         super(TableClause, self).__init__()
         self.name = name
         self._columns = DedupeColumnCollection()
@@ -2697,41 +2474,6 @@ class Values(Generative, FromClause):
     ]
 
     def __init__(self, *columns, name=None, literal_binds=False):
-        r"""Construct a :class:`_expression.Values` construct.
-
-        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
-
-            value_expr = values(
-                column('id', Integer),
-                column('name', String),
-                name="my_values"
-            ).data(
-                [(1, 'name1'), (2, 'name2'), (3, 'name3')]
-            )
-
-        :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.
-
-        """
-
         super(Values, self).__init__()
         self._column_args = columns
         self.name = name
@@ -3708,91 +3450,26 @@ class CompoundSelect(HasCompileState, GenerativeSelect):
 
     @classmethod
     def _create_union(cls, *selects, **kwargs):
-        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(CompoundSelect.UNION, *selects, **kwargs)
 
     @classmethod
     def _create_union_all(cls, *selects):
-        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(CompoundSelect.UNION_ALL, *selects)
 
     @classmethod
     def _create_except(cls, *selects):
-        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(CompoundSelect.EXCEPT, *selects)
 
     @classmethod
     def _create_except_all(cls, *selects):
-        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(CompoundSelect.EXCEPT_ALL, *selects)
 
     @classmethod
     def _create_intersect(cls, *selects):
-        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(CompoundSelect.INTERSECT, *selects)
 
     @classmethod
     def _create_intersect_all(cls, *selects):
-        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(CompoundSelect.INTERSECT_ALL, *selects)
 
     def _scalar_type(self):
@@ -4413,47 +4090,26 @@ class Select(
     ]
 
     @classmethod
-    def _create(
-        cls, *entities: Union[roles.ColumnsClauseRole, Type]
-    ) -> "Select":
-        r"""Construct a new :class:`_expression.Select`.
+    def _create_raw_select(cls, **kw) -> "Select":
+        """Create a :class:`.Select` using raw ``__new__`` with no coercions.
 
+        Used internally to build up :class:`.Select` constructs with
+        pre-established state.
 
-        .. 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:`_future.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`.
+        stmt = Select.__new__(Select)
+        stmt.__dict__.update(kw)
+        return stmt
 
-        .. seealso::
+    def __init__(self, *entities: Union[roles.ColumnsClauseRole, Type]):
+        r"""Construct a new :class:`_expression.Select`.
 
-            :ref:`coretutorial_selecting` - Core Tutorial description of
-            :func:`_expression.select`.
-
-        :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 public constructor for :class:`_expression.Select` is the
+        :func:`_sql.select` function.
 
         """
 
-        self = cls.__new__(cls)
         self._raw_columns = [
             coercions.expect(
                 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
@@ -4463,24 +4119,6 @@ class Select(
 
         GenerativeSelect.__init__(self)
 
-        return self
-
-    @classmethod
-    def _create_raw_select(cls, **kw) -> "Select":
-        """Create a :class:`.Select` using raw ``__new__`` with no coercions.
-
-        Used internally to build up :class:`.Select` constructs with
-        pre-established state.
-
-        """
-
-        stmt = Select.__new__(Select)
-        stmt.__dict__.update(kw)
-        return stmt
-
-    def __init__(self):
-        raise NotImplementedError()
-
     def _scalar_type(self):
         elem = self._raw_columns[0]
         cols = list(elem._select_iterable)
@@ -5787,52 +5425,16 @@ class Exists(UnaryExpression):
 
     """
 
-    _from_objects = []
+    _from_objects = ()
     inherit_cache = True
 
-    def __init__(self, *args, **kwargs):
-        """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::
-
-            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
-        if args and isinstance(args[0], (SelectBase, ScalarSelect)):
-            s = args[0]
+    def __init__(self, __argument=None):
+        if __argument is None:
+            s = Select(literal_column("*")).scalar_subquery()
+        elif isinstance(__argument, (SelectBase, ScalarSelect)):
+            s = __argument
         else:
-            if not args:
-                args = (literal_column("*"),)
-            s = Select._create(*args, **kwargs).scalar_subquery()
+            s = Select(__argument).scalar_subquery()
 
         UnaryExpression.__init__(
             self,
@@ -5865,7 +5467,7 @@ class Exists(UnaryExpression):
 
         """  # noqa
 
-        return Select._create(self)
+        return Select(self)
 
     def correlate(self, *fromclause):
         """Apply correlation to the subquery noted by this :class:`_sql.Exists`.
index 93ff5366367aae5432d61d95f91aa784e86c2eb0..81434fbb9efb922dff10d682656ff5ffdcded6fc 100644 (file)
@@ -8,12 +8,18 @@
 """SQL specific types.
 
 """
-
 import collections.abc as collections_abc
 import datetime as dt
 import decimal
+import enum
 import json
 import pickle
+from typing import Any
+from typing import Sequence
+from typing import Text as typing_Text
+from typing import Tuple
+from typing import TypeVar
+from typing import Union
 
 from . import coercions
 from . import elements
@@ -43,6 +49,9 @@ from ..util import langhelpers
 from ..util import OrderedDict
 
 
+_T = TypeVar("_T", bound="Any")
+
+
 class _LookupExpressionAdapter:
 
     """Mixin expression adaptations based on lookup tables.
@@ -121,7 +130,7 @@ class Indexable:
     comparator_factory = Comparator
 
 
-class String(Concatenable, TypeEngine):
+class String(Concatenable, TypeEngine[typing_Text]):
 
     """The base for all string and character types.
 
@@ -136,7 +145,10 @@ class String(Concatenable, TypeEngine):
     __visit_name__ = "string"
 
     def __init__(
-        self,
+        # note pylance appears to require the "self" type in a constructor
+        # for the _T type to be correctly recognized when we send the
+        # class as the argument, e.g. `column("somecol", String)`
+        self: "String",
         length=None,
         collation=None,
     ):
@@ -289,7 +301,7 @@ class UnicodeText(Text):
         super(UnicodeText, self).__init__(length=length, **kwargs)
 
 
-class Integer(_LookupExpressionAdapter, TypeEngine):
+class Integer(_LookupExpressionAdapter, TypeEngine[int]):
 
     """A type for ``int`` integers."""
 
@@ -351,7 +363,9 @@ class BigInteger(Integer):
     __visit_name__ = "big_integer"
 
 
-class Numeric(_LookupExpressionAdapter, TypeEngine):
+class Numeric(
+    _LookupExpressionAdapter, TypeEngine[Union[decimal.Decimal, float]]
+):
 
     """A type for fixed precision numbers, such as ``NUMERIC`` or ``DECIMAL``.
 
@@ -396,7 +410,7 @@ class Numeric(_LookupExpressionAdapter, TypeEngine):
     _default_decimal_return_scale = 10
 
     def __init__(
-        self,
+        self: "Numeric",
         precision=None,
         scale=None,
         decimal_return_scale=None,
@@ -544,7 +558,10 @@ class Float(Numeric):
     scale = None
 
     def __init__(
-        self, precision=None, asdecimal=False, decimal_return_scale=None
+        self: "Float",
+        precision=None,
+        asdecimal=False,
+        decimal_return_scale=None,
     ):
         r"""
         Construct a Float.
@@ -583,7 +600,7 @@ class Float(Numeric):
             return None
 
 
-class DateTime(_LookupExpressionAdapter, TypeEngine):
+class DateTime(_LookupExpressionAdapter, TypeEngine[dt.datetime]):
 
     """A type for ``datetime.datetime()`` objects.
 
@@ -645,7 +662,7 @@ class DateTime(_LookupExpressionAdapter, TypeEngine):
         }
 
 
-class Date(_LookupExpressionAdapter, TypeEngine):
+class Date(_LookupExpressionAdapter, TypeEngine[dt.date]):
 
     """A type for ``datetime.date()`` objects."""
 
@@ -683,7 +700,7 @@ class Date(_LookupExpressionAdapter, TypeEngine):
         }
 
 
-class Time(_LookupExpressionAdapter, TypeEngine):
+class Time(_LookupExpressionAdapter, TypeEngine[dt.time]):
 
     """A type for ``datetime.time()`` objects."""
 
@@ -717,7 +734,7 @@ class Time(_LookupExpressionAdapter, TypeEngine):
         }
 
 
-class _Binary(TypeEngine):
+class _Binary(TypeEngine[bytes]):
 
     """Define base behavior for binary types."""
 
@@ -1019,7 +1036,7 @@ class SchemaType(SchemaEventTarget):
             return _we_are_the_impl(variant_mapping["_default"])
 
 
-class Enum(Emulated, String, SchemaType):
+class Enum(Emulated, String, TypeEngine[Union[str, enum.Enum]], SchemaType):
     """Generic Enum Type.
 
     The :class:`.Enum` type provides a set of possible string values
@@ -1496,7 +1513,7 @@ class Enum(Emulated, String, SchemaType):
             return super(Enum, self).python_type
 
 
-class PickleType(TypeDecorator):
+class PickleType(TypeDecorator[object]):
     """Holds Python objects, which are serialized using pickle.
 
     PickleType builds upon the Binary type to apply Python's
@@ -1597,7 +1614,7 @@ class PickleType(TypeDecorator):
             return x == y
 
 
-class Boolean(Emulated, TypeEngine, SchemaType):
+class Boolean(Emulated, TypeEngine[bool], SchemaType):
 
     """A bool datatype.
 
@@ -1621,7 +1638,10 @@ class Boolean(Emulated, TypeEngine, SchemaType):
     native = True
 
     def __init__(
-        self, create_constraint=False, name=None, _create_events=True
+        self: "Boolean",
+        create_constraint=False,
+        name=None,
+        _create_events=True,
     ):
         """Construct a Boolean.
 
@@ -1723,7 +1743,7 @@ class Boolean(Emulated, TypeEngine, SchemaType):
             return processors.int_to_boolean
 
 
-class _AbstractInterval(_LookupExpressionAdapter, TypeEngine):
+class _AbstractInterval(_LookupExpressionAdapter, TypeEngine[dt.timedelta]):
     @util.memoized_property
     def _expression_adaptations(self):
         # Based on https://www.postgresql.org/docs/current/\
@@ -1841,7 +1861,7 @@ class Interval(Emulated, _AbstractInterval, TypeDecorator):
         return process
 
 
-class JSON(Indexable, TypeEngine):
+class JSON(Indexable, TypeEngine[Any]):
     """Represent a SQL JSON type.
 
     .. note::  :class:`_types.JSON`
@@ -2399,7 +2419,9 @@ class JSON(Indexable, TypeEngine):
         return process
 
 
-class ARRAY(SchemaEventTarget, Indexable, Concatenable, TypeEngine):
+class ARRAY(
+    SchemaEventTarget, Indexable, Concatenable, TypeEngine[Sequence[Any]]
+):
     """Represent a SQL Array type.
 
     .. note::  This type serves as the basis for all ARRAY operations.
@@ -2700,7 +2722,7 @@ class ARRAY(SchemaEventTarget, Indexable, Concatenable, TypeEngine):
             self.item_type._set_parent_with_dispatch(parent)
 
 
-class TupleType(TypeEngine):
+class TupleType(TypeEngine[Tuple[Any]]):
     """represent the composite type of a Tuple."""
 
     _is_tuple_type = True
index 7981100a48d8c6cab1787c24cbc1d3bca389bf14..75eb1b8c5e4f65bbcb5419fd13f728fbba17365b 100644 (file)
 """
 
 import typing
+from typing import Any
+from typing import Generic
+from typing import Tuple
+from typing import Type
+from typing import TypeVar
+from typing import Union
 
-from . import operators
 from .base import SchemaEventTarget
 from .cache_key import NO_CACHE
+from .operators import ColumnOperators
 from .visitors import Traversible
 from .. import exc
 from .. import util
 
 # these are back-assigned by sqltypes.
-BOOLEANTYPE = None
-INTEGERTYPE = None
-NULLTYPE = None
-STRINGTYPE = None
-MATCHTYPE = None
-INDEXABLE = None
-TABLEVALUE = None
-_resolve_value_to_type = None
-
+if not typing.TYPE_CHECKING:
+    BOOLEANTYPE = None
+    INTEGERTYPE = None
+    NULLTYPE = None
+    STRINGTYPE = None
+    MATCHTYPE = None
+    INDEXABLE = None
+    TABLEVALUE = None
+    _resolve_value_to_type = None
+
+if typing.TYPE_CHECKING:
+    from .elements import ColumnElement
+    from .operators import OperatorType
+    from .sqltypes import _resolve_value_to_type
+    from .sqltypes import Boolean as BOOLEANTYPE  # noqa
+    from .sqltypes import Indexable as INDEXABLE  # noqa
+    from .sqltypes import MatchType as MATCHTYPE  # noqa
+    from .sqltypes import NULLTYPE
+
+_T = TypeVar("_T", bound=Any)
+_CT = TypeVar("_CT", bound=Any)
 
 # replace with pep-673 when applicable
 SelfTypeEngine = typing.TypeVar("SelfTypeEngine", bound="TypeEngine")
 
 
-class TypeEngine(Traversible):
+class TypeEngine(Traversible, Generic[_T]):
     """The ultimate base class for all SQL datatypes.
 
     Common subclasses of :class:`.TypeEngine` include
@@ -55,6 +73,8 @@ class TypeEngine(Traversible):
     _is_array = False
     _is_type_decorator = False
 
+    _block_from_type_affinity = False
+
     render_bind_cast = False
     """Render bind casts for :attr:`.BindTyping.RENDER_CASTS` mode.
 
@@ -70,7 +90,10 @@ class TypeEngine(Traversible):
 
     """
 
-    class Comparator(operators.ColumnOperators):
+    class Comparator(
+        ColumnOperators["ColumnElement"],
+        Generic[_CT],
+    ):
         """Base class for custom comparison operations defined at the
         type level.  See :attr:`.TypeEngine.comparator_factory`.
 
@@ -84,23 +107,33 @@ class TypeEngine(Traversible):
         def __clause_element__(self):
             return self.expr
 
-        def __init__(self, expr):
+        def __init__(self, expr: "ColumnElement[_CT]"):
             self.expr = expr
-            self.type = expr.type
+            self.type: TypeEngine[_CT] = expr.type
 
         @util.preload_module("sqlalchemy.sql.default_comparator")
-        def operate(self, op, *other, **kwargs):
+        def operate(
+            self, op: "OperatorType", *other, **kwargs
+        ) -> "ColumnElement":
             default_comparator = util.preloaded.sql_default_comparator
-            o = default_comparator.operator_lookup[op.__name__]
-            return o[0](self.expr, op, *(other + o[1:]), **kwargs)
+            op_fn, addtl_kw = default_comparator.operator_lookup[op.__name__]
+            if kwargs:
+                addtl_kw = addtl_kw.union(kwargs)
+            return op_fn(self.expr, op, *other, **addtl_kw)
 
         @util.preload_module("sqlalchemy.sql.default_comparator")
-        def reverse_operate(self, op, other, **kwargs):
+        def reverse_operate(
+            self, op: "OperatorType", other, **kwargs
+        ) -> "ColumnElement":
             default_comparator = util.preloaded.sql_default_comparator
-            o = default_comparator.operator_lookup[op.__name__]
-            return o[0](self.expr, op, other, reverse=True, *o[1:], **kwargs)
-
-        def _adapt_expression(self, op, other_comparator):
+            op_fn, addtl_kw = default_comparator.operator_lookup[op.__name__]
+            if kwargs:
+                addtl_kw = addtl_kw.union(kwargs)
+            return op_fn(self.expr, op, other, reverse=True, **addtl_kw)
+
+        def _adapt_expression(
+            self, op: "OperatorType", other_comparator
+        ) -> Tuple["OperatorType", "TypeEngine[_CT]"]:
             """evaluate the return type of <self> <op> <othertype>,
             and apply any adaptations to the given operator.
 
@@ -611,7 +644,9 @@ class TypeEngine(Traversible):
         for t in self.__class__.__mro__:
             if t in (TypeEngine, UserDefinedType):
                 return typ
-            elif issubclass(t, (TypeEngine, UserDefinedType)):
+            elif issubclass(
+                t, (TypeEngine, UserDefinedType)
+            ) and not t.__dict__.get("_block_from_type_affinity", False):
                 typ = t
         else:
             return self.__class__
@@ -1202,7 +1237,7 @@ class NativeForEmulated:
         return cls(**kw)
 
 
-class TypeDecorator(ExternalType, SchemaEventTarget, TypeEngine):
+class TypeDecorator(ExternalType, SchemaEventTarget, TypeEngine[_T]):
     """Allows the creation of types which add additional functionality
     to an existing type.
 
@@ -1882,7 +1917,9 @@ def _reconstitute_comparator(expression):
     return expression.comparator
 
 
-def to_instance(typeobj, *arg, **kw):
+def to_instance(
+    typeobj: Union[Type[TypeEngine[_T]], TypeEngine[_T], None], *arg, **kw
+) -> TypeEngine[_T]:
     if typeobj is None:
         return NULLTYPE
 
index 63067585ed1c1f584da6a97eb882cca822d66435..fa3bae83530d8cf9d2fcf2dd8c3d614ea6b1c349 100644 (file)
@@ -46,9 +46,35 @@ from .. import exc
 from .. import util
 
 
-join_condition = util.langhelpers.public_factory(
-    Join._join_condition, ".sql.util.join_condition"
-)
+def join_condition(a, b, a_subset=None, consider_as_foreign_keys=None):
+    """Create a join condition between two tables or selectables.
+
+    e.g.::
+
+        join_condition(tablea, tableb)
+
+    would produce an expression along the lines of::
+
+        tablea.c.id==tableb.c.tablea_id
+
+    The join is determined based on the foreign key relationships
+    between the two selectables.   If there are multiple ways
+    to join, or no way to join, an error is raised.
+
+    :param a_subset: An optional expression that is a sub-component
+        of ``a``.  An attempt will be made to join to just this sub-component
+        first before looking at the full ``a`` construct, and if found
+        will be successful even if there are other ways to join to ``a``.
+        This allows the "right side" of a join to be passed thereby
+        providing a "natural join".
+
+    """
+    return Join._join_condition(
+        a,
+        b,
+        a_subset=a_subset,
+        consider_as_foreign_keys=consider_as_foreign_keys,
+    )
 
 
 def find_join_source(clauses, join_to):
index 464914d334feb09a0fa05123bd4209fa6b7837c4..f3a3debe0ed845f6946ca2bbce5d4a797da50d21 100644 (file)
@@ -140,14 +140,14 @@ def _formatannotation(annotation, base_module=None):
     """vendored from python 3.7"""
 
     if getattr(annotation, "__module__", None) == "typing":
-        return f'"{repr(annotation).replace("typing.", "")}"'
+        return f'"{repr(annotation).replace("typing.", "").replace("~", "")}"'
     if isinstance(annotation, type):
         if annotation.__module__ in ("builtins", base_module):
             return repr(annotation.__qualname__)
         return annotation.__module__ + "." + annotation.__qualname__
     elif isinstance(annotation, typing.TypeVar):
-        return f'"{annotation}"'
-    return repr(annotation)
+        return f'"{repr(annotation).replace("~", "")}"'
+    return f'"{repr(annotation).replace("~", "")}"'
 
 
 def inspect_formatargspec(
index 66c5308678241a7452eb07f05c7d7f1396aeb06f..d85b1261bc33f46fed8158933e16d01059dcd956 100644 (file)
@@ -36,6 +36,11 @@ from . import typing as compat_typing
 from .. import exc
 
 _T = TypeVar("_T")
+_F = TypeVar("_F", bound=Callable[..., Any])
+_MP = TypeVar("_MP", bound="memoized_property[Any]")
+_MA = TypeVar("_MA", bound="HasMemoized.memoized_attribute[Any]")
+_HP = TypeVar("_HP", bound="hybridproperty")
+_HM = TypeVar("_HM", bound="hybridmethod")
 
 
 def md5_hex(x):
@@ -234,103 +239,12 @@ def _exec_code_in_env(code, env, fn_name):
     return env[fn_name]
 
 
+_PF = TypeVar("_PF")
 _TE = TypeVar("_TE")
 
 _P = compat_typing.ParamSpec("_P")
 
 
-def public_factory(
-    target: typing.Callable[_P, _TE],
-    location: str,
-    class_location: Optional[str] = None,
-) -> typing.Callable[_P, _TE]:
-    """Produce a wrapping function for the given cls or classmethod.
-
-    Rationale here is so that the __init__ method of the
-    class can serve as documentation for the function.
-
-    """
-
-    if isinstance(target, type):
-        fn = target.__init__
-        callable_ = target
-        doc = (
-            "Construct a new :class:`%s` object. \n\n"
-            "This constructor is mirrored as a public API function; "
-            "see :func:`sqlalchemy%s` "
-            "for a full usage and argument description."
-            % (
-                class_location if class_location else ".%s" % target.__name__,
-                location,
-            )
-        )
-    else:
-        fn = callable_ = target
-        doc = (
-            "This function is mirrored; see :func:`sqlalchemy%s` "
-            "for a description of arguments." % location
-        )
-
-    location_name = location.split(".")[-1]
-    spec = compat.inspect_getfullargspec(fn)
-    del spec[0][0]
-    metadata = format_argspec_plus(spec, grouped=False)
-    metadata["name"] = location_name
-    code = (
-        """\
-def %(name)s%(grouped_args)s:
-    return cls(%(apply_kw)s)
-"""
-        % metadata
-    )
-    env = {
-        "cls": callable_,
-        "symbol": symbol,
-        "__name__": callable_.__module__,
-    }
-    exec(code, env)
-
-    decorated = env[location_name]
-
-    if hasattr(fn, "_linked_to"):
-        linked_to, linked_to_location = fn._linked_to
-        linked_to_doc = linked_to.__doc__
-        if class_location is None:
-            class_location = "%s.%s" % (target.__module__, target.__name__)
-
-        linked_to_doc = inject_docstring_text(
-            linked_to_doc,
-            ".. container:: inherited_member\n\n    "
-            "This documentation is inherited from :func:`sqlalchemy%s`; "
-            "this constructor, :func:`sqlalchemy%s`,   "
-            "creates a :class:`sqlalchemy%s` object.  See that class for "
-            "additional details describing this subclass."
-            % (linked_to_location, location, class_location),
-            1,
-        )
-        decorated.__doc__ = linked_to_doc
-    else:
-        decorated.__doc__ = fn.__doc__
-
-    decorated.__module__ = "sqlalchemy" + location.rsplit(".", 1)[0]
-    if decorated.__module__ not in sys.modules:
-        raise ImportError(
-            "public_factory location %s is not in sys.modules"
-            % (decorated.__module__,)
-        )
-
-    if hasattr(fn, "__func__"):
-        fn.__func__.__doc__ = doc
-        if not hasattr(fn.__func__, "_linked_to"):
-            fn.__func__._linked_to = (decorated, location)
-    else:
-        fn.__doc__ = doc
-        if not hasattr(fn, "_linked_to"):
-            fn._linked_to = (decorated, location)
-
-    return decorated
-
-
 class PluginLoader:
     def __init__(self, group, auto_fn=None):
         self.group = group
@@ -1182,14 +1096,26 @@ class HasMemoized:
         self.__dict__[key] = value
         self._memoized_keys |= {key}
 
-    class memoized_attribute:
+    class memoized_attribute(Generic[_T]):
         """A read-only @property that is only evaluated once."""
 
-        def __init__(self, fget, doc=None):
+        fget: Callable[..., _T]
+        __doc__: Optional[str]
+        __name__: str
+
+        def __init__(self, fget: Callable[..., _T], doc: Optional[str] = None):
             self.fget = fget
             self.__doc__ = doc or fget.__doc__
             self.__name__ = fget.__name__
 
+        @overload
+        def __get__(self: _MA, obj: None, cls: Any) -> _MA:
+            ...
+
+        @overload
+        def __get__(self, obj: Any, cls: Any) -> _T:
+            ...
+
         def __get__(self, obj, cls):
             if obj is None:
                 return self
@@ -1198,7 +1124,7 @@ class HasMemoized:
             return result
 
     @classmethod
-    def memoized_instancemethod(cls, fn):
+    def memoized_instancemethod(cls, fn: Any) -> Any:
         """Decorate a method memoize its return value."""
 
         def oneshot(self, *args, **kw):
index 8fc616326e07426e2e815dbb2ca7cf5e7a80b6d3..103e59d478fd33cd0b3a7a72a163d68f5c8d5ba7 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -119,7 +119,7 @@ per-file-ignores =
 # min mypy version 0.800
 strict = True
 incremental = True
-plugins = sqlalchemy.ext.mypy.plugin
+#plugins = sqlalchemy.ext.mypy.plugin
 
 [mypy-sqlalchemy.*]
 ignore_errors = True
index d0cc5eed953b85836f5348a2cd0df9d3adc87c45..99dbe2aef23607f3eac2626c5f54aa1bb754cfb9 100644 (file)
@@ -1,8 +1,17 @@
+import operator
+from typing import cast
+
 from sqlalchemy import Column
+from sqlalchemy.testing import eq_
 from sqlalchemy.testing import fixtures
 
 
 class TestGenerics(fixtures.TestBase):
     def test_traversible_is_generic(self):
+        """test #6759"""
         col = Column[int]
-        assert col is Column
+
+        # looked in the source for typing._GenericAlias.
+        # col.__origin__ is Column, but it's not public API.
+        # __reduce__ could change too but seems good enough for now
+        eq_(cast(object, col).__reduce__(), (operator.getitem, (Column, int)))
index 2a912f3492b25fd747f528fb607c558266db6b8f..a88b7c56c5ce8d20020371817b29e125f02ecef2 100644 (file)
@@ -1976,41 +1976,6 @@ class DuckTypeCollectionTest(fixtures.TestBase):
             is_(util.duck_type_collection(instance), None)
 
 
-class PublicFactoryTest(fixtures.TestBase):
-    def _fixture(self):
-        class Thingy:
-            def __init__(self, value):
-                "make a thingy"
-                self.value = value
-
-            @classmethod
-            def foobar(cls, x, y):
-                "do the foobar"
-                return Thingy(x + y)
-
-        return Thingy
-
-    def test_classmethod(self):
-        Thingy = self._fixture()
-        foob = langhelpers.public_factory(Thingy.foobar, ".sql.elements.foob")
-        eq_(foob(3, 4).value, 7)
-        eq_(foob(x=3, y=4).value, 7)
-        eq_(foob.__doc__, "do the foobar")
-        eq_(foob.__module__, "sqlalchemy.sql.elements")
-        assert Thingy.foobar.__doc__.startswith("This function is mirrored;")
-
-    def test_constructor(self):
-        Thingy = self._fixture()
-        foob = langhelpers.public_factory(Thingy, ".sql.elements.foob")
-        eq_(foob(7).value, 7)
-        eq_(foob(value=7).value, 7)
-        eq_(foob.__doc__, "make a thingy")
-        eq_(foob.__module__, "sqlalchemy.sql.elements")
-        assert Thingy.__init__.__doc__.startswith(
-            "Construct a new :class:`.Thingy` object."
-        )
-
-
 class ArgInspectionTest(fixtures.TestBase):
     def test_get_cls_kwargs(self):
         class A:
index fe7b22162f6762e5be2841e45d4cdf4a6e92b709..e8d75ac48cd97fb474099c4ffcfe6eb2ca3038d4 100644 (file)
@@ -1508,7 +1508,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL):
 
         def go():
             with testing.expect_deprecated(
-                "The AliasOption is not necessary for entities to be "
+                "The AliasOption object is not necessary for entities to be "
                 "matched up to a query"
             ):
                 result = (