2.1.6
Released: October 21, 2026
orm
-
[orm] [bug] Fixed issue where a
Sessionflush that replaced an expired object in the identity map with a newly flushed object of the same primary key would emit a SELECT to refresh the expired object, solely in order to determine whether to emit an "Identity map already had an identity" warning. This could occur when a row loaded within a transaction is rolled back and its primary key value is subsequently reused, and could lead to anAttributeErrorif the expired object were garbage collected during that load. The check now emits no SQL, and an expired object that is replaced in this way no longer causes the warning to be emitted.This change is also backported to: 2.0.56
References: #13711
-
[orm] [bug] [regression] Fixed regression caused by #13070 where using more than one
orm.with_loader_criteria()option for the same entity, where the criteria made use of correlated subqueries referring to that entity, would fail with aRecursionErrorwhen compiling.References: #13701
-
[orm] [bug] [regression] Fixed regression caused by the new implementation of
.params()for statements introduced in #7066, where parameter values passed to the.params()method of an ORM statement created usingSelect.from_statement()would not be applied when the statement was compiled without the compiled statement cache, such as when the cache was disabled or when the statement was stringified directly, leading to an error that a value is required for the bound parameter.References: #13709
orm extensions
-
[bug] [orm extensions] Fixed an issue in the
instrumentation_toplevelextension where unrelated classes inheriting fromtyping.Genericcould incorrectly raise aTypeErrorwhen using different instrumentation implementations. Pull request courtesy TomasCaruso10.This change is also backported to: 2.0.56
References: #13680
engine
-
[engine] [usecase] Added
make_url.keep_blank_valuesandURL.update_query_string.keep_blank_valuesparameters, which when set to True retain query string parameters with blank values such askey=in theURL.querydictionary as empty strings. This allows aURLwith empty-string query values to round trip throughURL.render_as_string()andmake_url(). The default behavior of omitting blank values is unchanged, as dialects may not accept an empty string for query parameters that are coerced to other types.References: #13697
sql
-
[sql] [bug] Fixed issues in cache key generation involving the DML constructs
Insert,UpdateandDelete. TheInsert.from_select.include_defaults,UpdateBase.return_defaults()andUpdateBase.return_defaults.supplemental_colsparameters/attributes are now considered as part of the cache key.This change is also backported to: 2.0.56
-
[sql] [bug] Fixed issue where the individual bound parameters generated for an "expanding" parameter, such as that of an IN expression, at statement execution time could take on the same name as another bound parameter in the same statement, causing the value of the other parameter to be silently replaced with that of an element of the IN list. Names are now disambiguated from one another in this scenario.
This change is also backported to: 2.0.56
References: #13695
asyncio
-
[asyncio] [bug] Fixed issue where calling
_asyncio.AsyncResult.unique()or_asyncio.AsyncResult.columns()on an_asyncio.AsyncResultwould have no effect on a subsequent call to_asyncio.AsyncResult.scalars()or_asyncio.AsyncResult.mappings(), as the resulting_asyncio.AsyncScalarResultor_asyncio.AsyncMappingResultwas built from the underlying synchronous result, which did not include those modifications. Unique filtering and column selection are now carried over in the same way as for_engine.Result.scalars()and_engine.Result.mappings(). Among other things, this allows_asyncio.AsyncSession.stream()to be used with a joined eager load against a collection, followed by.unique().scalars(), which would previously raise an error indicating that_asyncio.AsyncResult.unique()must be invoked.This change is also backported to: 2.0.56
References: #13688
-
[asyncio] [bug] Fixed issue where the
_asyncio.AsyncResult.freeze()method would fail to fetch rows from the result, producing a_engine.FrozenResultthat would raiseTypeErrorwhen invoked for a Core result, or raisingAttributeErrorimmediately for an ORM result that returns a single entity per row. The method now fully fetches all rows from the async cursor, honoring_asyncio.AsyncResult.unique()and_asyncio.AsyncResult.columns()in the same way as the synchronous_engine.Result.freeze()method.This change is also backported to: 2.0.56
References: #13689
-
[asyncio] [bug] Fixed regression caused by #12710 where a cancellation received by
_asyncio.AsyncConnection.close()was not handled properly, leaving the_asyncio.AsyncConnectionin an inconsistent state that could interfere with connections subsequently checked out from the pool. The connection is now fully closed in this case.This change is also backported to: 2.0.56
References: #13699
mysql
-
[mysql] [bug] Fixed issue where backslashes in the values of a
mysql.ENUMormysql.SETtype were not escaped when rendered in DDL, leading to incorrect values or a malformed statement under MySQL's defaultsql_mode. Backslashes are now escaped in the same way as for other string literals, unlessNO_BACKSLASH_ESCAPESis in effect. Pull request courtesy dxbjavid.This change is also backported to: 2.0.56
References: #13466