SQLAlchemy 2.0.38__py3-none-any.whl → 2.0.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sqlalchemy/__init__.py CHANGED
@@ -269,7 +269,7 @@ from .types import Uuid as Uuid
269
269
  from .types import VARBINARY as VARBINARY
270
270
  from .types import VARCHAR as VARCHAR
271
271
 
272
- __version__ = "2.0.38"
272
+ __version__ = "2.0.39"
273
273
 
274
274
 
275
275
  def __go(lcls: Any) -> None:
@@ -182,6 +182,31 @@ For fully atomic transactions as well as support for foreign key
182
182
  constraints, all participating ``CREATE TABLE`` statements must specify a
183
183
  transactional engine, which in the vast majority of cases is ``InnoDB``.
184
184
 
185
+ Partitioning can similarly be specified using similar options.
186
+ In the example below the create table will specify ``PARTITION_BY``,
187
+ ``PARTITIONS``, ``SUBPARTITIONS`` and ``SUBPARTITION_BY``::
188
+
189
+ # can also use mariadb_* prefix
190
+ Table(
191
+ "testtable",
192
+ MetaData(),
193
+ Column("id", Integer(), primary_key=True, autoincrement=True),
194
+ Column("other_id", Integer(), primary_key=True, autoincrement=False),
195
+ mysql_partitions="2",
196
+ mysql_partition_by="KEY(other_id)",
197
+ mysql_subpartition_by="HASH(some_expr)",
198
+ mysql_subpartitions="2",
199
+ )
200
+
201
+ This will render:
202
+
203
+ .. sourcecode:: sql
204
+
205
+ CREATE TABLE testtable (
206
+ id INTEGER NOT NULL AUTO_INCREMENT,
207
+ other_id INTEGER NOT NULL,
208
+ PRIMARY KEY (id, other_id)
209
+ )PARTITION BY KEY(other_id) PARTITIONS 2 SUBPARTITION BY HASH(some_expr) SUBPARTITIONS 2
185
210
 
186
211
  Case Sensitivity and Table Reflection
187
212
  -------------------------------------
@@ -2001,9 +2001,10 @@ class PGCompiler(compiler.SQLCompiler):
2001
2001
  for c in select._for_update_arg.of:
2002
2002
  tables.update(sql_util.surface_selectables_only(c))
2003
2003
 
2004
+ of_kw = dict(kw)
2005
+ of_kw.update(ashint=True, use_schema=False)
2004
2006
  tmp += " OF " + ", ".join(
2005
- self.process(table, ashint=True, use_schema=False, **kw)
2006
- for table in tables
2007
+ self.process(table, **of_kw) for table in tables
2007
2008
  )
2008
2009
 
2009
2010
  if select._for_update_arg.nowait:
@@ -3601,6 +3602,7 @@ class PGDialect(default.DefaultDialect):
3601
3602
  pg_catalog.pg_sequence.c.seqcache,
3602
3603
  "cycle",
3603
3604
  pg_catalog.pg_sequence.c.seqcycle,
3605
+ type_=sqltypes.JSON(),
3604
3606
  )
3605
3607
  )
3606
3608
  .select_from(pg_catalog.pg_sequence)
@@ -5010,11 +5012,12 @@ class PGDialect(default.DefaultDialect):
5010
5012
  key=lambda t: t[0],
5011
5013
  )
5012
5014
  for name, def_ in sorted_constraints:
5013
- # constraint is in the form "CHECK (expression)".
5015
+ # constraint is in the form "CHECK (expression)"
5016
+ # or "NOT NULL". Ignore the "NOT NULL" and
5014
5017
  # remove "CHECK (" and the tailing ")".
