From: Federico Caselli Date: Mon, 17 Oct 2022 20:02:13 +0000 (+0200) Subject: Improve typings of execution options X-Git-Tag: rel_2_0_0b3~9^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d10b62f54e6b9dd0613c0412b924c1b346ec1611;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Improve typings of execution options Fixes: #8605 Change-Id: I4aec83b9f321462427c3f4ac941c3b272255c088 --- diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index 7c5e62faeb..458663bb77 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -29,7 +29,7 @@ from ..engine import URL from ..sql.type_api import TypeEngine if typing.TYPE_CHECKING: - from ..engine.interfaces import _IsolationLevel + from ..engine.interfaces import IsolationLevel class PyODBCConnector(Connector): @@ -223,7 +223,7 @@ class PyODBCConnector(Connector): def get_isolation_level_values( self, dbapi_connection: interfaces.DBAPIConnection - ) -> List[_IsolationLevel]: + ) -> List[IsolationLevel]: return super().get_isolation_level_values(dbapi_connection) + [ # type: ignore # noqa: E501 "AUTOCOMMIT" ] @@ -231,7 +231,7 @@ class PyODBCConnector(Connector): def set_isolation_level( self, dbapi_connection: interfaces.DBAPIConnection, - level: _IsolationLevel, + level: IsolationLevel, ) -> None: # adjust for ConnectionFairy being present # allows attribute set e.g. "connection.autocommit = True" diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 8cbc0163c6..9dde9a445b 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -4,6 +4,9 @@ # # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php +"""Defines :class:`_engine.Connection` and :class:`_engine.Engine`. + +""" from __future__ import annotations import contextlib @@ -16,7 +19,6 @@ from typing import Iterable from typing import Iterator from typing import List from typing import Mapping -from typing import MutableMapping from typing import NoReturn from typing import Optional from typing import overload @@ -25,13 +27,13 @@ from typing import Type from typing import TypeVar from typing import Union -from .interfaces import _IsolationLevel from .interfaces import BindTyping from .interfaces import ConnectionEventsTarget from .interfaces import DBAPICursor from .interfaces import ExceptionContext from .interfaces import ExecuteStyle from .interfaces import ExecutionContext +from .interfaces import IsolationLevel from .util import _distill_params_20 from .util import _distill_raw_params from .util import TransactionalContext @@ -42,8 +44,6 @@ from .. import util from ..sql import compiler from ..sql import util as sql_util -_CompiledCacheType = MutableMapping[Any, "Compiled"] - if typing.TYPE_CHECKING: from . import CursorResult from . import ScalarResult @@ -55,9 +55,10 @@ if typing.TYPE_CHECKING: from .interfaces import _DBAPIAnyExecuteParams from .interfaces import _DBAPISingleExecuteParams from .interfaces import _ExecuteOptions - from .interfaces import _ExecuteOptionsParameter - from .interfaces import _SchemaTranslateMapType + from .interfaces import CompiledCacheType + from .interfaces import CoreExecuteOptionsParameter from .interfaces import Dialect + from .interfaces import SchemaTranslateMapType from .reflection import Inspector # noqa from .url import URL from ..event import dispatcher @@ -77,9 +78,6 @@ if typing.TYPE_CHECKING: from ..sql.schema import SchemaItem from ..sql.selectable import TypedReturnsRows -"""Defines :class:`_engine.Connection` and :class:`_engine.Engine`. - -""" _T = TypeVar("_T", bound=Any) _EMPTY_EXECUTION_OPTS: _ExecuteOptions = util.EMPTY_DICT @@ -206,7 +204,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self.engine.logger.debug(message, *arg, **kw) @property - def _schema_translate_map(self) -> Optional[_SchemaTranslateMapType]: + def _schema_translate_map(self) -> Optional[SchemaTranslateMapType]: return self._execution_options.get("schema_translate_map", None) def schema_for_object(self, obj: HasSchemaAttr) -> Optional[str]: @@ -217,7 +215,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): name = obj.schema schema_translate_map: Optional[ - Mapping[Optional[str], str] + SchemaTranslateMapType ] = self._execution_options.get("schema_translate_map", None) if ( @@ -235,6 +233,27 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): def __exit__(self, type_: Any, value: Any, traceback: Any) -> None: self.close() + @overload + def execution_options( + self, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + no_parameters: bool = False, + stream_results: bool = False, + max_row_buffer: int = ..., + yield_per: int = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + **opt: Any, + ) -> Connection: + ... + + @overload + def execution_options(self, **opt: Any) -> Connection: + ... + def execution_options(self, **opt: Any) -> Connection: r"""Set non-SQL options for the connection which take effect during execution. @@ -440,7 +459,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` describing the ORM version of ``yield_per`` - :param insertmanyvalues_page_size: number of rows to format into an + :param insertmanyvalues_page_size: Available on: :class:`_engine.Connection`, + :class:`_engine.Engine`. Number of rows to format into an INSERT statement when the statement uses "insertmanyvalues" mode, which is a paged form of bulk insert that is used for many backends when using :term:`executemany` execution typically in conjunction @@ -560,7 +580,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): else: return self._dbapi_connection - def get_isolation_level(self) -> _IsolationLevel: + def get_isolation_level(self) -> IsolationLevel: """Return the current isolation level assigned to this :class:`_engine.Connection`. @@ -600,7 +620,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self._handle_dbapi_exception(e, None, None, None, None) @property - def default_isolation_level(self) -> Optional[_IsolationLevel]: + def default_isolation_level(self) -> Optional[IsolationLevel]: """The default isolation level assigned to this :class:`_engine.Connection`. @@ -1239,7 +1259,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: TypedReturnsRows[Tuple[_T]], parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Optional[_T]: ... @@ -1249,7 +1269,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Any: ... @@ -1258,7 +1278,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Any: r"""Executes a SQL statement construct and returns a scalar object. @@ -1288,7 +1308,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: TypedReturnsRows[Tuple[_T]], parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[_T]: ... @@ -1298,7 +1318,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[Any]: ... @@ -1307,7 +1327,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[Any]: """Executes and returns a scalar result set, which yields scalar values from the first column of each row. @@ -1333,7 +1353,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: TypedReturnsRows[_T], parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[_T]: ... @@ -1343,7 +1363,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: ... @@ -1352,7 +1372,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: r"""Executes a SQL statement construct and returns a :class:`_engine.CursorResult`. @@ -1401,7 +1421,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, func: FunctionElement[Any], distilled_parameters: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> CursorResult[Any]: """Execute a sql.FunctionElement object.""" @@ -1413,7 +1433,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, default: DefaultGenerator, distilled_parameters: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> Any: """Execute a schema.ColumnDefault object.""" @@ -1472,7 +1492,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, ddl: ExecutableDDLElement, distilled_parameters: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> CursorResult[Any]: """Execute a schema.DDL object.""" @@ -1569,7 +1589,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, elem: Executable, distilled_parameters: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> CursorResult[Any]: """Execute a sql.ClauseElement object.""" @@ -1603,7 +1623,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): "schema_translate_map", None ) - compiled_cache: Optional[_CompiledCacheType] = execution_options.get( + compiled_cache: Optional[CompiledCacheType] = execution_options.get( "compiled_cache", self.engine._compiled_cache ) @@ -1642,7 +1662,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, compiled: Compiled, distilled_parameters: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter = _EMPTY_EXECUTION_OPTS, + execution_options: CoreExecuteOptionsParameter = _EMPTY_EXECUTION_OPTS, ) -> CursorResult[Any]: """Execute a sql.Compiled object. @@ -1692,7 +1712,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): self, statement: str, parameters: Optional[_DBAPIAnyExecuteParams] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: r"""Executes a SQL statement construct and returns a :class:`_engine.CursorResult`. @@ -2882,7 +2902,7 @@ class Engine( dispatch: dispatcher[ConnectionEventsTarget] - _compiled_cache: Optional[_CompiledCacheType] + _compiled_cache: Optional[CompiledCacheType] _execution_options: _ExecuteOptions = _EMPTY_EXECUTION_OPTS _has_events: bool = False @@ -2890,7 +2910,7 @@ class Engine( _sqla_logger_namespace: str = "sqlalchemy.engine.Engine" _is_future: bool = False - _schema_translate_map: Optional[_SchemaTranslateMapType] = None + _schema_translate_map: Optional[SchemaTranslateMapType] = None _option_cls: Type[OptionEngine] dialect: Dialect @@ -2980,6 +3000,23 @@ class Engine( self._execution_options = self._execution_options.union(opt) self.dialect.set_engine_execution_options(self, opt) + @overload + def execution_options( + self, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + **opt: Any, + ) -> OptionEngine: + ... + + @overload + def execution_options(self, **opt: Any) -> OptionEngine: + ... + def execution_options(self, **opt: Any) -> OptionEngine: """Return a new :class:`_engine.Engine` that will provide :class:`_engine.Connection` objects with the given execution options. @@ -3240,7 +3277,7 @@ class OptionEngineMixin(log.Identified): _sa_propagate_class_events = False dispatch: dispatcher[ConnectionEventsTarget] - _compiled_cache: Optional[_CompiledCacheType] + _compiled_cache: Optional[CompiledCacheType] dialect: Dialect pool: Pool url: URL @@ -3248,7 +3285,7 @@ class OptionEngineMixin(log.Identified): echo: log.echo_property def __init__( - self, proxied: Engine, execution_options: _ExecuteOptionsParameter + self, proxied: Engine, execution_options: CoreExecuteOptionsParameter ): self._proxied = proxied self.url = proxied.url diff --git a/lib/sqlalchemy/engine/create.py b/lib/sqlalchemy/engine/create.py index ef54639723..1ad8c90e76 100644 --- a/lib/sqlalchemy/engine/create.py +++ b/lib/sqlalchemy/engine/create.py @@ -33,8 +33,8 @@ from ..sql import compiler if typing.TYPE_CHECKING: from .base import Engine from .interfaces import _ExecuteOptions - from .interfaces import _IsolationLevel from .interfaces import _ParamStyle + from .interfaces import IsolationLevel from .url import URL from ..log import _EchoFlagType from ..pool import _CreatorFnType @@ -59,7 +59,7 @@ def create_engine( hide_parameters: bool = ..., implicit_returning: Literal[True] = ..., insertmanyvalues_page_size: int = ..., - isolation_level: _IsolationLevel = ..., + isolation_level: IsolationLevel = ..., json_deserializer: Callable[..., Any] = ..., json_serializer: Callable[..., Any] = ..., label_length: Optional[int] = ..., diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 71ceb3301c..e5d613dd58 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -75,10 +75,10 @@ if typing.TYPE_CHECKING: from .interfaces import _DBAPICursorDescription from .interfaces import _DBAPIMultiExecuteParams from .interfaces import _ExecuteOptions - from .interfaces import _IsolationLevel from .interfaces import _MutableCoreSingleExecuteParams from .interfaces import _ParamStyle from .interfaces import DBAPIConnection + from .interfaces import IsolationLevel from .row import Row from .url import URL from ..event import _ListenerFnType @@ -280,7 +280,7 @@ class DefaultDialect(Dialect): def __init__( self, paramstyle: Optional[_ParamStyle] = None, - isolation_level: Optional[_IsolationLevel] = None, + isolation_level: Optional[IsolationLevel] = None, dbapi: Optional[ModuleType] = None, implicit_returning: Literal[True] = True, supports_native_boolean: Optional[bool] = None, @@ -582,13 +582,13 @@ class DefaultDialect(Dialect): return [[], opts] def set_engine_execution_options( - self, engine: Engine, opts: Mapping[str, str] + self, engine: Engine, opts: Mapping[str, Any] ) -> None: supported_names = set(self.connection_characteristics).intersection( opts ) if supported_names: - characteristics: Mapping[str, str] = util.immutabledict( + characteristics: Mapping[str, Any] = util.immutabledict( (name, opts[name]) for name in supported_names ) @@ -599,13 +599,13 @@ class DefaultDialect(Dialect): ) def set_connection_execution_options( - self, connection: Connection, opts: Mapping[str, str] + self, connection: Connection, opts: Mapping[str, Any] ) -> None: supported_names = set(self.connection_characteristics).intersection( opts ) if supported_names: - characteristics: Mapping[str, str] = util.immutabledict( + characteristics: Mapping[str, Any] = util.immutabledict( (name, opts[name]) for name in supported_names ) self._set_connection_characteristics(connection, characteristics) diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py index fb59acbd06..7395b2fa48 100644 --- a/lib/sqlalchemy/engine/interfaces.py +++ b/lib/sqlalchemy/engine/interfaces.py @@ -250,10 +250,8 @@ _AnySingleExecuteParams = _DBAPISingleExecuteParams _AnyMultiExecuteParams = _DBAPIMultiExecuteParams _AnyExecuteParams = _DBAPIAnyExecuteParams - -_ExecuteOptions = immutabledict[str, Any] -_ExecuteOptionsParameter = Mapping[str, Any] -_SchemaTranslateMapType = Mapping[str, str] +CompiledCacheType = MutableMapping[Any, "Compiled"] +SchemaTranslateMapType = Mapping[Optional[str], Optional[str]] _ImmutableExecuteOptions = immutabledict[str, Any] @@ -261,7 +259,7 @@ _ParamStyle = Literal["qmark", "numeric", "named", "format", "pyformat"] _GenericSetInputSizesType = List[Tuple[str, Any, "TypeEngine[Any]"]] -_IsolationLevel = Literal[ +IsolationLevel = Literal[ "SERIALIZABLE", "REPEATABLE READ", "READ COMMITTED", @@ -270,6 +268,24 @@ _IsolationLevel = Literal[ ] +class _CoreKnownExecutionOptions(TypedDict, total=False): + compiled_cache: Optional[CompiledCacheType] + logging_token: str + isolation_level: IsolationLevel + no_parameters: bool + stream_results: bool + max_row_buffer: int + yield_per: int + insertmanyvalues_page_size: int + schema_translate_map: Optional[SchemaTranslateMapType] + + +_ExecuteOptions = immutabledict[str, Any] +CoreExecuteOptionsParameter = Union[ + _CoreKnownExecutionOptions, Mapping[str, Any] +] + + class ReflectedIdentity(TypedDict): """represent the reflected IDENTITY structure of a column, corresponding to the :class:`_schema.Identity` construct. @@ -735,11 +751,11 @@ class Dialect(EventTarget): # NOTE: this does not take into effect engine-level isolation level. # not clear if this should be changed, seems like it should - default_isolation_level: Optional[_IsolationLevel] + default_isolation_level: Optional[IsolationLevel] """the isolation that is implicitly present on new connections""" # create_engine() -> isolation_level currently goes here - _on_connect_isolation_level: Optional[_IsolationLevel] + _on_connect_isolation_level: Optional[IsolationLevel] execution_ctx_cls: Type["ExecutionContext"] """a :class:`.ExecutionContext` class used to handle statement execution""" @@ -2333,7 +2349,7 @@ class Dialect(EventTarget): raise NotImplementedError() def set_isolation_level( - self, dbapi_connection: DBAPIConnection, level: _IsolationLevel + self, dbapi_connection: DBAPIConnection, level: IsolationLevel ) -> None: """Given a DBAPI connection, set its isolation level. @@ -2368,7 +2384,7 @@ class Dialect(EventTarget): def get_isolation_level( self, dbapi_connection: DBAPIConnection - ) -> _IsolationLevel: + ) -> IsolationLevel: """Given a DBAPI connection, return its isolation level. When working with a :class:`_engine.Connection` object, @@ -2403,7 +2419,7 @@ class Dialect(EventTarget): def get_default_isolation_level( self, dbapi_conn: DBAPIConnection - ) -> _IsolationLevel: + ) -> IsolationLevel: """Given a DBAPI connection, return its isolation level, or a default isolation level if one cannot be retrieved. @@ -2425,7 +2441,7 @@ class Dialect(EventTarget): def get_isolation_level_values( self, dbapi_conn: DBAPIConnection - ) -> List[_IsolationLevel]: + ) -> List[IsolationLevel]: """return a sequence of string isolation level names that are accepted by this dialect. @@ -2468,7 +2484,7 @@ class Dialect(EventTarget): raise NotImplementedError() def _assert_and_set_isolation_level( - self, dbapi_conn: DBAPIConnection, level: _IsolationLevel + self, dbapi_conn: DBAPIConnection, level: IsolationLevel ) -> None: raise NotImplementedError() @@ -2571,7 +2587,7 @@ class Dialect(EventTarget): raise NotImplementedError() def set_engine_execution_options( - self, engine: Engine, opt: _ExecuteOptionsParameter + self, engine: Engine, opts: CoreExecuteOptionsParameter ) -> None: """Establish execution options for a given engine. @@ -2585,7 +2601,7 @@ class Dialect(EventTarget): raise NotImplementedError() def set_connection_execution_options( - self, connection: Connection, opt: _ExecuteOptionsParameter + self, connection: Connection, opts: CoreExecuteOptionsParameter ) -> None: """Establish execution options for a given connection. diff --git a/lib/sqlalchemy/engine/mock.py b/lib/sqlalchemy/engine/mock.py index 77dc21d181..cf01c72540 100644 --- a/lib/sqlalchemy/engine/mock.py +++ b/lib/sqlalchemy/engine/mock.py @@ -23,7 +23,7 @@ from .. import util if typing.TYPE_CHECKING: from .base import Engine from .interfaces import _CoreAnyExecuteParams - from .interfaces import _ExecuteOptionsParameter + from .interfaces import CoreExecuteOptionsParameter from .interfaces import Dialect from .url import URL from ..sql.base import Executable @@ -64,7 +64,7 @@ class MockConnection: self, obj: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Any: return self._execute_impl(obj, parameters) diff --git a/lib/sqlalchemy/ext/asyncio/engine.py b/lib/sqlalchemy/ext/asyncio/engine.py index 19ef4d3a1d..3890888754 100644 --- a/lib/sqlalchemy/ext/asyncio/engine.py +++ b/lib/sqlalchemy/ext/asyncio/engine.py @@ -42,9 +42,11 @@ if TYPE_CHECKING: from ...engine.interfaces import _CoreSingleExecuteParams from ...engine.interfaces import _DBAPIAnyExecuteParams from ...engine.interfaces import _ExecuteOptions - from ...engine.interfaces import _ExecuteOptionsParameter - from ...engine.interfaces import _IsolationLevel + from ...engine.interfaces import CompiledCacheType + from ...engine.interfaces import CoreExecuteOptionsParameter from ...engine.interfaces import Dialect + from ...engine.interfaces import IsolationLevel + from ...engine.interfaces import SchemaTranslateMapType from ...engine.result import ScalarResult from ...engine.url import URL from ...pool import Pool @@ -291,7 +293,7 @@ class AsyncConnection( self._proxied.invalidate, exception=exception ) - async def get_isolation_level(self) -> _IsolationLevel: + async def get_isolation_level(self) -> IsolationLevel: return await greenlet_spawn(self._proxied.get_isolation_level) def in_transaction(self) -> bool: @@ -345,6 +347,27 @@ class AsyncConnection( else: return None + @overload + async def execution_options( + self, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + no_parameters: bool = False, + stream_results: bool = False, + max_row_buffer: int = ..., + yield_per: int = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + **opt: Any, + ) -> AsyncConnection: + ... + + @overload + async def execution_options(self, **opt: Any) -> AsyncConnection: + ... + async def execution_options(self, **opt: Any) -> AsyncConnection: r"""Set non-SQL options for the connection which take effect during execution. @@ -405,7 +428,7 @@ class AsyncConnection( self, statement: str, parameters: Optional[_DBAPIAnyExecuteParams] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: r"""Executes a driver-level SQL string and return buffered :class:`_engine.Result`. @@ -428,7 +451,7 @@ class AsyncConnection( statement: TypedReturnsRows[_T], parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncResult[_T]: ... @@ -438,7 +461,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncResult[Any]: ... @@ -447,7 +470,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncResult[Any]: """Execute a statement and return a streaming :class:`_asyncio.AsyncResult` object.""" @@ -472,7 +495,7 @@ class AsyncConnection( statement: TypedReturnsRows[_T], parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[_T]: ... @@ -482,7 +505,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: ... @@ -491,7 +514,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> CursorResult[Any]: r"""Executes a SQL statement construct and return a buffered :class:`_engine.Result`. @@ -539,7 +562,7 @@ class AsyncConnection( statement: TypedReturnsRows[Tuple[_T]], parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Optional[_T]: ... @@ -549,7 +572,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Any: ... @@ -558,7 +581,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> Any: r"""Executes a SQL statement construct and returns a scalar object. @@ -581,7 +604,7 @@ class AsyncConnection( statement: TypedReturnsRows[Tuple[_T]], parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[_T]: ... @@ -591,7 +614,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[Any]: ... @@ -600,7 +623,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> ScalarResult[Any]: r"""Executes a SQL statement construct and returns a scalar objects. @@ -624,7 +647,7 @@ class AsyncConnection( statement: TypedReturnsRows[Tuple[_T]], parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncScalarResult[_T]: ... @@ -634,7 +657,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncScalarResult[Any]: ... @@ -643,7 +666,7 @@ class AsyncConnection( statement: Executable, parameters: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[CoreExecuteOptionsParameter] = None, ) -> AsyncScalarResult[Any]: r"""Executes a SQL statement and returns a streaming scalar result object. @@ -926,6 +949,23 @@ class AsyncEngine(ProxyComparable[Engine], AsyncConnectable): """ return await greenlet_spawn(self.sync_engine.raw_connection) + @overload + def execution_options( + self, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + **opt: Any, + ) -> AsyncEngine: + ... + + @overload + def execution_options(self, **opt: Any) -> AsyncEngine: + ... + def execution_options(self, **opt: Any) -> AsyncEngine: """Return a new :class:`_asyncio.AsyncEngine` that will provide :class:`_asyncio.AsyncConnection` objects with the given execution diff --git a/lib/sqlalchemy/ext/asyncio/scoping.py b/lib/sqlalchemy/ext/asyncio/scoping.py index a2fec1c246..daaaaea483 100644 --- a/lib/sqlalchemy/ext/asyncio/scoping.py +++ b/lib/sqlalchemy/ext/asyncio/scoping.py @@ -44,10 +44,10 @@ if TYPE_CHECKING: from ...engine import RowMapping from ...engine.interfaces import _CoreAnyExecuteParams from ...engine.interfaces import _CoreSingleExecuteParams - from ...engine.interfaces import _ExecuteOptionsParameter from ...engine.result import ScalarResult from ...orm._typing import _IdentityKeyType from ...orm._typing import _O + from ...orm._typing import OrmExecuteOptionsParameter from ...orm.interfaces import ORMOption from ...orm.session import _BindArguments from ...orm.session import _EntityBindKey @@ -219,7 +219,7 @@ class async_scoped_session(Generic[_AS]): populate_existing: bool = False, with_for_update: Optional[ForUpdateArg] = None, identity_token: Optional[Any] = None, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, ) -> Optional[_O]: r"""Return an instance based on the given primary key identifier, or ``None`` if not found. @@ -518,7 +518,7 @@ class async_scoped_session(Generic[_AS]): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -531,7 +531,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -543,7 +543,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Result[Any]: @@ -980,7 +980,7 @@ class async_scoped_session(Generic[_AS]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Optional[_T]: @@ -992,7 +992,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -1003,7 +1003,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -1035,7 +1035,7 @@ class async_scoped_session(Generic[_AS]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[_T]: @@ -1047,7 +1047,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -1058,7 +1058,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -1096,7 +1096,7 @@ class async_scoped_session(Generic[_AS]): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[_T]: @@ -1108,7 +1108,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[Any]: @@ -1119,7 +1119,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[Any]: @@ -1148,7 +1148,7 @@ class async_scoped_session(Generic[_AS]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[_T]: @@ -1160,7 +1160,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[Any]: @@ -1171,7 +1171,7 @@ class async_scoped_session(Generic[_AS]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[Any]: diff --git a/lib/sqlalchemy/ext/asyncio/session.py b/lib/sqlalchemy/ext/asyncio/session.py index e17b729bfa..0aa9661e9f 100644 --- a/lib/sqlalchemy/ext/asyncio/session.py +++ b/lib/sqlalchemy/ext/asyncio/session.py @@ -47,10 +47,10 @@ if TYPE_CHECKING: from ...engine import ScalarResult from ...engine.interfaces import _CoreAnyExecuteParams from ...engine.interfaces import _CoreSingleExecuteParams - from ...engine.interfaces import _ExecuteOptionsParameter from ...event import dispatcher from ...orm._typing import _IdentityKeyType from ...orm._typing import _O + from ...orm._typing import OrmExecuteOptionsParameter from ...orm.identity import IdentityMap from ...orm.interfaces import ORMOption from ...orm.session import _BindArguments @@ -264,7 +264,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -277,7 +277,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -289,7 +289,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Result[Any]: @@ -325,7 +325,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Optional[_T]: @@ -337,7 +337,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -348,7 +348,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -383,7 +383,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[_T]: @@ -395,7 +395,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -406,7 +406,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -442,7 +442,7 @@ class AsyncSession(ReversibleProxy[Session]): populate_existing: bool = False, with_for_update: Optional[ForUpdateArg] = None, identity_token: Optional[Any] = None, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, ) -> Optional[_O]: """Return an instance based on the given primary key identifier, @@ -472,7 +472,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[_T]: @@ -484,7 +484,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[Any]: @@ -495,7 +495,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncResult[Any]: @@ -528,7 +528,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[_T]: @@ -540,7 +540,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[Any]: @@ -551,7 +551,7 @@ class AsyncSession(ReversibleProxy[Session]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> AsyncScalarResult[Any]: diff --git a/lib/sqlalchemy/orm/_typing.py b/lib/sqlalchemy/orm/_typing.py index 06df0731d2..76483265d4 100644 --- a/lib/sqlalchemy/orm/_typing.py +++ b/lib/sqlalchemy/orm/_typing.py @@ -1,3 +1,10 @@ +# orm/_typing.py +# Copyright (C) 2022 the SQLAlchemy authors and contributors +# +# +# This module is part of SQLAlchemy and is released under +# the MIT License: https://www.opensource.org/licenses/mit-license.php + from __future__ import annotations import operator @@ -11,7 +18,12 @@ from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +from ..engine.interfaces import _CoreKnownExecutionOptions from ..sql import roles +from ..sql._orm_types import DMLStrategyArgument as DMLStrategyArgument +from ..sql._orm_types import ( + SynchronizeSessionArgument as SynchronizeSessionArgument, +) from ..sql._typing import _HasClauseElement from ..sql.elements import ColumnElement from ..util.typing import Protocol @@ -80,6 +92,20 @@ _ORMColumnExprArgument = Union[ _ORMCOLEXPR = TypeVar("_ORMCOLEXPR", bound=ColumnElement[Any]) +class _OrmKnownExecutionOptions(_CoreKnownExecutionOptions, total=False): + populate_existing: bool + autoflush: bool + synchronize_session: SynchronizeSessionArgument + dml_strategy: DMLStrategyArgument + is_delete_using: bool + is_update_from: bool + + +OrmExecuteOptionsParameter = Union[ + _OrmKnownExecutionOptions, Mapping[str, Any] +] + + class _ORMAdapterProto(Protocol): """protocol for the :class:`.AliasedInsp._orm_adapt_element` method which is a synonym for :class:`.AliasedInsp._adapt_element`. diff --git a/lib/sqlalchemy/orm/bulk_persistence.py b/lib/sqlalchemy/orm/bulk_persistence.py index af5bf6b6a1..651533db6a 100644 --- a/lib/sqlalchemy/orm/bulk_persistence.py +++ b/lib/sqlalchemy/orm/bulk_persistence.py @@ -55,6 +55,9 @@ from ..util import EMPTY_DICT from ..util.typing import Literal if TYPE_CHECKING: + from ._typing import DMLStrategyArgument + from ._typing import OrmExecuteOptionsParameter + from ._typing import SynchronizeSessionArgument from .mapper import Mapper from .session import _BindArguments from .session import ORMExecuteState @@ -64,15 +67,10 @@ if TYPE_CHECKING: from ..engine import Connection from ..engine import cursor from ..engine.interfaces import _CoreAnyExecuteParams - from ..engine.interfaces import _ExecuteOptionsParameter _O = TypeVar("_O", bound=object) -_SynchronizeSessionArgument = Literal[False, "auto", "evaluate", "fetch"] -_DMLStrategyArgument = Literal["bulk", "raw", "orm", "auto"] - - @overload def _bulk_insert( mapper: Mapper[_O], @@ -82,7 +80,7 @@ def _bulk_insert( return_defaults: bool, render_nulls: bool, use_orm_insert_stmt: Literal[None] = ..., - execution_options: Optional[_ExecuteOptionsParameter] = ..., + execution_options: Optional[OrmExecuteOptionsParameter] = ..., ) -> None: ... @@ -96,7 +94,7 @@ def _bulk_insert( return_defaults: bool, render_nulls: bool, use_orm_insert_stmt: Optional[dml.Insert] = ..., - execution_options: Optional[_ExecuteOptionsParameter] = ..., + execution_options: Optional[OrmExecuteOptionsParameter] = ..., ) -> cursor.CursorResult[Any]: ... @@ -109,7 +107,7 @@ def _bulk_insert( return_defaults: bool, render_nulls: bool, use_orm_insert_stmt: Optional[dml.Insert] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[OrmExecuteOptionsParameter] = None, ) -> Optional[cursor.CursorResult[Any]]: base_mapper = mapper.base_mapper @@ -547,8 +545,8 @@ class ORMDMLState(AbstractORMCompileState): class BulkUDCompileState(ORMDMLState): class default_update_options(Options): - _dml_strategy: _DMLStrategyArgument = "auto" - _synchronize_session: _SynchronizeSessionArgument = "auto" + _dml_strategy: DMLStrategyArgument = "auto" + _synchronize_session: SynchronizeSessionArgument = "auto" _can_use_returning: bool = False _is_delete_using: bool = False _is_update_from: bool = False @@ -1075,7 +1073,7 @@ class BulkUDCompileState(ORMDMLState): @CompileState.plugin_for("orm", "insert") class BulkORMInsert(ORMDMLState, InsertDMLState): class default_insert_options(Options): - _dml_strategy: _DMLStrategyArgument = "auto" + _dml_strategy: DMLStrategyArgument = "auto" _render_nulls: bool = False _return_defaults: bool = False _subject_mapper: Optional[Mapper[Any]] = None @@ -1163,7 +1161,7 @@ class BulkORMInsert(ORMDMLState, InsertDMLState): session: Session, statement: dml.Insert, params: _CoreAnyExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: OrmExecuteOptionsParameter, bind_arguments: _BindArguments, conn: Connection, ) -> _result.Result: @@ -1471,7 +1469,7 @@ class BulkORMUpdate(BulkUDCompileState, UpdateDMLState): session: Session, statement: dml.Update, params: _CoreAnyExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: OrmExecuteOptionsParameter, bind_arguments: _BindArguments, conn: Connection, ) -> _result.Result: @@ -1808,7 +1806,7 @@ class BulkORMDelete(BulkUDCompileState, DeleteDMLState): session: Session, statement: dml.Delete, params: _CoreAnyExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: OrmExecuteOptionsParameter, bind_arguments: _BindArguments, conn: Connection, ) -> _result.Result: diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py index 8dca837569..60ccecdb7c 100644 --- a/lib/sqlalchemy/orm/context.py +++ b/lib/sqlalchemy/orm/context.py @@ -68,6 +68,7 @@ from ..sql.visitors import InternalTraversal if TYPE_CHECKING: from ._typing import _InternalEntityType + from ._typing import OrmExecuteOptionsParameter from .loading import PostLoad from .mapper import Mapper from .query import Query @@ -75,7 +76,6 @@ if TYPE_CHECKING: from .session import Session from ..engine import Result from ..engine.interfaces import _CoreSingleExecuteParams - from ..engine.interfaces import _ExecuteOptionsParameter from ..sql._typing import _ColumnsClauseArgument from ..sql.compiler import SQLCompiler from ..sql.dml import _DMLTableElement @@ -150,7 +150,7 @@ class QueryContext: Type[QueryContext.default_load_options], QueryContext.default_load_options, ], - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[OrmExecuteOptionsParameter] = None, bind_arguments: Optional[_BindArguments] = None, ): self.load_options = load_options diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 86137e00e6..63035f585b 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -97,7 +97,7 @@ if TYPE_CHECKING: from ._typing import _EntityType from ._typing import _ExternalEntityType from ._typing import _InternalEntityType - from .bulk_persistence import _SynchronizeSessionArgument + from ._typing import SynchronizeSessionArgument from .mapper import Mapper from .path_registry import PathRegistry from .session import _PKIdentityArgument @@ -105,6 +105,9 @@ if TYPE_CHECKING: from .state import InstanceState from ..engine.cursor import CursorResult from ..engine.interfaces import _ImmutableExecuteOptions + from ..engine.interfaces import CompiledCacheType + from ..engine.interfaces import IsolationLevel + from ..engine.interfaces import SchemaTranslateMapType from ..engine.result import FrozenResult from ..engine.result import ScalarResult from ..sql._typing import _ColumnExpressionArgument @@ -1654,6 +1657,29 @@ class Query( """ return self._execution_options + @overload + def execution_options( + self: SelfQuery, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + no_parameters: bool = False, + stream_results: bool = False, + max_row_buffer: int = ..., + yield_per: int = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + populate_existing: bool = False, + autoflush: bool = False, + **opt: Any, + ) -> SelfQuery: + ... + + @overload + def execution_options(self: SelfQuery, **opt: Any) -> SelfQuery: + ... + @_generative def execution_options(self: SelfQuery, **kwargs: Any) -> SelfQuery: """Set non-SQL options which take effect during execution. @@ -2975,7 +3001,7 @@ class Query( ) def delete( - self, synchronize_session: _SynchronizeSessionArgument = "auto" + self, synchronize_session: SynchronizeSessionArgument = "auto" ) -> int: r"""Perform a DELETE with an arbitrary WHERE clause. @@ -3039,7 +3065,7 @@ class Query( def update( self, values: Dict[_DMLColumnArgument, Any], - synchronize_session: _SynchronizeSessionArgument = "auto", + synchronize_session: SynchronizeSessionArgument = "auto", update_args: Optional[Dict[Any, Any]] = None, ) -> int: r"""Perform an UPDATE with an arbitrary WHERE clause. diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py index 1971caedc0..3ec2db4e63 100644 --- a/lib/sqlalchemy/orm/scoping.py +++ b/lib/sqlalchemy/orm/scoping.py @@ -36,6 +36,7 @@ from ..util.typing import Protocol if TYPE_CHECKING: from ._typing import _EntityType from ._typing import _IdentityKeyType + from ._typing import OrmExecuteOptionsParameter from .identity import IdentityMap from .interfaces import ORMOption from .mapper import Mapper @@ -55,7 +56,6 @@ if TYPE_CHECKING: from ..engine.interfaces import _CoreAnyExecuteParams from ..engine.interfaces import _CoreSingleExecuteParams from ..engine.interfaces import _ExecuteOptions - from ..engine.interfaces import _ExecuteOptionsParameter from ..engine.result import ScalarResult from ..sql._typing import _ColumnsClauseArgument from ..sql._typing import _T0 @@ -618,7 +618,7 @@ class scoped_session(Generic[_S]): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -631,7 +631,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -643,7 +643,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -876,7 +876,7 @@ class scoped_session(Generic[_S]): populate_existing: bool = False, with_for_update: Optional[ForUpdateArg] = None, identity_token: Optional[Any] = None, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, ) -> Optional[_O]: r"""Return an instance based on the given primary key identifier, or ``None`` if not found. @@ -1672,7 +1672,7 @@ class scoped_session(Generic[_S]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Optional[_T]: @@ -1684,7 +1684,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -1695,7 +1695,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -1727,7 +1727,7 @@ class scoped_session(Generic[_S]): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[_T]: @@ -1739,7 +1739,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -1750,7 +1750,7 @@ class scoped_session(Generic[_S]): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 22e47585d7..540e64e7d3 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -93,6 +93,7 @@ if typing.TYPE_CHECKING: from ._typing import _EntityType from ._typing import _IdentityKeyType from ._typing import _InstanceDict + from ._typing import OrmExecuteOptionsParameter from .interfaces import ORMOption from .interfaces import UserDefinedOption from .mapper import Mapper @@ -106,7 +107,6 @@ if typing.TYPE_CHECKING: from ..engine.interfaces import _CoreAnyExecuteParams from ..engine.interfaces import _CoreSingleExecuteParams from ..engine.interfaces import _ExecuteOptions - from ..engine.interfaces import _ExecuteOptionsParameter from ..engine.result import ScalarResult from ..event import _InstanceLevelDispatch from ..sql._typing import _ColumnsClauseArgument @@ -365,7 +365,7 @@ class ORMExecuteState(util.MemoizedSlots): self, statement: Optional[Executable] = None, params: Optional[_CoreAnyExecuteParams] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[OrmExecuteOptionsParameter] = None, bind_arguments: Optional[_BindArguments] = None, ) -> Result[Any]: """Execute the statement represented by this @@ -1858,7 +1858,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -1872,7 +1872,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -1885,7 +1885,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -1997,7 +1997,7 @@ class Session(_SessionClassMethods, EventTarget): statement: TypedReturnsRows[_T], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -2010,7 +2010,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -2022,7 +2022,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, _parent_execute_state: Optional[Any] = None, _add_event: Optional[Any] = None, @@ -2093,7 +2093,7 @@ class Session(_SessionClassMethods, EventTarget): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Optional[_T]: @@ -2105,7 +2105,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -2116,7 +2116,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreSingleExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> Any: @@ -2143,7 +2143,7 @@ class Session(_SessionClassMethods, EventTarget): statement: TypedReturnsRows[Tuple[_T]], params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[_T]: @@ -2155,7 +2155,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -2166,7 +2166,7 @@ class Session(_SessionClassMethods, EventTarget): statement: Executable, params: Optional[_CoreAnyExecuteParams] = None, *, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, bind_arguments: Optional[_BindArguments] = None, **kw: Any, ) -> ScalarResult[Any]: @@ -3246,7 +3246,7 @@ class Session(_SessionClassMethods, EventTarget): populate_existing: bool = False, with_for_update: Optional[ForUpdateArg] = None, identity_token: Optional[Any] = None, - execution_options: _ExecuteOptionsParameter = util.EMPTY_DICT, + execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, ) -> Optional[_O]: """Return an instance based on the given primary key identifier, or ``None`` if not found. @@ -3364,7 +3364,7 @@ class Session(_SessionClassMethods, EventTarget): populate_existing: bool = False, with_for_update: Optional[ForUpdateArg] = None, identity_token: Optional[Any] = None, - execution_options: Optional[_ExecuteOptionsParameter] = None, + execution_options: Optional[OrmExecuteOptionsParameter] = None, ) -> Optional[_O]: # convert composite types to individual args diff --git a/lib/sqlalchemy/sql/_orm_types.py b/lib/sqlalchemy/sql/_orm_types.py new file mode 100644 index 0000000000..90986ec0cc --- /dev/null +++ b/lib/sqlalchemy/sql/_orm_types.py @@ -0,0 +1,20 @@ +# sql/_orm_types.py +# Copyright (C) 2022 the SQLAlchemy authors and contributors +# +# +# This module is part of SQLAlchemy and is released under +# the MIT License: https://www.opensource.org/licenses/mit-license.php + +"""ORM types that need to present specifically for **documentation only** of +the Executable.execution_options() method, which includes options that +are meaningful to the ORM. + +""" + + +from __future__ import annotations + +from ..util.typing import Literal + +SynchronizeSessionArgument = Literal[False, "auto", "evaluate", "fetch"] +DMLStrategyArgument = Literal["bulk", "raw", "orm", "auto"] diff --git a/lib/sqlalchemy/sql/_typing.py b/lib/sqlalchemy/sql/_typing.py index ed1bd28322..8a758e7c7e 100644 --- a/lib/sqlalchemy/sql/_typing.py +++ b/lib/sqlalchemy/sql/_typing.py @@ -1,3 +1,10 @@ +# sql/_typing.py +# Copyright (C) 2022 the SQLAlchemy authors and contributors +# +# +# This module is part of SQLAlchemy and is released under +# the MIT License: https://www.opensource.org/licenses/mit-license.php + from __future__ import annotations import operator diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py index 2a8479c6d4..a8901c1441 100644 --- a/lib/sqlalchemy/sql/base.py +++ b/lib/sqlalchemy/sql/base.py @@ -64,6 +64,8 @@ if TYPE_CHECKING: from . import coercions from . import elements from . import type_api + from ._orm_types import DMLStrategyArgument + from ._orm_types import SynchronizeSessionArgument from .elements import BindParameter from .elements import ClauseList from .elements import ColumnClause # noqa @@ -77,15 +79,16 @@ if TYPE_CHECKING: from .selectable import FromClause from ..engine import Connection from ..engine import CursorResult - from ..engine.base import _CompiledCacheType from ..engine.interfaces import _CoreMultiExecuteParams from ..engine.interfaces import _ExecuteOptions - from ..engine.interfaces import _ExecuteOptionsParameter from ..engine.interfaces import _ImmutableExecuteOptions - from ..engine.interfaces import _SchemaTranslateMapType from ..engine.interfaces import CacheStats from ..engine.interfaces import Compiled + from ..engine.interfaces import CompiledCacheType + from ..engine.interfaces import CoreExecuteOptionsParameter from ..engine.interfaces import Dialect + from ..engine.interfaces import IsolationLevel + from ..engine.interfaces import SchemaTranslateMapType from ..event import dispatcher if not TYPE_CHECKING: @@ -1009,10 +1012,10 @@ class Executable(roles.StatementRole): self, dialect: Dialect, *, - compiled_cache: Optional[_CompiledCacheType], + compiled_cache: Optional[CompiledCacheType], column_keys: List[str], for_executemany: bool = False, - schema_translate_map: Optional[_SchemaTranslateMapType] = None, + schema_translate_map: Optional[SchemaTranslateMapType] = None, **kw: Any, ) -> Tuple[ Compiled, Optional[Sequence[BindParameter[Any]]], CacheStats @@ -1023,7 +1026,7 @@ class Executable(roles.StatementRole): self, connection: Connection, distilled_params: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> CursorResult[Any]: ... @@ -1031,7 +1034,7 @@ class Executable(roles.StatementRole): self, connection: Connection, distilled_params: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> Any: ... @@ -1123,6 +1126,33 @@ class Executable(roles.StatementRole): self._with_context_options += ((callable_, cache_args),) return self + @overload + def execution_options( + self: SelfExecutable, + *, + compiled_cache: Optional[CompiledCacheType] = ..., + logging_token: str = ..., + isolation_level: IsolationLevel = ..., + no_parameters: bool = False, + stream_results: bool = False, + max_row_buffer: int = ..., + yield_per: int = ..., + insertmanyvalues_page_size: int = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., + populate_existing: bool = False, + autoflush: bool = False, + synchronize_session: SynchronizeSessionArgument = ..., + dml_strategy: DMLStrategyArgument = ..., + is_delete_using: bool = ..., + is_update_from: bool = ..., + **opt: Any, + ) -> SelfExecutable: + ... + + @overload + def execution_options(self: SelfExecutable, **opt: Any) -> SelfExecutable: + ... + @_generative def execution_options(self: SelfExecutable, **kw: Any) -> SelfExecutable: """Set non-SQL options for the statement which take effect during diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 5b7238a079..704c0d19cf 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -109,8 +109,8 @@ if typing.TYPE_CHECKING: from ..engine.interfaces import _CoreSingleExecuteParams from ..engine.interfaces import _ExecuteOptions from ..engine.interfaces import _MutableCoreSingleExecuteParams - from ..engine.interfaces import _SchemaTranslateMapType from ..engine.interfaces import Dialect + from ..engine.interfaces import SchemaTranslateMapType _FromHintsType = Dict["FromClause", str] @@ -535,7 +535,7 @@ class Compiled: _result_columns: Optional[List[ResultColumnsEntry]] = None - schema_translate_map: Optional[_SchemaTranslateMapType] = None + schema_translate_map: Optional[SchemaTranslateMapType] = None execution_options: _ExecuteOptions = util.EMPTY_DICT """ @@ -595,7 +595,7 @@ class Compiled: self, dialect: Dialect, statement: Optional[ClauseElement], - schema_translate_map: Optional[_SchemaTranslateMapType] = None, + schema_translate_map: Optional[SchemaTranslateMapType] = None, render_schema_translate: bool = False, compile_kwargs: Mapping[str, Any] = util.immutabledict(), ): @@ -5365,7 +5365,7 @@ class DDLCompiler(Compiled): self, dialect: Dialect, statement: ExecutableDDLElement, - schema_translate_map: Optional[_SchemaTranslateMapType] = ..., + schema_translate_map: Optional[SchemaTranslateMapType] = ..., render_schema_translate: bool = ..., compile_kwargs: Mapping[str, Any] = ..., ): diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py index e744f0c1de..fa0c25b1d3 100644 --- a/lib/sqlalchemy/sql/ddl.py +++ b/lib/sqlalchemy/sql/ddl.py @@ -42,11 +42,11 @@ if typing.TYPE_CHECKING: from .schema import SchemaItem from .schema import Sequence from .schema import Table - from ..engine.base import _CompiledCacheType from ..engine.base import Connection - from ..engine.interfaces import _SchemaTranslateMapType from ..engine.interfaces import CacheStats + from ..engine.interfaces import CompiledCacheType from ..engine.interfaces import Dialect + from ..engine.interfaces import SchemaTranslateMapType class BaseDDLElement(ClauseElement): @@ -70,10 +70,10 @@ class BaseDDLElement(ClauseElement): self, dialect: Dialect, *, - compiled_cache: Optional[_CompiledCacheType], + compiled_cache: Optional[CompiledCacheType], column_keys: List[str], for_executemany: bool = False, - schema_translate_map: Optional[_SchemaTranslateMapType] = None, + schema_translate_map: Optional[SchemaTranslateMapType] = None, **kw: Any, ) -> Tuple[ Compiled, Optional[typing_Sequence[BindParameter[Any]]], CacheStats diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 3f4381c1a8..3b70e8d4e9 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -104,11 +104,11 @@ if typing.TYPE_CHECKING: from ..engine import Connection from ..engine import Dialect from ..engine import Engine - from ..engine.base import _CompiledCacheType from ..engine.interfaces import _CoreMultiExecuteParams from ..engine.interfaces import _ExecuteOptions - from ..engine.interfaces import _SchemaTranslateMapType from ..engine.interfaces import CacheStats + from ..engine.interfaces import CompiledCacheType + from ..engine.interfaces import SchemaTranslateMapType from ..engine.result import Result _NUMERIC = Union[float, Decimal] @@ -618,10 +618,10 @@ class ClauseElement( self, dialect: Dialect, *, - compiled_cache: Optional[_CompiledCacheType], + compiled_cache: Optional[CompiledCacheType], column_keys: List[str], for_executemany: bool = False, - schema_translate_map: Optional[_SchemaTranslateMapType] = None, + schema_translate_map: Optional[SchemaTranslateMapType] = None, **kw: Any, ) -> typing_Tuple[ Compiled, Optional[Sequence[BindParameter[Any]]], CacheStats diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py index c04f5fa1d2..fad7c28eb5 100644 --- a/lib/sqlalchemy/sql/functions.py +++ b/lib/sqlalchemy/sql/functions.py @@ -66,7 +66,7 @@ if TYPE_CHECKING: from ..engine.base import Connection from ..engine.cursor import CursorResult from ..engine.interfaces import _CoreMultiExecuteParams - from ..engine.interfaces import _ExecuteOptionsParameter + from ..engine.interfaces import CoreExecuteOptionsParameter _T = TypeVar("_T", bound=Any) @@ -175,7 +175,7 @@ class FunctionElement(Executable, ColumnElement[_T], FromClause, Generative): self, connection: Connection, distilled_params: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> CursorResult[Any]: return connection._execute_function( self, distilled_params, execution_options diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 5d5f76c758..36c33868af 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -97,7 +97,7 @@ if typing.TYPE_CHECKING: from ..engine import Connection from ..engine import Engine from ..engine.interfaces import _CoreMultiExecuteParams - from ..engine.interfaces import _ExecuteOptionsParameter + from ..engine.interfaces import CoreExecuteOptionsParameter from ..engine.interfaces import ExecutionContext from ..engine.mock import MockConnection from ..engine.reflection import _ReflectionInfo @@ -3034,7 +3034,7 @@ class DefaultGenerator(Executable, SchemaItem): self, connection: Connection, distilled_params: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> Any: util.warn_deprecated( "Using the .execute() method to invoke a " @@ -3050,7 +3050,7 @@ class DefaultGenerator(Executable, SchemaItem): self, connection: Connection, distilled_params: _CoreMultiExecuteParams, - execution_options: _ExecuteOptionsParameter, + execution_options: CoreExecuteOptionsParameter, ) -> Any: return connection._execute_default( self, distilled_params, execution_options diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index 7c73255d78..9de015774d 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -105,7 +105,6 @@ and_ = BooleanClauseList.and_ _T = TypeVar("_T", bound=Any) if TYPE_CHECKING: - import sqlalchemy from ._typing import _ColumnExpressionArgument from ._typing import _FromClauseArgument from ._typing import _JoinTargetArgument @@ -130,6 +129,7 @@ if TYPE_CHECKING: from .cache_key import _CacheKeyTraversalType from .compiler import SQLCompiler from .dml import Delete + from .dml import Insert from .dml import Update from .elements import KeyedColumnElement from .elements import Label @@ -2997,7 +2997,7 @@ class TableClause(roles.DMLTableRole, Immutable, NamedFromClause): c.table = self @util.preload_module("sqlalchemy.sql.dml") - def insert(self) -> sqlalchemy.sql.expression.Insert: + def insert(self) -> Insert: """Generate an :func:`_expression.insert` construct against this :class:`_expression.TableClause`. diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py index 8ceb2af2f6..5b3443d1a3 100644 --- a/lib/sqlalchemy/testing/requirements.py +++ b/lib/sqlalchemy/testing/requirements.py @@ -1425,6 +1425,12 @@ class SuiteRequirements(Requirements): lambda: util.py310, "Python 3.10 or above required" ) + @property + def python311(self): + return exclusions.only_if( + lambda: util.py311, "Python 3.11 or above required" + ) + @property def cpython(self): return exclusions.only_if( diff --git a/setup.cfg b/setup.cfg index 1255c3bcdb..87efad03a8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,7 +38,7 @@ package_dir = install_requires = importlib-metadata;python_version<"3.8" greenlet != 0.4.17;(platform_machine=='aarch64' or (platform_machine=='ppc64le' or (platform_machine=='x86_64' or (platform_machine=='amd64' or (platform_machine=='AMD64' or (platform_machine=='win32' or platform_machine=='WIN32')))))) - typing-extensions >= 4.1.0 + typing-extensions >= 4.2.0 [options.extras_require] asyncio = diff --git a/test/ext/mypy/test_mypy_plugin_py3k.py b/test/ext/mypy/test_mypy_plugin_py3k.py index 9b28539701..dce75b4f34 100644 --- a/test/ext/mypy/test_mypy_plugin_py3k.py +++ b/test/ext/mypy/test_mypy_plugin_py3k.py @@ -119,6 +119,10 @@ class MypyPluginTest(fixtures.TestBase): args.append(path) + # I set this locally but for the suite here needs to be + # disabled + os.environ.pop("MYPY_FORCE_COLOR", None) + result = api.run(args) return result diff --git a/test/ext/mypy/test_overloads.py b/test/ext/mypy/test_overloads.py new file mode 100644 index 0000000000..4a258a00bf --- /dev/null +++ b/test/ext/mypy/test_overloads.py @@ -0,0 +1,94 @@ +from sqlalchemy import testing +from sqlalchemy.engine.base import Connection +from sqlalchemy.engine.base import Engine +from sqlalchemy.engine.interfaces import CoreExecuteOptionsParameter +from sqlalchemy.ext.asyncio.engine import AsyncConnection +from sqlalchemy.ext.asyncio.engine import AsyncEngine +from sqlalchemy.orm._typing import OrmExecuteOptionsParameter +from sqlalchemy.orm.query import Query +from sqlalchemy.sql.base import Executable +from sqlalchemy.testing import fixtures +from sqlalchemy.testing.assertions import eq_ + +engine_execution_options = { + "compiled_cache": "Optional[CompiledCacheType]", + "logging_token": "str", + "isolation_level": "IsolationLevel", + "insertmanyvalues_page_size": "int", + "schema_translate_map": "Optional[SchemaTranslateMapType]", + "opt": "Any", +} +core_execution_options = { + **engine_execution_options, + "no_parameters": "bool", + "stream_results": "bool", + "max_row_buffer": "int", + "yield_per": "int", +} + +orm_dql_execution_options = { + **core_execution_options, + "populate_existing": "bool", + "autoflush": "bool", +} + +orm_dml_execution_options = { + "synchronize_session": "SynchronizeSessionArgument", + "dml_strategy": "DMLStrategyArgument", + "is_delete_using": "bool", + "is_update_from": "bool", +} + +orm_execution_options = { + **orm_dql_execution_options, + **orm_dml_execution_options, +} + + +class OverloadTest(fixtures.TestBase): + # NOTE: get_overloads is python 3.11. typing_extensions implements it + # but for it to work the typing_extensions overload needs to be use and + # it can only be imported directly from typing_extensions in all modules + # that use it otherwise flake8 (pyflakes actually) will flag it with F811 + __requires__ = ("python311",) + + @testing.combinations( + (Engine, engine_execution_options), + (Connection, core_execution_options), + (AsyncEngine, engine_execution_options), + (AsyncConnection, core_execution_options), + (Query, orm_dql_execution_options), + (Executable, orm_execution_options), + ) + def test_methods(self, class_, expected): + from typing import get_overloads + + overloads = get_overloads(getattr(class_, "execution_options")) + eq_(len(overloads), 2) + annotations = overloads[0].__annotations__.copy() + annotations.pop("self", None) + annotations.pop("return", None) + eq_(annotations, expected) + annotations = overloads[1].__annotations__.copy() + annotations.pop("self", None) + annotations.pop("return", None) + eq_(annotations, {"opt": "Any"}) + + @testing.combinations( + (CoreExecuteOptionsParameter, core_execution_options), + (OrmExecuteOptionsParameter, orm_execution_options), + ) + def test_typed_dicts(self, typ, expected): + # we currently expect these to be union types with first entry + # is the typed dict + + typed_dict = typ.__args__[0] + + expected = dict(expected) + expected.pop("opt") + + assert_annotations = { + key: fwd_ref.__forward_arg__ + for key, fwd_ref in typed_dict.__annotations__.items() + } + eq_(assert_annotations, expected) diff --git a/tools/generate_proxy_methods.py b/tools/generate_proxy_methods.py index 85f8b23208..c21db9d601 100644 --- a/tools/generate_proxy_methods.py +++ b/tools/generate_proxy_methods.py @@ -154,7 +154,7 @@ def _grab_overloads(fn): current_ov[:] = [] break - fn_match = re.match(r"^ (?: )?(?:async )?def (.*)\($", line) + fn_match = re.match(r"^ (?: )?(?:async )?def (.*)\(", line) if fn_match and fn_match.group(1) != fn.__name__: current_ov[:] = [] break @@ -166,6 +166,7 @@ def _grab_overloads(fn): if re.match(r"^ if (?:typing\.)?TYPE_CHECKING:", line): output.append(line) + current_ov[:] = [] output.reverse() return output diff --git a/tox.ini b/tox.ini index 0b0e0d7ccb..1b2e3d5396 100644 --- a/tox.ini +++ b/tox.ini @@ -180,8 +180,12 @@ deps= # this is to satisfy the mypy plugin dependency # when slotscheck imports sqlalchemy.mypy modules sqlalchemy[mypy] + # required by generate_tuple_map_overloads + zimports allowlist_externals = env + git + sh commands = flake8 ./lib/ ./test/ ./examples/ setup.py doc/build/conf.py {posargs} black --check ./lib/ ./test/ ./examples/ setup.py doc/build/conf.py @@ -189,6 +193,8 @@ commands = slotscheck -m sqlalchemy env DISABLE_SQLALCHEMY_CEXT_RUNTIME=1 slotscheck -m sqlalchemy python ./tools/format_docs_code.py --check + sh -c 'python ./tools/generate_tuple_map_overloads.py && git diff --exit-code' + sh -c 'python ./tools/generate_proxy_methods.py && git diff --exit-code' # "pep8" env was renamed to "lint".