2.0.52
- Python 3.15 support has been added and tested with minimal changes for full compatibility
- Fixed a result-column misalignment bug in ORM-enabled UPDATE statements where synchronize_session="fetch" is in use, where columns in rows returned by .returning() could be returned under incorrect keys
- Fixed bug where a failed bulk_insert_mappings(), bulk_update_mappings() or bulk_save_objects() call could leave the Session permanently in a flushing state
- Fixed issue where unpickling an ORM object loaded using loader options with wildcard tokens would fail with KeyError or IndexError in separate processes
- Fixed issue where a string ending in "*" passed to a Load strategy method would bypass the check rejecting string attribute names and now raises ArgumentError
- Calling aliased() against a select() or union() / CompoundSelect construct now raises under SQLAlchemy 2.1 and emits a deprecation warning under SQLAlchemy 2.0
- Fixed issue where using PEP 593 Annotated wrapping a PEP 695 type alias would crash with AttributeError: __value__
- Fixed issue where Select.get_final_froms() would emit a spurious deprecation warning when the statement used the PostgreSQL-specific expression argument to Select.distinct()
- Fixed an issue in Numeric where the decimal_return_scale parameter was ignored when the DBAPI does not support native decimal objects
2.0.52
Released: August 11, 2026
platform
-
[platform] [bug] Python 3.15 support has been added and tested, including minimal changes for full compatibility.
References: #13477
orm
-
[orm] [bug] Fixed a result-column misalignment bug in ORM-enabled UPDATE statements where
synchronize_session="fetch"is in use, either explicitly or because the statement uses constructs such as CTEs that implicitly select for it. Columns in rows returned by.returning()could be returned under incorrect keys (e.g.row[SomeClass.a]returning the value of a different column), a problem most likely to manifest under concurrent workloads. ORM DELETE statements were not affected.References: #13439
-
[orm] [bug] Fixed bug where a failed
_orm.Session.bulk_insert_mappings(),_orm.Session.bulk_update_mappings()or_orm.Session.bulk_save_objects()call could leave the_orm.Sessionpermanently in a "flushing" state, such as when the transaction could not be begun because a previous flush had left it needing a rollback. Unlike_orm.Session.flush(), the bulk methods set the internal flushing flag and began the transaction outside of thetry/finallyblock that resets it, so that neither_orm.Session.rollback()nor_orm.Session.close()would clear it, and every subsequent flush would raiseInvalidRequestError: Session is already flushing. Pull request courtesy Hamody We.References: #13485
-
[orm] [bug] Fixed issue where unpickling an ORM object that were loaded using loader options making use of wildcard tokens, such as
_orm.load_only()or_orm.raiseload()with"*", would fail withKeyErrororIndexErrorif the process doing the unpickling had not yet constructed a loader path making use of that same token. This would typically be observed when the object were unpickled in a separate process, such as with thespawnorforkservermultiprocessing start methods, the latter of which became the default on POSIX platforms as of Python 3.14. The internal collection of these tokens is now established up front, so that it is identical in every process.References: #13493
-
[orm] [bug] Fixed issue where a string ending in
"*"passed to a_orm.Loadstrategy method, such asLoad(A).joinedload("bs.*"), would bypass the check which rejects string attribute names in loader options, silently producing a loader path that matched nothing. Such a string now raisesArgumentErrorwith the same message given for any other string attribute name. The bare wildcard"*", as inLoad(A).lazyload("*"), continues to be accepted.References: #13493
-
[orm] [bug] Calling
_orm.aliased()against a_sql.select()or_sql.union()/_sql.CompoundSelectconstruct, which previously failed with an obscureAttributeErrorregarding a missing.mapperattribute, now raises when using SQLAlchemy 2.1, and emits a deprecation warning under SQLAlchemy 2.0 as it coerces the construct into a subquery instead. This matches the behavior of other similar implicit SELECT-to-FROM coercions. Pull request courtesy Rens Groothuijsen.References: #6274
orm declarative
-
[bug] [orm declarative] Fixed issue where using PEP 593
Annotatedwrapping a PEP 695typealias, such asAnnotated[SomeTypeAlias, mapped_column()], would crash withAttributeError: __value__. The internalis_pep695()check incorrectly identified theAnnotatedtype as a PEP 695 type alias due to a quirk inAnnotated.__origin__returning the first type argument rather thanAnnotateditself.References: #13386
sql
-
[sql] [bug] Fixed issue where
_sql.Select.get_final_froms()would emit a deprecation warning when the statement made use of the PostgreSQL-specific expression argument to_sql.Select.distinct(); the same spurious warning would be emitted when stringifying such a statement without explicitly using a PostgreSQL dialect. The fix ensures that this 1.4-era warning is suppressed under both 2.0 and 2.1.Note that under SQLAlchemy 2.1, passing an expression to
_sql.Select.distinct()is deprecated overall, and is replaced by a new PostgreSQL-specific construct (see #12342).References: #13396
-
[sql] [bug] Fixed an issue in
Numericwhere theNumeric.decimal_return_scaleparameter was ignored when the DBAPI does not support native decimal objects (i.e.dialect.supports_native_decimalisFalse). In this path the result processor was computing the conversion scale fromNumeric.scaledirectly, bypassingNumeric.decimal_return_scaleentirely. The behavior now matchesFloat, which already used the correct_effective_decimal_return_scaleproperty. Pull request courtesy Kadir Can Ozden.References: #13424
-
[sql] [bug] Added auditing to the test suite which exercises the literal execute processors across all datatypes and dialects to ensure that string input is either appropriately rejected or correctly escaped. Literal execute processors are invoked when the
bindparam.literal_executeparameter is used with an explicitbindparam()object, which overrides DBAPI-native bind handling to render the value inline with the statement instead. Datatypes that were updated include the originally reported SQL ServerUuid/UNIQUEIDENTIFIERrendering which now escapes properly, theJSONPATHtype that's currently PostgreSQL-only, and a full family of numeric types stemming from the_types.Floatand_types.Numericbases which now coerce the value to a number, rejecting non-numeric input. Thanks to Javid Khan for helping to identify the issue.References: #13448
schema
-
[schema] [bug] Fixed an issue where
_schema.Table.to_metadata()reused column default and on-update objects, causing the defaults on the original columns to refer to the copied columns. Default generators, including sequences, and server-side defaults are now copied and remain associated with their respective columns and metadata collections. Applications that inspected these objects will now see distinct defaults on the copied table instead of the objects owned by the original table. Pull request courtesy Goutam Adwant.References: #13481
postgresql
-
[postgresql] [bug] [reflection] Fixed reflection of PostgreSQL CHECK constraints where an expression made up of multiple parenthesized sub-expressions, such as
(x IS NULL OR y IS NULL) AND (x IS NULL OR y IS NULL), would have its leading and trailing parentheses incorrectly stripped, producing an unbalanced and syntactically invalid reflected expression. Pull request courtesy Shaurya Singh.References: #13157
-
[postgresql] [bug] Fixed bug in the PostgreSQL dialect where a single quote in a sequence, table, or schema name, such as one supplied via a
schema_translate_mapor an explicitSequence, could result in a malformednextval()statement. The quote is now properly escaped. Pull request courtesy dxbjavid.References: #13429
sqlite
-
[sqlite] [bug] Reworked the regular expression that detects inline
UNIQUEcolumn constraints during SQLiteCREATE TABLEreflection so that the whitespace separating a column's type from a following clause is matched unambiguously. The previous pattern had three overlapping quantifiers that could each consume a space character, so a column definition carrying a long run of whitespace in the stored schema made_reflection.Inspector.get_unique_constraints()spend cubic time backtracking before returning. Fix courtesy of Javid Khan.References: #13419
mssql
-
[mssql] [bug] Tightened the construction of the ODBC connection string in the pyodbc connector (as well as the mssql-python connector in 2.1) so that the driver name, the names of pass-through connection parameters, and values containing
}are brace-quoted. Previously a}in the driver name or in a pass-through value, or a;in the name of a pass-through parameter, could close the surrounding token early and allow the remainder of the string to be interpreted as additional connection attributes. Pull request courtesy dxbjavid.References: #13380
tests
-
[tests] [bug] Fixed class-scoped pytest fixtures that were defined as instance methods using
self, which is deprecated as of pytest 9.1 and will be removed in pytest 10. Fixtures are now decorated with a compatibility@classmethoddecorator and useclsas the first parameter.References: #13392