5015
- check = def_[7:-1]
5016
- constraints.append({"name": name, "check": check})
5017
-
5018
+ if def_.casefold().startswith("check"):
5019
+ check = def_[7:-1]
5020
+ constraints.append({"name": name, "check": check})
5018
5021
  domain_rec: ReflectedDomain = {
5019
5022
  "name": domain["name"],
5020
5023
  "schema": domain["schema"],
@@ -4,8 +4,15 @@
4
4
  #
5
5
  # This module is part of SQLAlchemy and is released under
6
6
  # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
- # mypy: ignore-errors
8
7
 
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import Callable
12
+ from typing import List
13
+ from typing import Optional
14
+ from typing import TYPE_CHECKING
15
+ from typing import Union
9
16
 
10
17
  from .array import ARRAY
11
18
  from .array import array as _pg_array
@@ -21,13 +28,23 @@ from .operators import PATH_EXISTS
21
28
  from .operators import PATH_MATCH
22
29
  from ... import types as sqltypes
23
30
  from ...sql import cast
31
+ from ...sql._typing import _T
32
+
33
+ if TYPE_CHECKING:
34
+ from ...engine.interfaces import Dialect
35
+ from ...sql.elements import ColumnElement
36
+ from ...sql.type_api import _BindProcessorType
37
+ from ...sql.type_api import _LiteralProcessorType
38
+ from ...sql.type_api import TypeEngine
24
39
 
25
40
  __all__ = ("JSON", "JSONB")
26
41
 
27
42
 
28
43
  class JSONPathType(sqltypes.JSON.JSONPathType):
29
- def _processor(self, dialect, super_proc):
30
- def process(value):
44
+ def _processor(
45
+ self, dialect: Dialect, super_proc: Optional[Callable[[Any], Any]]
46
+ ) -> Callable[[Any], Any]:
47
+ def process(value: Any) -> Any:
31
48
  if isinstance(value, str):
32
49
  # If it's already a string assume that it's in json path
33
50
  # format. This allows using cast with json paths literals
@@ -44,11 +61,13 @@ class JSONPathType(sqltypes.JSON.JSONPathType):
44
61
 
45
62
  return process
46
63
 
47
- def bind_processor(self, dialect):
48
- return self._processor(dialect, self.string_bind_processor(dialect))
64
+ def bind_processor(self, dialect: Dialect) -> _BindProcessorType[Any]:
65
+ return self._processor(dialect, self.string_bind_processor(dialect)) # type: ignore[return-value] # noqa: E501
49
66
 
50
- def literal_processor(self, dialect):
51
- return self._processor(dialect, self.string_literal_processor(dialect))
67
+ def literal_processor(
68
+ self, dialect: Dialect
69
+ ) -> _LiteralProcessorType[Any]:
70
+ return self._processor(dialect, self.string_literal_processor(dialect)) # type: ignore[return-value] # noqa: E501
52
71
 
53
72
 
54
73
  class JSONPATH(JSONPathType):
@@ -148,9 +167,13 @@ class JSON(sqltypes.JSON):
148
167
  """ # noqa
149
168
 
150
169
  render_bind_cast = True
151
- astext_type = sqltypes.Text()
170
+ astext_type: TypeEngine[str] = sqltypes.Text()
152
171
 
153
- def __init__(self, none_as_null=False, astext_type=None):
172
+ def __init__(
173
+ self,
174
+ none_as_null: bool = False,
175
+ astext_type: Optional[TypeEngine[str]] = None,
176
+ ):
154
177
  """Construct a :class:`_types.JSON` type.
155
178
 
156
179
  :param none_as_null: if True, persist the value ``None`` as a
@@ -175,11 +198,13 @@ class JSON(sqltypes.JSON):
175
198
  if astext_type is not None:
176
199
  self.astext_type = astext_type
177
200
 
178
- class Comparator(sqltypes.JSON.Comparator):
201
+ class Comparator(sqltypes.JSON.Comparator[_T]):
179
202
  """Define comparison operations for :class:`_types.JSON`."""
180
203
 
204
+ type: JSON
205
+
181
206
  @property
182
- def astext(self):
207
+ def astext(self) -> ColumnElement[str]:
183
208
  """On an indexed expression, use the "astext" (e.g. "->>")
184
209
  conversion when rendered in SQL.
185
210
 
@@ -193,13 +218,13 @@ class JSON(sqltypes.JSON):
193
218
 
194
219
  """
195
220
  if isinstance(self.expr.right.type, sqltypes.JSON.JSONPathType):
196
- return self.expr.left.operate(
221
+ return self.expr.left.operate( # type: ignore[no-any-return]
197
222
  JSONPATH_ASTEXT,
198
223
  self.expr.right,
199
224
  result_type=self.type.astext_type,
200
225
  )
201
226
  else:
202
- return self.expr.left.operate(
227
+ return self.expr.left.operate( # type: ignore[no-any-return]
203
228
  ASTEXT, self.expr.right, result_type=self.type.astext_type
204
229
  )
205
230
 
@@ -258,28 +283,30 @@ class JSONB(JSON):
258
283
 
259
284
  __visit_name__ = "JSONB"
260
285
 
261
- class Comparator(JSON.Comparator):
286
+ class Comparator(JSON.Comparator[_T]):
262
287
  """Define comparison operations for :class:`_types.JSON`."""
263
288
 
264
- def has_key(self, other):
289
+ type: JSONB
290
+
291
+ def has_key(self, other: Any) -> ColumnElement[bool]:
265
292
  """Boolean expression. Test for presence of a key (equivalent of
266
293
  the ``?`` operator). Note that the key may be a SQLA expression.
267
294
  """
268
295
  return self.operate(HAS_KEY, other, result_type=sqltypes.Boolean)
269
296
 
270
- def has_all(self, other):
297
+ def has_all(self, other: Any) -> ColumnElement[bool]:
271
298
  """Boolean expression. Test for presence of all keys in jsonb
272
299
  (equivalent of the ``?&`` operator)
273
300
  """
274
301
  return self.operate(HAS_ALL, other, result_type=sqltypes.Boolean)
275
302
 
276
- def has_any(self, other):
303
+ def has_any(self, other: Any) -> ColumnElement[bool]:
277
304
  """Boolean expression. Test for presence of any key in jsonb
278
305
  (equivalent of the ``?|`` operator)
279
306
  """
280
307
  return self.operate(HAS_ANY, other, result_type=sqltypes.Boolean)
281
308
 
282
- def contains(self, other, **kwargs):
309
+ def contains(self, other: Any, **kwargs: Any) -> ColumnElement[bool]:
283
310
  """Boolean expression. Test if keys (or array) are a superset
284
311
  of/contained the keys of the argument jsonb expression
285
312
  (equivalent of the ``@>`` operator).
@@ -289,7 +316,7 @@ class JSONB(JSON):
289
316
  """
290
317
  return self.operate(CONTAINS, other, result_type=sqltypes.Boolean)
291
318
 
292
- def contained_by(self, other):
319
+ def contained_by(self, other: Any) -> ColumnElement[bool]:
293
320
  """Boolean expression. Test if keys are a proper subset of the
294
321
  keys of the argument jsonb expression
295
322
  (equivalent of the ``<@`` operator).
@@ -298,7 +325,9 @@ class JSONB(JSON):
298
325
  CONTAINED_BY, other, result_type=sqltypes.Boolean
299
326
  )
300
327
 
301
- def delete_path(self, array):
328
+ def delete_path(
329
+ self, array: Union[List[str], _pg_array[str]]
330
+ ) -> ColumnElement[JSONB]:
302
331
  """JSONB expression. Deletes field or array element specified in
303
332
  the argument array (equivalent of the ``#-`` operator).
304
333
 
@@ -308,11 +337,11 @@ class JSONB(JSON):
308
337
  .. versionadded:: 2.0
309
338
  """
310
339
  if not isinstance(array, _pg_array):
311
- array = _pg_array(array)
340
+ array = _pg_array(array) # type: ignore[no-untyped-call]
312
341
  right_side = cast(array, ARRAY(sqltypes.TEXT))
313
342
  return self.operate(DELETE_PATH, right_side, result_type=JSONB)
314
343
 
315
- def path_exists(self, other):
344
+ def path_exists(self, other: Any) -> ColumnElement[bool]:
316
345
  """Boolean expression. Test for presence of item given by the
317
346
  argument JSONPath expression (equivalent of the ``@?`` operator).
318
347
 
@@ -322,7 +351,7 @@ class JSONB(JSON):
322
351
  PATH_EXISTS, other, result_type=sqltypes.Boolean
323
352
  )
324
353
 
325
- def path_match(self, other):
354
+ def path_match(self, other: Any) -> ColumnElement[bool]:
326
355
  """Boolean expression. Test if JSONPath predicate given by the
327
356
  argument JSONPath expression matches
328
357
  (equivalent of the ``@@`` operator).
@@ -52,28 +52,38 @@ class BYTEA(sqltypes.LargeBinary):
52
52
  __visit_name__ = "BYTEA"
53
53
 
54
54
 
55
- class INET(sqltypes.TypeEngine[str]):
55
+ class _NetworkAddressTypeMixin:
56
+
57
+ def coerce_compared_value(
58
+ self, op: Optional[OperatorType], value: Any
59
+ ) -> TypeEngine[Any]:
60
+ if TYPE_CHECKING:
61
+ assert isinstance(self, TypeEngine)
62
+ return self
63
+
64
+
65
+ class INET(_NetworkAddressTypeMixin, sqltypes.TypeEngine[str]):
56
66
  __visit_name__ = "INET"
57
67
 
58
68
 
59
69
  PGInet = INET
60
70
 
61
71
 
62
- class CIDR(sqltypes.TypeEngine[str]):
72
+ class CIDR(_NetworkAddressTypeMixin, sqltypes.TypeEngine[str]):
63
73
  __visit_name__ = "CIDR"
64
74
 
65
75
 
66
76
  PGCidr = CIDR
67
77
 
68
78
 
69
- class MACADDR(sqltypes.TypeEngine[str]):
79
+ class MACADDR(_NetworkAddressTypeMixin, sqltypes.TypeEngine[str]):
70
80
  __visit_name__ = "MACADDR"
71
81
 
72
82
 
73
83
  PGMacAddr = MACADDR
74
84
 
75
85
 
76
- class MACADDR8(sqltypes.TypeEngine[str]):
86
+ class MACADDR8(_NetworkAddressTypeMixin, sqltypes.TypeEngine[str]):
77
87
  __visit_name__ = "MACADDR8"
78
88
 
79
89
 
@@ -1758,12 +1758,18 @@ class SQLiteDDLCompiler(compiler.DDLCompiler):
1758
1758
  return text
1759
1759
 
1760
1760
  def post_create_table(self, table):
1761
- text = ""
1762
- if table.dialect_options["sqlite"]["with_rowid"] is False:
1763
- text += "\n WITHOUT ROWID"
1764
- if table.dialect_options["sqlite"]["strict"] is True:
1765
- text += "\n STRICT"
1766
- return text
1761
+ table_options = []
1762
+
1763
+ if not table.dialect_options["sqlite"]["with_rowid"]:
1764
+ table_options.append("WITHOUT ROWID")
1765
+
1766
+ if table.dialect_options["sqlite"]["strict"]:
1767
+ table_options.append("STRICT")
1768
+
1769
+ if table_options:
1770
+ return "\n " + ",\n ".join(table_options)
1771
+ else:
1772
+ return ""
1767
1773
 
1768
1774
 
1769
1775
  class SQLiteTypeCompiler(compiler.GenericTypeCompiler):
@@ -52,11 +52,11 @@ else:
52
52
  from sqlalchemy.cyextension.resultproxy import tuplegetter as tuplegetter
53
53
 
54
54
  if typing.TYPE_CHECKING:
55
- from ..sql.schema import Column
55
+ from ..sql.elements import SQLCoreOperations
56
56
  from ..sql.type_api import _ResultProcessorType
57
57
 
58
- _KeyType = Union[str, "Column[Any]"]
59
- _KeyIndexType = Union[str, "Column[Any]", int]
58
+ _KeyType = Union[str, "SQLCoreOperations[Any]"]
59
+ _KeyIndexType = Union[_KeyType, int]
60
60
 
61
61
  # is overridden in cursor using _CursorKeyMapRecType
62
62
  _KeyMapRecType = Any
@@ -93,6 +93,7 @@ class AsyncResult(_WithKeys, AsyncCommon[Row[_TP]]):
93
93
 
94
94
  self._metadata = real_result._metadata
95
95
  self._unique_filter_state = real_result._unique_filter_state
96
+ self._source_supports_scalars = real_result._source_supports_scalars
96
97
  self._post_creational_filter = None
97
98
 
98
99
  # BaseCursorResult pre-generates the "_row_getter". Use that
sqlalchemy/orm/context.py CHANGED
@@ -148,10 +148,11 @@ class QueryContext:
148
148
  def __init__(
149
149
  self,
150
150
  compile_state: CompileState,
151
- statement: Union[Select[Any], FromStatement[Any]],
151
+ statement: Union[Select[Any], FromStatement[Any], UpdateBase],
152
152
  user_passed_query: Union[
153
153
  Select[Any],
154
154
  FromStatement[Any],
155
+ UpdateBase,
155
156
  ],
156
157
  params: _CoreSingleExecuteParams,
157
158
  session: Session,
@@ -264,10 +265,10 @@ class AbstractORMCompileState(CompileState):
264
265
  @classmethod
265
266
  def create_for_statement(
266
267
  cls,
267
- statement: Union[Select, FromStatement],
268
- compiler: Optional[SQLCompiler],
268
+ statement: Executable,
269
+ compiler: SQLCompiler,
269
270
  **kw: Any,
270
- ) -> AbstractORMCompileState:
271
+ ) -> CompileState:
271
272
  """Create a context for a statement given a :class:`.Compiler`.
272
273
 
273
274
  This method is always invoked in the context of SQLCompiler.process().
@@ -413,8 +414,8 @@ class ORMCompileState(AbstractORMCompileState):
413
414
  attributes: Dict[Any, Any]
414
415
  global_attributes: Dict[Any, Any]
415
416
 
416
- statement: Union[Select[Any], FromStatement[Any]]
417
- select_statement: Union[Select[Any], FromStatement[Any]]
417
+ statement: Union[Select[Any], FromStatement[Any], UpdateBase]
418
+ select_statement: Union[Select[Any], FromStatement[Any], UpdateBase]
418
419
  _entities: List[_QueryEntity]
419
420
  _polymorphic_adapters: Dict[_InternalEntityType, ORMAdapter]
420
421
  compile_options: Union[
@@ -436,15 +437,30 @@ class ORMCompileState(AbstractORMCompileState):
436
437
  def __init__(self, *arg, **kw):
437
438
  raise NotImplementedError()
438
439
 
439
- if TYPE_CHECKING:
440
+ @classmethod
441
+ def create_for_statement(
442
+ cls,
443
+ statement: Executable,
444
+ compiler: SQLCompiler,
445
+ **kw: Any,
446
+ ) -> ORMCompileState:
447
+ return cls._create_orm_context(
448
+ cast("Union[Select, FromStatement]", statement),
449
+ toplevel=not compiler.stack,
450
+ compiler=compiler,
451
+ **kw,
452
+ )
440
453
 
441
- @classmethod
442
- def create_for_statement(
443
- cls,
444
- statement: Union[Select, FromStatement],
445
- compiler: Optional[SQLCompiler],
446
- **kw: Any,
447
- ) -> ORMCompileState: ...
454
+ @classmethod
455
+ def _create_orm_context(
456
+ cls,
457
+ statement: Union[Select, FromStatement],
458
+ *,
459
+ toplevel: bool,
460
+ compiler: Optional[SQLCompiler],
461
+ **kw: Any,
462
+ ) -> ORMCompileState:
463
+ raise NotImplementedError()
448
464
 
449
465
  def _append_dedupe_col_collection(self, obj, col_collection):
450
466
  dedupe = self.dedupe_columns
@@ -654,8 +670,8 @@ class ORMCompileState(AbstractORMCompileState):
654
670
  )
655
671
 
656
672
 
657
- class DMLReturningColFilter:
658
- """an adapter used for the DML RETURNING case.
673
+ class _DMLReturningColFilter:
674
+ """a base for an adapter used for the DML RETURNING cases
659
675
 
660
676
  Has a subset of the interface used by
661
677
  :class:`.ORMAdapter` and is used for :class:`._QueryEntity`
@@ -689,6 +705,21 @@ class DMLReturningColFilter:
689
705
  else:
690
706
  return None
691
707
 
708
+ def adapt_check_present(self, col):
709
+ raise NotImplementedError()
710
+
711
+
712
+ class _DMLBulkInsertReturningColFilter(_DMLReturningColFilter):
713
+ """an adapter used for the DML RETURNING case specifically
714
+ for ORM bulk insert (or any hypothetical DML that is splitting out a class
715
+ hierarchy among multiple DML statements....ORM bulk insert is the only
716
+ example right now)
717
+
718
+ its main job is to limit the columns in a RETURNING to only a specific
719
+ mapped table in a hierarchy.
720
+
721
+ """
722
+
692
723
  def adapt_check_present(self, col):
693
724
  mapper = self.mapper
694
725
  prop = mapper._columntoproperty.get(col, None)
@@ -697,6 +728,30 @@ class DMLReturningColFilter:
697
728
  return mapper.local_table.c.corresponding_column(col)
698
729
 
699
730
 
731
+ class _DMLUpdateDeleteReturningColFilter(_DMLReturningColFilter):
732
+ """an adapter used for the DML RETURNING case specifically
733
+ for ORM enabled UPDATE/DELETE
734
+
735
+ its main job is to limit the columns in a RETURNING to include
736
+ only direct persisted columns from the immediate selectable, not
737
+ expressions like column_property(), or to also allow columns from other
738
+ mappers for the UPDATE..FROM use case.
739
+
740
+ """
741
+
742
+ def adapt_check_present(self, col):
743
+ mapper = self.mapper
744
+ prop = mapper._columntoproperty.get(col, None)
745
+ if prop is not None:
746
+ # if the col is from the immediate mapper, only return a persisted
747
+ # column, not any kind of column_property expression
748
+ return mapper.persist_selectable.c.corresponding_column(col)
749
+
750
+ # if the col is from some other mapper, just return it, assume the
751
+ # user knows what they are doing
752
+ return col
753
+
754
+
700
755
  @sql.base.CompileState.plugin_for("orm", "orm_from_statement")
701
756
  class ORMFromStatementCompileState(ORMCompileState):
702
757
  _from_obj_alias = None
@@ -715,12 +770,16 @@ class ORMFromStatementCompileState(ORMCompileState):
715
770
  eager_joins = _EMPTY_DICT
716
771
 
717
772
  @classmethod
718
- def create_for_statement(
773
+ def _create_orm_context(
719
774
  cls,
720
- statement_container: Union[Select, FromStatement],
775
+ statement: Union[Select, FromStatement],
776
+ *,
777
+ toplevel: bool,
721
778
  compiler: Optional[SQLCompiler],
722
779
  **kw: Any,
723
780
  ) -> ORMFromStatementCompileState:
781
+ statement_container = statement
782
+
724
783
  assert isinstance(statement_container, FromStatement)
725
784
 
726
785
  if compiler is not None and compiler.stack:
@@ -851,14 +910,24 @@ class ORMFromStatementCompileState(ORMCompileState):
851
910
  return None
852
911
 
853
912
  def setup_dml_returning_compile_state(self, dml_mapper):
854
- """used by BulkORMInsert (and Update / Delete?) to set up a handler
913
+ """used by BulkORMInsert, Update, Delete to set up a handler
855
914
  for RETURNING to return ORM objects and expressions
856
915
 
857
916
  """
858
917
  target_mapper = self.statement._propagate_attrs.get(
859
918
  "plugin_subject", None
860
919
  )
861
- adapter = DMLReturningColFilter(target_mapper, dml_mapper)
920
+
921
+ if self.statement.is_insert:
922
+ adapter = _DMLBulkInsertReturningColFilter(
923
+ target_mapper, dml_mapper
924
+ )
925
+ elif self.statement.is_update or self.statement.is_delete:
926
+ adapter = _DMLUpdateDeleteReturningColFilter(
927
+ target_mapper, dml_mapper
928
+ )
929
+ else:
930
+ adapter = None
862
931
 
863
932
  if self.compile_options._is_star and (len(self._entities) != 1):
864
933
  raise sa_exc.CompileError(
@@ -1017,21 +1086,17 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
1017
1086
  _having_criteria = ()
1018
1087
 
1019
1088
  @classmethod
1020
- def create_for_statement(
1089
+ def _create_orm_context(
1021
1090
  cls,
1022
1091
  statement: Union[Select, FromStatement],
1092
+ *,
1093
+ toplevel: bool,
1023
1094
  compiler: Optional[SQLCompiler],
1024
1095
  **kw: Any,
1025
1096
  ) -> ORMSelectCompileState:
1026
- """compiler hook, we arrive here from compiler.visit_select() only."""
1027
1097
 
1028
1098
  self = cls.__new__(cls)
1029
1099
 
1030
- if compiler is not None:
1031
- toplevel = not compiler.stack
1032
- else:
1033
- toplevel = True
1034
-
1035
1100
  select_statement = statement
1036
1101
 
1037
1102
  # if we are a select() that was never a legacy Query, we won't
@@ -2535,7 +2600,7 @@ class _QueryEntity:
2535
2600
  def setup_dml_returning_compile_state(
2536
2601
  self,
2537
2602
  compile_state: ORMCompileState,
2538
- adapter: DMLReturningColFilter,
2603
+ adapter: Optional[_DMLReturningColFilter],
2539
2604
  ) -> None:
2540
2605
  raise NotImplementedError()
2541
2606
 
@@ -2737,7 +2802,7 @@ class _MapperEntity(_QueryEntity):
2737
2802
  def setup_dml_returning_compile_state(
2738
2803
  self,
2739
2804
  compile_state: ORMCompileState,
2740
- adapter: DMLReturningColFilter,
2805
+ adapter: Optional[_DMLReturningColFilter],
2741
2806
  ) -> None:
2742
2807
  loading._setup_entity_query(
2743
2808
  compile_state,
@@ -2896,7 +2961,7 @@ class _BundleEntity(_QueryEntity):
2896
2961
  def setup_dml_returning_compile_state(
2897
2962
  self,
2898
2963
  compile_state: ORMCompileState,
2899
- adapter: DMLReturningColFilter,
2964
+ adapter: Optional[_DMLReturningColFilter],
2900
2965
  ) -> None:
2901
2966
  return self.setup_compile_state(compile_state)
2902
2967
 
@@ -3086,7 +3151,7 @@ class _RawColumnEntity(_ColumnEntity):
3086
3151
  def setup_dml_returning_compile_state(
3087
3152
  self,
3088
3153
  compile_state: ORMCompileState,
3089
- adapter: DMLReturningColFilter,
3154
+ adapter: Optional[_DMLReturningColFilter],
3090
3155
  ) -> None:
3091
3156
  return self.setup_compile_state(compile_state)
3092
3157
 
@@ -3203,10 +3268,13 @@ class _ORMColumnEntity(_ColumnEntity):
3203
3268
  def setup_dml_returning_compile_state(
3204
3269
  self,
3205
3270
  compile_state: ORMCompileState,
3206
- adapter: DMLReturningColFilter,
3271
+ adapter: Optional[_DMLReturningColFilter],
3207
3272
  ) -> None:
3208
- self._fetch_column = self.column
3209
- column = adapter(self.column, False)
3273
+
3274
+ self._fetch_column = column = self.column
3275
+ if adapter:
3276
+ column = adapter(column, False)
3277
+
3210
3278
  if column is not None:
3211
3279
  compile_state.dedupe_columns.add(column)
3212
3280
  compile_state.primary_columns.append(column)
sqlalchemy/orm/mapper.py CHANGED
@@ -3440,7 +3440,7 @@ class Mapper(
3440
3440
 
3441
3441
  def identity_key_from_row(
3442
3442
  self,
3443
- row: Optional[Union[Row[Any], RowMapping]],
3443
+ row: Union[Row[Any], RowMapping],
3444
3444
  identity_token: Optional[Any] = None,
3445
3445
  adapter: Optional[ORMAdapter] = None,
3446
3446
  ) -> _IdentityKeyType[_O]:
@@ -3459,14 +3459,15 @@ class Mapper(
3459
3459
  if adapter:
3460
3460
  pk_cols = [adapter.columns[c] for c in pk_cols]
3461
3461
 
3462
+ mapping: RowMapping
3462
3463
  if hasattr(row, "_mapping"):
3463
- mapping = row._mapping # type: ignore
3464
+ mapping = row._mapping
3464
3465
  else:
3465
- mapping = cast("Mapping[Any, Any]", row)
3466
+ mapping = row # type: ignore[assignment]
3466
3467
 
3467
3468
  return (
3468
3469
  self._identity_class,
3469
- tuple(mapping[column] for column in pk_cols), # type: ignore
3470
+ tuple(mapping[column] for column in pk_cols),
3470
3471
  identity_token,
3471
3472
  )
3472
3473