diff options
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/base.py | 49 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/ddl.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/dml.py | 61 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 9 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/expression.py | 8 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 142 |
6 files changed, 218 insertions, 63 deletions
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py index 187651435..30d589258 100644 --- a/lib/sqlalchemy/sql/base.py +++ b/lib/sqlalchemy/sql/base.py @@ -16,6 +16,7 @@ import itertools from itertools import zip_longest import operator import re +import typing from . import roles from . import visitors @@ -29,6 +30,7 @@ from .. import exc from .. import util from ..util import HasMemoized from ..util import hybridmethod +from ..util import typing as compat_typing try: from sqlalchemy.cyextension.util import prefix_anon_map # noqa @@ -42,6 +44,10 @@ type_api = None NO_ARG = util.symbol("NO_ARG") +# if I use sqlalchemy.util.typing, which has the exact same +# symbols, mypy reports: "error: _Fn? not callable" +_Fn = typing.TypeVar("_Fn", bound=typing.Callable) + class Immutable: """mark a ClauseElement as 'immutable' when expressions are cloned.""" @@ -101,7 +107,16 @@ def _select_iterables(elements): ) -def _generative(fn): +_Self = typing.TypeVar("_Self", bound="_GenerativeType") +_Args = compat_typing.ParamSpec("_Args") + + +class _GenerativeType(compat_typing.Protocol): + def _generate(self: "_Self") -> "_Self": + ... + + +def _generative(fn: _Fn) -> _Fn: """non-caching _generative() decorator. This is basically the legacy decorator that copies the object and @@ -110,14 +125,14 @@ def _generative(fn): """ @util.decorator - def _generative(fn, self, *args, **kw): + def _generative( + fn: _Fn, self: _Self, *args: _Args.args, **kw: _Args.kwargs + ) -> _Self: """Mark a method as generative.""" self = self._generate() x = fn(self, *args, **kw) - assert ( - x is None or x is self - ), "generative methods must return None or self" + assert x is self, "generative methods must return self" return self decorated = _generative(fn) @@ -788,6 +803,9 @@ class ExecutableOption(HasCopyInternals): return c +SelfExecutable = typing.TypeVar("SelfExecutable", bound="Executable") + + class Executable(roles.StatementRole, Generative): """Mark a :class:`_expression.ClauseElement` as supporting execution. @@ -824,7 +842,7 @@ class Executable(roles.StatementRole, Generative): return self.__visit_name__ @_generative - def options(self, *options): + def options(self: SelfExecutable, *options) -> SelfExecutable: """Apply options to this statement. In the general sense, options are any kind of Python object @@ -857,9 +875,12 @@ class Executable(roles.StatementRole, Generative): coercions.expect(roles.ExecutableOptionRole, opt) for opt in options ) + return self @_generative - def _set_compile_options(self, compile_options): + def _set_compile_options( + self: SelfExecutable, compile_options + ) -> SelfExecutable: """Assign the compile options to a new value. :param compile_options: appropriate CacheableOptions structure @@ -867,15 +888,21 @@ class Executable(roles.StatementRole, Generative): """ self._compile_options = compile_options + return self @_generative - def _update_compile_options(self, options): + def _update_compile_options( + self: SelfExecutable, options + ) -> SelfExecutable: """update the _compile_options with new keys.""" self._compile_options += options + return self @_generative - def _add_context_option(self, callable_, cache_args): + def _add_context_option( + self: SelfExecutable, callable_, cache_args + ) -> SelfExecutable: """Add a context option to this statement. These are callable functions that will @@ -887,9 +914,10 @@ class Executable(roles.StatementRole, Generative): """ self._with_context_options += ((callable_, cache_args),) + return self @_generative - def execution_options(self, **kw): + def execution_options(self: SelfExecutable, **kw) -> SelfExecutable: """Set non-SQL options for the statement which take effect during execution. @@ -1004,6 +1032,7 @@ class Executable(roles.StatementRole, Generative): "on Connection.execution_options(), not per statement." ) self._execution_options = self._execution_options.union(kw) + return self def get_execution_options(self): """Get the non-SQL options which will take effect during execution. diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py index f415aeaff..ad22fa6da 100644 --- a/lib/sqlalchemy/sql/ddl.py +++ b/lib/sqlalchemy/sql/ddl.py @@ -9,6 +9,7 @@ Provides the hierarchy of DDL-defining schema items as well as routines to invoke them for a create/drop call. """ +import typing from . import roles from .base import _generative @@ -34,6 +35,9 @@ class _DDLCompiles(ClauseElement): raise NotImplementedError() +SelfDDLElement = typing.TypeVar("SelfDDLElement", bound="DDLElement") + + class DDLElement(roles.DDLRole, Executable, _DDLCompiles): """Base class for DDL expression constructs. @@ -77,7 +81,7 @@ class DDLElement(roles.DDLRole, Executable, _DDLCompiles): ) @_generative - def against(self, target): + def against(self: SelfDDLElement, target) -> SelfDDLElement: """Return a copy of this :class:`_schema.DDLElement` which will include the given target. @@ -111,9 +115,12 @@ class DDLElement(roles.DDLRole, Executable, _DDLCompiles): """ self.target = target + return self @_generative - def execute_if(self, dialect=None, callable_=None, state=None): + def execute_if( + self: SelfDDLElement, dialect=None, callable_=None, state=None + ) -> SelfDDLElement: r"""Return a callable that will execute this :class:`_ddl.DDLElement` conditionally within an event handler. @@ -181,6 +188,7 @@ class DDLElement(roles.DDLRole, Executable, _DDLCompiles): self.dialect = dialect self.callable_ = callable_ self.state = state + return self def _should_execute(self, target, bind, **kw): if isinstance(self.dialect, str): diff --git a/lib/sqlalchemy/sql/dml.py b/lib/sqlalchemy/sql/dml.py index 7b3716a68..ab0a05651 100644 --- a/lib/sqlalchemy/sql/dml.py +++ b/lib/sqlalchemy/sql/dml.py @@ -10,8 +10,8 @@ Provide :class:`_expression.Insert`, :class:`_expression.Update` and """ import collections.abc as collections_abc +import typing -from sqlalchemy.types import NullType from . import coercions from . import roles from . import util as sql_util @@ -30,6 +30,7 @@ from .elements import Null from .selectable import HasCTE from .selectable import HasPrefixes from .selectable import ReturnsRows +from .sqltypes import NullType from .visitors import InternalTraversal from .. import exc from .. import util @@ -210,6 +211,9 @@ class DeleteDMLState(DMLState): self._extra_froms = self._make_extra_froms(statement) +SelfUpdateBase = typing.TypeVar("SelfUpdateBase", bound="UpdateBase") + + class UpdateBase( roles.DMLRole, HasCTE, @@ -313,7 +317,7 @@ class UpdateBase( ) @_generative - def with_dialect_options(self, **opt): + def with_dialect_options(self: SelfUpdateBase, **opt) -> SelfUpdateBase: """Add dialect options to this INSERT/UPDATE/DELETE object. e.g.:: @@ -326,6 +330,7 @@ class UpdateBase( """ self._validate_dialect_kwargs(opt) + return self def _validate_dialect_kwargs_deprecated(self, dialect_kw): util.warn_deprecated_20( @@ -337,7 +342,7 @@ class UpdateBase( self._validate_dialect_kwargs(dialect_kw) @_generative - def returning(self, *cols): + def returning(self: SelfUpdateBase, *cols) -> SelfUpdateBase: r"""Add a :term:`RETURNING` or equivalent clause to this statement. e.g.: @@ -414,6 +419,7 @@ class UpdateBase( self._returning += tuple( coercions.expect(roles.ColumnsClauseRole, c) for c in cols ) + return self @property def _all_selected_columns(self): @@ -433,7 +439,9 @@ class UpdateBase( ).as_immutable() @_generative - def with_hint(self, text, selectable=None, dialect_name="*"): + def with_hint( + self: SelfUpdateBase, text, selectable=None, dialect_name="*" + ) -> SelfUpdateBase: """Add a table hint for a single table to this INSERT/UPDATE/DELETE statement. @@ -467,6 +475,10 @@ class UpdateBase( selectable = self.table self._hints = self._hints.union({(selectable, dialect_name): text}) + return self + + +SelfValuesBase = typing.TypeVar("SelfValuesBase", bound="ValuesBase") class ValuesBase(UpdateBase): @@ -506,7 +518,7 @@ class ValuesBase(UpdateBase): "values present", }, ) - def values(self, *args, **kwargs): + def values(self: SelfValuesBase, *args, **kwargs) -> SelfValuesBase: r"""Specify a fixed VALUES clause for an INSERT statement, or the SET clause for an UPDATE. @@ -643,7 +655,7 @@ class ValuesBase(UpdateBase): if arg and isinstance(arg[0], (list, dict, tuple)): self._multi_values += (arg,) - return + return self # tuple values arg = {c.key: value for c, value in zip(self.table.c, arg)} @@ -681,6 +693,7 @@ class ValuesBase(UpdateBase): self._values = self._values.union(arg) else: self._values = util.immutabledict(arg) + return self @_generative @_exclusive_against( @@ -690,7 +703,7 @@ class ValuesBase(UpdateBase): }, defaults={"_returning": _returning}, ) - def return_defaults(self, *cols): + def return_defaults(self: SelfValuesBase, *cols) -> SelfValuesBase: """Make use of a :term:`RETURNING` clause for the purpose of fetching server-side expressions and defaults. @@ -776,6 +789,10 @@ class ValuesBase(UpdateBase): """ self._return_defaults = True self._return_defaults_columns = cols + return self + + +SelfInsert = typing.TypeVar("SelfInsert", bound="Insert") class Insert(ValuesBase): @@ -918,7 +935,7 @@ class Insert(ValuesBase): self._return_defaults_columns = return_defaults @_generative - def inline(self): + def inline(self: SelfInsert) -> SelfInsert: """Make this :class:`_expression.Insert` construct "inline" . When set, no attempt will be made to retrieve the @@ -936,9 +953,12 @@ class Insert(ValuesBase): """ self._inline = True + return self @_generative - def from_select(self, names, select, include_defaults=True): + def from_select( + self: SelfInsert, names, select, include_defaults=True + ) -> SelfInsert: """Return a new :class:`_expression.Insert` construct which represents an ``INSERT...FROM SELECT`` statement. @@ -997,13 +1017,17 @@ class Insert(ValuesBase): self._inline = True self.include_insert_from_select_defaults = include_defaults self.select = coercions.expect(roles.DMLSelectRole, select) + return self + + +SelfDMLWhereBase = typing.TypeVar("SelfDMLWhereBase", bound="DMLWhereBase") class DMLWhereBase: _where_criteria = () @_generative - def where(self, *whereclause): + def where(self: SelfDMLWhereBase, *whereclause) -> SelfDMLWhereBase: """Return a new construct with the given expression(s) added to its WHERE clause, joined to the existing clause via AND, if any. @@ -1037,8 +1061,9 @@ class DMLWhereBase: for criterion in whereclause: where_criteria = coercions.expect(roles.WhereHavingRole, criterion) self._where_criteria += (where_criteria,) + return self - def filter(self, *criteria): + def filter(self: SelfDMLWhereBase, *criteria) -> SelfDMLWhereBase: """A synonym for the :meth:`_dml.DMLWhereBase.where` method. .. versionadded:: 1.4 @@ -1050,7 +1075,7 @@ class DMLWhereBase: def _filter_by_zero(self): return self.table - def filter_by(self, **kwargs): + def filter_by(self: SelfDMLWhereBase, **kwargs) -> SelfDMLWhereBase: r"""apply the given filtering criterion as a WHERE clause to this select. @@ -1081,6 +1106,9 @@ class DMLWhereBase: ) +SelfUpdate = typing.TypeVar("SelfUpdate", bound="Update") + + class Update(DMLWhereBase, ValuesBase): """Represent an Update construct. @@ -1261,7 +1289,7 @@ class Update(DMLWhereBase, ValuesBase): self._return_defaults = return_defaults @_generative - def ordered_values(self, *args): + def ordered_values(self: SelfUpdate, *args) -> SelfUpdate: """Specify the VALUES clause of this UPDATE statement with an explicit parameter ordering that will be maintained in the SET clause of the resulting UPDATE statement. @@ -1295,9 +1323,10 @@ class Update(DMLWhereBase, ValuesBase): kv_generator = DMLState.get_plugin_class(self)._get_crud_kv_pairs self._ordered_values = kv_generator(self, args) + return self @_generative - def inline(self): + def inline(self: SelfUpdate) -> SelfUpdate: """Make this :class:`_expression.Update` construct "inline" . When set, SQL defaults present on :class:`_schema.Column` @@ -1313,6 +1342,10 @@ class Update(DMLWhereBase, ValuesBase): """ self._inline = True + return self + + +SelfDelete = typing.TypeVar("SelfDelete", bound="Delete") class Delete(DMLWhereBase, UpdateBase): diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 37425345b..f6606e01d 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -13,6 +13,7 @@ import itertools import operator import re +import typing from . import coercions from . import operators @@ -1719,6 +1720,9 @@ class TypeClause(ClauseElement): self.type = type_ +SelfTextClause = typing.TypeVar("SelfTextClause", bound="TextClause") + + class TextClause( roles.DDLConstraintColumnRole, roles.DDLExpressionRole, @@ -1875,7 +1879,9 @@ class TextClause( return TextClause(text) @_generative - def bindparams(self, *binds, **names_to_values): + def bindparams( + self: SelfTextClause, *binds, **names_to_values + ) -> SelfTextClause: """Establish the values and/or types of bound parameters within this :class:`_expression.TextClause` construct. @@ -2000,6 +2006,7 @@ class TextClause( ) from err else: new_params[key] = existing._with_value(value, required=False) + return self @util.preload_module("sqlalchemy.sql.selectable") def columns(self, *cols, **types): diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 407f1dd33..89b7c6596 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -88,6 +88,8 @@ __all__ = [ ] +from typing import Callable + from .base import _from_objects from .base import _select_iterables from .base import ColumnCollection @@ -175,10 +177,8 @@ from .traversals import CacheKey from .visitors import Visitable from ..util.langhelpers import public_factory -# factory functions - these pull class-bound constructors and classmethods -# from SQL elements and selectables into public functions. This allows -# the functions to be available in the sqlalchemy.sql.* namespace and -# to be auto-cross-documenting from the function to the class itself. +# 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_") diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index 802576b89..8b35dc6ac 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -14,6 +14,9 @@ SQL tables and derived rowsets. import collections import itertools from operator import attrgetter +import typing +from typing import Type +from typing import Union from . import coercions from . import operators @@ -209,6 +212,9 @@ class Selectable(ReturnsRows): ) +SelfHasPrefixes = typing.TypeVar("SelfHasPrefixes", bound="HasPrefixes") + + class HasPrefixes: _prefixes = () @@ -222,7 +228,7 @@ class HasPrefixes: ":meth:`_expression.HasPrefixes.prefix_with`", ":paramref:`.HasPrefixes.prefix_with.*expr`", ) - def prefix_with(self, *expr, **kw): + def prefix_with(self: SelfHasPrefixes, *expr, **kw) -> SelfHasPrefixes: r"""Add one or more expressions following the statement keyword, i.e. SELECT, INSERT, UPDATE, or DELETE. Generative. @@ -255,6 +261,7 @@ class HasPrefixes: "Unsupported argument(s): %s" % ",".join(kw) ) self._setup_prefixes(expr, dialect) + return self def _setup_prefixes(self, prefixes, dialect=None): self._prefixes = self._prefixes + tuple( @@ -265,6 +272,9 @@ class HasPrefixes: ) +SelfHasSuffixes = typing.TypeVar("SelfHasSuffixes", bound="HasSuffixes") + + class HasSuffixes: _suffixes = () @@ -278,7 +288,7 @@ class HasSuffixes: ":meth:`_expression.HasSuffixes.suffix_with`", ":paramref:`.HasSuffixes.suffix_with.*expr`", ) - def suffix_with(self, *expr, **kw): + def suffix_with(self: SelfHasSuffixes, *expr, **kw) -> SelfHasSuffixes: r"""Add one or more expressions following the statement as a whole. This is used to support backend-specific suffix keywords on @@ -306,6 +316,7 @@ class HasSuffixes: "Unsupported argument(s): %s" % ",".join(kw) ) self._setup_suffixes(expr, dialect) + return self def _setup_suffixes(self, suffixes, dialect=None): self._suffixes = self._suffixes + tuple( @@ -316,6 +327,9 @@ class HasSuffixes: ) +SelfHasHints = typing.TypeVar("SelfHasHints", bound="HasHints") + + class HasHints: _hints = util.immutabledict() _statement_hints = () @@ -352,7 +366,9 @@ class HasHints: return self.with_hint(None, text, dialect_name) @_generative - def with_hint(self, selectable, text, dialect_name="*"): + def with_hint( + self: SelfHasHints, selectable, text, dialect_name="*" + ) -> SelfHasHints: r"""Add an indexing or other executional context hint for the given selectable to this :class:`_expression.Select` or other selectable object. @@ -398,6 +414,7 @@ class HasHints: ): text } ) + return self class FromClause(roles.AnonymizedFromClauseRole, Selectable): @@ -2082,6 +2099,9 @@ class CTE( return self._restates if self._restates is not None else self +SelfHasCTE = typing.TypeVar("SelfHasCTE", bound="HasCTE") + + class HasCTE(roles.HasCTERole): """Mixin that declares a class to include CTE support. @@ -2096,7 +2116,7 @@ class HasCTE(roles.HasCTERole): _independent_ctes = () @_generative - def add_cte(self, cte): + def add_cte(self: SelfHasCTE, cte) -> SelfHasCTE: """Add a :class:`_sql.CTE` to this statement object that will be independently rendered even if not referenced in the statement otherwise. @@ -2161,6 +2181,7 @@ class HasCTE(roles.HasCTERole): """ cte = coercions.expect(roles.IsCTERole, cte) self._independent_ctes += (cte,) + return self def cte(self, name=None, recursive=False, nesting=False): r"""Return a new :class:`_expression.CTE`, @@ -2759,6 +2780,9 @@ class ForUpdateArg(ClauseElement): self.of = None +SelfValues = typing.TypeVar("SelfValues", bound="Values") + + class Values(Generative, FromClause): """Represent a ``VALUES`` construct that can be used as a FROM element in a statement. @@ -2829,7 +2853,7 @@ class Values(Generative, FromClause): return [col.type for col in self._column_args] @_generative - def alias(self, name, **kw): + def alias(self: SelfValues, name, **kw) -> SelfValues: """Return a new :class:`_expression.Values` construct that is a copy of this one with the given name. @@ -2846,9 +2870,10 @@ class Values(Generative, FromClause): """ self.name = name self.named_with_column = self.name is not None + return self @_generative - def lateral(self, name=None): + def lateral(self: SelfValues, name=None) -> SelfValues: """Return a new :class:`_expression.Values` with the lateral flag set, so that it renders as LATERAL. @@ -2861,9 +2886,10 @@ class Values(Generative, FromClause): self._is_lateral = True if name is not None: self.name = name + return self @_generative - def data(self, values): + def data(self: SelfValues, values) -> SelfValues: """Return a new :class:`_expression.Values` construct, adding the given data to the data list. @@ -2879,6 +2905,7 @@ class Values(Generative, FromClause): """ self._data += (values,) + return self def _populate_column_collection(self): for c in self._column_args: @@ -3312,6 +3339,11 @@ class DeprecatedSelectBaseGenerations: self.group_by.non_generative(self, *clauses) +SelfGenerativeSelect = typing.TypeVar( + "SelfGenerativeSelect", bound="GenerativeSelect" +) + + class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): """Base class for SELECT statements where additional elements can be added. @@ -3371,13 +3403,13 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): @_generative def with_for_update( - self, + self: SelfGenerativeSelect, nowait=False, read=False, of=None, skip_locked=False, key_share=False, - ): + ) -> SelfGenerativeSelect: """Specify a ``FOR UPDATE`` clause for this :class:`_expression.GenerativeSelect`. @@ -3430,6 +3462,7 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): skip_locked=skip_locked, key_share=key_share, ) + return self def get_label_style(self): """ @@ -3573,7 +3606,7 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): ) @_generative - def limit(self, limit): + def limit(self: SelfGenerativeSelect, limit) -> SelfGenerativeSelect: """Return a new selectable with the given LIMIT criterion applied. @@ -3603,9 +3636,12 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): self._fetch_clause = self._fetch_clause_options = None self._limit_clause = self._offset_or_limit_clause(limit) + return self @_generative - def fetch(self, count, with_ties=False, percent=False): + def fetch( + self: SelfGenerativeSelect, count, with_ties=False, percent=False + ) -> SelfGenerativeSelect: """Return a new selectable with the given FETCH FIRST criterion applied. @@ -3653,9 +3689,10 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): "with_ties": with_ties, "percent": percent, } + return self @_generative - def offset(self, offset): + def offset(self: SelfGenerativeSelect, offset) -> SelfGenerativeSelect: """Return a new selectable with the given OFFSET criterion applied. @@ -3681,10 +3718,11 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): """ self._offset_clause = self._offset_or_limit_clause(offset) + return self @_generative @util.preload_module("sqlalchemy.sql.util") - def slice(self, start, stop): + def slice(self: SelfGenerativeSelect, start, stop) -> SelfGenerativeSelect: """Apply LIMIT / OFFSET to this statement based on a slice. The start and stop indices behave like the argument to Python's @@ -3728,9 +3766,10 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): self._limit_clause, self._offset_clause = sql_util._make_slice( self._limit_clause, self._offset_clause, start, stop ) + return self @_generative - def order_by(self, *clauses): + def order_by(self: SelfGenerativeSelect, *clauses) -> SelfGenerativeSelect: r"""Return a new selectable with the given list of ORDER BY criteria applied. @@ -3764,9 +3803,10 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): coercions.expect(roles.OrderByRole, clause) for clause in clauses ) + return self @_generative - def group_by(self, *clauses): + def group_by(self: SelfGenerativeSelect, *clauses) -> SelfGenerativeSelect: r"""Return a new selectable with the given list of GROUP BY criterion applied. @@ -3797,6 +3837,7 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase): coercions.expect(roles.GroupByRole, clause) for clause in clauses ) + return self @CompileState.plugin_for("default", "compound_select") @@ -4658,6 +4699,10 @@ class _MemoizedSelectEntities( ) = select_stmt._with_options = () +# TODO: use pep-673 when feasible +SelfSelect = typing.TypeVar("SelfSelect", bound="Select") + + class Select( HasPrefixes, HasSuffixes, @@ -4737,7 +4782,9 @@ class Select( ] @classmethod - def _create(cls, *entities) -> "Select": + def _create( + cls, *entities: Union[roles.ColumnsClauseRole, Type] + ) -> "Select": r"""Construct a new :class:`_expression.Select`. @@ -4788,7 +4835,7 @@ class Select( return self @classmethod - def _create_raw_select(cls, **kw): + 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 @@ -4873,7 +4920,9 @@ class Select( return meth(self, statement) @_generative - def join(self, target, onclause=None, isouter=False, full=False): + def join( + self: SelfSelect, target, onclause=None, isouter=False, full=False + ) -> SelfSelect: r"""Create a SQL JOIN against this :class:`_expression.Select` object's criterion and apply generatively, returning the newly resulting @@ -4939,6 +4988,7 @@ class Select( self._setup_joins += ( (target, onclause, None, {"isouter": isouter, "full": full}), ) + return self def outerjoin_from(self, from_, target, onclause=None, full=False): r"""Create a SQL LEFT OUTER JOIN against this :class:`_expression.Select` @@ -4955,8 +5005,13 @@ class Select( @_generative def join_from( - self, from_, target, onclause=None, isouter=False, full=False - ): + self: SelfSelect, + from_, + target, + onclause=None, + isouter=False, + full=False, + ) -> SelfSelect: r"""Create a SQL JOIN against this :class:`_expression.Select` object's criterion and apply generatively, returning the newly resulting @@ -5014,6 +5069,7 @@ class Select( self._setup_joins += ( (target, onclause, from_, {"isouter": isouter, "full": full}), ) + return self def outerjoin(self, target, onclause=None, full=False): """Create a left outer join. @@ -5211,7 +5267,7 @@ class Select( ) @_generative - def add_columns(self, *columns): + def add_columns(self: SelfSelect, *columns) -> SelfSelect: """Return a new :func:`_expression.select` construct with the given column expressions added to its columns clause. @@ -5233,6 +5289,7 @@ class Select( ) for column in columns ] + return self def _set_entities(self, entities): self._raw_columns = [ @@ -5297,7 +5354,7 @@ class Select( ) @_generative - def with_only_columns(self, *columns, **kw): + def with_only_columns(self: SelfSelect, *columns, **kw) -> SelfSelect: r"""Return a new :func:`_expression.select` construct with its columns clause replaced with the given columns. @@ -5372,6 +5429,7 @@ class Select( "columns", "Select.with_only_columns", columns ) ] + return self @property def whereclause(self): @@ -5393,7 +5451,7 @@ class Select( _whereclause = whereclause @_generative - def where(self, *whereclause): + def where(self: SelfSelect, *whereclause) -> SelfSelect: """Return a new :func:`_expression.select` construct with the given expression added to its WHERE clause, joined to the existing clause via AND, if any. @@ -5405,9 +5463,10 @@ class Select( for criterion in whereclause: where_criteria = coercions.expect(roles.WhereHavingRole, criterion) self._where_criteria += (where_criteria,) + return self @_generative - def having(self, having): + def having(self: SelfSelect, having) -> SelfSelect: """Return a new :func:`_expression.select` construct with the given expression added to its HAVING clause, joined to the existing clause via AND, if any. @@ -5416,9 +5475,10 @@ class Select( self._having_criteria += ( coercions.expect(roles.WhereHavingRole, having), ) + return self @_generative - def distinct(self, *expr): + def distinct(self: SelfSelect, *expr) -> SelfSelect: r"""Return a new :func:`_expression.select` construct which will apply DISTINCT to its columns clause. @@ -5437,9 +5497,10 @@ class Select( ) else: self._distinct = True + return self @_generative - def select_from(self, *froms): + def select_from(self: SelfSelect, *froms) -> SelfSelect: r"""Return a new :func:`_expression.select` construct with the given FROM expression(s) merged into its list of FROM objects. @@ -5480,9 +5541,10 @@ class Select( ) for fromclause in froms ) + return self @_generative - def correlate(self, *fromclauses): + def correlate(self: SelfSelect, *fromclauses) -> SelfSelect: r"""Return a new :class:`_expression.Select` which will correlate the given FROM clauses to that of an enclosing :class:`_expression.Select`. @@ -5541,9 +5603,10 @@ class Select( self._correlate = self._correlate + tuple( coercions.expect(roles.FromClauseRole, f) for f in fromclauses ) + return self @_generative - def correlate_except(self, *fromclauses): + def correlate_except(self: SelfSelect, *fromclauses) -> SelfSelect: r"""Return a new :class:`_expression.Select` which will omit the given FROM clauses from the auto-correlation process. @@ -5579,6 +5642,7 @@ class Select( self._correlate_except = (self._correlate_except or ()) + tuple( coercions.expect(roles.FromClauseRole, f) for f in fromclauses ) + return self @HasMemoized.memoized_attribute def selected_columns(self): @@ -5959,6 +6023,9 @@ class Select( return CompoundSelect._create_intersect_all(self, *other, **kwargs) +SelfScalarSelect = typing.TypeVar("SelfScalarSelect", bound="ScalarSelect") + + class ScalarSelect(roles.InElementRole, Generative, Grouping): """Represent a scalar subquery. @@ -5998,18 +6065,19 @@ class ScalarSelect(roles.InElementRole, Generative, Grouping): c = columns @_generative - def where(self, crit): + def where(self: SelfScalarSelect, crit) -> SelfScalarSelect: """Apply a WHERE clause to the SELECT statement referred to by this :class:`_expression.ScalarSelect`. """ self.element = self.element.where(crit) + return self def self_group(self, **kwargs): return self @_generative - def correlate(self, *fromclauses): + def correlate(self: SelfScalarSelect, *fromclauses) -> SelfScalarSelect: r"""Return a new :class:`_expression.ScalarSelect` which will correlate the given FROM clauses to that of an enclosing :class:`_expression.Select`. @@ -6039,9 +6107,12 @@ class ScalarSelect(roles.InElementRole, Generative, Grouping): """ self.element = self.element.correlate(*fromclauses) + return self @_generative - def correlate_except(self, *fromclauses): + def correlate_except( + self: SelfScalarSelect, *fromclauses + ) -> SelfScalarSelect: r"""Return a new :class:`_expression.ScalarSelect` which will omit the given FROM clauses from the auto-correlation process. @@ -6073,6 +6144,7 @@ class ScalarSelect(roles.InElementRole, Generative, Grouping): """ self.element = self.element.correlate_except(*fromclauses) + return self class Exists(UnaryExpression): @@ -6228,6 +6300,9 @@ class Exists(UnaryExpression): return e +SelfTextualSelect = typing.TypeVar("SelfTextualSelect", bound="TextualSelect") + + class TextualSelect(SelectBase): """Wrap a :class:`_expression.TextClause` construct within a :class:`_expression.SelectBase` @@ -6315,8 +6390,11 @@ class TextualSelect(SelectBase): return self @_generative - def bindparams(self, *binds, **bind_as_values): + def bindparams( + self: SelfTextualSelect, *binds, **bind_as_values + ) -> SelfTextualSelect: self.element = self.element.bindparams(*binds, **bind_as_values) + return self def _generate_fromclause_column_proxies(self, fromclause): fromclause._columns._populate_separate_keys( |
