Skip to content

Releases: sqlalchemy/sqlalchemy

2.0.51

15 Jun 15:41

Choose a tag to compare

2.0.51

Released: June 15, 2026

orm

  • [orm] [bug] Fixed issue where _orm.subqueryload() combined with
    PropComparator.of_type() and PropComparator.and_() would
    silently drop the additional filter criteria, causing all related objects
    to be loaded instead of only those matching the filter. The
    LoaderCriteriaOption was being constructed against the base
    entity rather than the effective entity indicated by
    PropComparator.of_type(). Pull request courtesy Arya Rizky.

    References: #13207

  • [orm] [bug] Fixed bug where a failure during tpc_prepare() within
    _orm.Session.commit() for a two-phase session would raise
    IllegalStateChangeError instead of the original database
    exception. The internal _prepare_impl() method's error handler
    was unable to invoke _orm.SessionTransaction.rollback() due
    to a state-change guard, preventing proper cleanup and masking the
    underlying error.

    References: #13356

engine

  • [engine] [bug] Fixed issue where Result.freeze() would lose track of ambiguous
    column names present in the original CursorResult, causing
    key-based access on the thawed result to silently return a value instead of
    raising InvalidRequestError. The
    SimpleResultMetaData now accepts and propagates ambiguous key
    information so that frozen, thawed, and pickled results raise consistently
    for duplicate column names. Pull request courtesy Saurabh Kohli.

    References: #9427

sql

  • [sql] [bug] Fixed issue where _sql.StatementLambdaElement would proxy
    attribute access through the cached "expected" expression rather than the
    resolved expression, causing stale closure-bound parameter values to be
    used when a lambda statement was extended with non-lambda criteria such as
    an additional .where() clause. Courtesy cjc0013.

    References: #10827

postgresql

  • [postgresql] [bug] Repaired bug introduced in #13229 where a two-phase
    transaction recovery would not return the correct transaction
    identifier when generating the identifiers using the xid()
    method of the psycopg connection.

    References: #13355

  • [postgresql] [bug] Fixed regular expression in the pure Python hstore result processor,
    used when use_native_hstore=False is set, which could hang on
    malformed hstore text containing unterminated quoted segments with
    backslashes. Pull request courtesy dxbjavid.

    References: #13370

2.0.50

24 May 19:20

Choose a tag to compare

2.0.50

Released: May 24, 2026

orm

  • [orm] [bug] Fixed issue where using _orm.joinedload() with
    PropComparator.of_type() targeting a joined-table subclass combined
    with PropComparator.and_() referencing a column on that subclass
    would generate invalid SQL, where the subclass column was not adapted to
    the subquery alias. Pull request courtesy Joaquin Hui Gomez.

    References: #13203

  • [orm] [bug] Fixed issue where the presence of a SessionEvents.do_orm_execute()
    event hook would cause internal execution options such as yield_per and
    loader-specific state from the first orm_pre_session_exec pass to leak
    into the second pass, leading to errors when using relationship loaders
    such as selectinload() and immediateload(). The execution
    options passed to the second compilation pass are now based on the original
    options plus only the explicit updates made via
    ORMExecuteState.update_execution_options() within the event hook.

    References: #13301

  • [orm] [bug] Fixed issue where using _orm.with_polymorphic() on a leaf class (a
    subclass with no further descendants) or a non-inherited class would fail
    with an AttributeError when used in an ORM statement, due to
    _orm.configure_mappers() not being triggered implicitly. The fix
    ensures that AliasedInsp participates in the _post_inspect
    hook, triggering mapper configuration during ORM statement compilation.

    References: #13319

sql

  • [sql] [bug] Fixed issue where floor division (//) between a Float or
    Numeric numerator and an Integer denominator would omit
    the FLOOR() SQL wrapper on dialects where
    Dialect.div_is_floordiv is True (the default, including
    PostgreSQL and SQLite). FLOOR() is now applied if either the
    denominator or the numerator is a non-integer, so that expressions such as
    float_col // int_col render as FLOOR(float_col / int_col) instead
    of the incorrect float_col / int_col. Pull request courtesy r266-tech.

    References: #10528

postgresql

  • [postgresql] [bug] Improve handling of two phase transaction identifiers for PostgreSQL
    when the identifier is provided by the user.
    As part of this change the psycopg dialect was updated to use the DBAPI
    two phase transaction API instead of executing the SQL directly.

    References: #13229

  • [postgresql] [bug] Fixed issue where the asyncpg driver could throw an insufficiently-handled
    exception InternalClientError under some circumstances, leading to
    connections not being properly marked as invalidated.

    References: #13241

  • [postgresql] [bug] Fixed issue where the ExcludeConstraint construct did not
    correctly forward the ExcludeConstraint.info parameter to
    the superclass, causing user-defined metadata to be lost. Pull request
    courtesy Wiktor Byrka.

    References: #13317

mysql

  • [mysql] [bug] [reflection] Narrowed the scope of the internal workaround for MySQL bugs #88718 and #96365 so that it is only applied
    where needed: MySQL 8.0.1 through 8.0.13 (where bug 88718 is present), and
    on systems with lower_case_table_names=2 (where bug 96365 applies,
    typically macOS). Previously the workaround was applied unconditionally
    for all MySQL 8.0+ versions, which caused a KeyError during foreign key
    reflection when the database user lacked SELECT privileges on referred
    tables.

    References: #13243

  • [mysql] [bug] Fixed issue in aiomysql and asyncmy dialects that appears as of using
    pymysql 1.2.0; the dialects were not properly taking into account logic
    that detects the argument signature of pymysql's ping() method which
    was added as part of #10492.

    References: #13306

sqlite

  • [sqlite] [bug] Escape key and pragma values when utilizing the pysqlcipher dialect.

    References: #13230

2.1.0b2

16 Apr 20:16

Choose a tag to compare

2.1.0b2 Pre-release
Pre-release

2.1.0b2

Released: April 16, 2026

orm

  • [orm] [usecase] The metadata, type_annotation_map, or registry can now be
    set up in a declarative base also via a mixin class, not only by
    directly setting them on the subclass like before.
    The declarative class setup now uses getattr() to look for these
    attributes, instead of relying only on the class __dict__.

    References: #13198

sql

  • [sql] [usecase] Added new parameter _sql.over.exclude to _sql.over() and
    related methods, enabling SQL standard frame exclusion clauses EXCLUDE CURRENT ROW, EXCLUDE GROUP, EXCLUDE TIES, EXCLUDE NO OTHERS
    in window functions. Pull request courtesy of Varun Chawla.

    References: #11671

  • [sql] [usecase] The ColumnCollection class hierarchy has been refactored to allow
    column names such as add, remove, update, extend, and
    clear to be used without conflicts. ColumnCollection is now
    an abstract base class, with mutation operations moved to
    WriteableColumnCollection and DedupeColumnCollection
    subclasses. The ReadOnlyColumnCollection exposed as attributes
    such as Table.c no longer includes mutation methods that raised
    NotImplementedError, allowing these common column names to be
    accessed naturally, e.g. table.c.add, table.c.remove,
    table.c.update, etc.

  • [sql] [bug] A warning is emitted when using the standalone _sql.distinct()
    function in a _sql.select() columns list outside of an aggregate
    function; this function is not intended as a replacement for the use of
    Select.distinct(). Pull request courtesy bekapono.

    References: #11526

  • [sql] [bug] Improved the ability for TypeDecorator to produce a correct
    repr() for "schema" types such as Enum and Boolean.
    This is mostly to support the Alembic autogenerate use case so that custom
    types render with relevant arguments present. Improved the architecture
    used by TypeEngine to produce repr() strings to be more
    modular for compound types like TypeDecorator.

    References: #13140

schema

  • [schema] [usecase] Most _sql.FromClause subclasses are now generic on
    _schema.TypedColumns subclasses, that can be used to type their
    _sql.FromClause.c collection.
    This applied to _schema.Table, _sql.Join,
    _sql.Subquery, _sql.CTE and more.

    References: #13085

  • [schema] [bug] Amended the repr() output for Enum so that the
    MetaData is not shown in the output, as this interferes with
    Alembic-autogenerated forms of this type which should be inheriting the
    MetaData of the parent table in the migration script.

    References: #10604

typing

  • [typing] [bug] Fixed issue in new PEP 646 support for result sets where an issue in the
    mypy type checker prevented "scalar" methods including
    Connection.scalar(), Result.scalar(),
    _orm.Session.scalar(), as well as async versions of these methods
    from applying the correct type to the scalar result value, when the columns
    in the originating _sql.select() were typed as Any. Pull request
    courtesy Yurii Karabas.

    References: #13091

  • [typing] [bug] Improved typing of _sqltypes.JSON as well as dialect specific
    variants like _postgresql.JSON to include generic capabilities, so
    that the types may be parameterized to indicate any specific type of
    contents expected, e.g. JSONB[list[str]]().

    References: #13131

mssql

  • [mssql] [feature] Added support for the mssql-python driver, Microsoft's official Python
    driver for SQL Server.

    References: #12869

oracle

  • [oracle] [feature] Added support for the _sqltypes.JSON datatype when using the
    Oracle database with the oracledb dialect. JSON values are serialized and
    deserialized using configurable strategies that accommodate Oracle's native
    JSON type available as of Oracle 21c. Pull request courtesy Abdallah
    Alhadad.

    References: #10375

2.0.49

03 Apr 16:38

Choose a tag to compare

2.0.49

Released: April 3, 2026

orm

  • [orm] [bug] Fixed issue where _orm.Session.get() would bypass the identity map
    and emit unnecessary SQL when with_for_update=False was passed,
    rather than treating it equivalently to the default of None.
    Pull request courtesy of Joshua Swanson.

    References: #13176

  • [orm] [bug] Fixed issue where chained _orm.joinedload() options would not be
    applied correctly when the final relationship in the chain is declared on a
    base mapper and accessed through a subclass mapper in a
    _orm.with_polymorphic() query. The path registry now correctly
    computes the natural path when a property declared on a base class is
    accessed through a path containing a subclass mapper, ensuring the loader
    option can be located during query compilation.

    References: #13193

  • [orm] [bug] [inheritance] Fixed issue where using _orm.Load.options() to apply a chained loader
    option such as _orm.joinedload() or _orm.selectinload() with
    _orm.PropComparator.of_type() for a polymorphic relationship would
    not generate the necessary clauses for the polymorphic subclasses. The
    polymorphic loading strategy is now correctly propagated when using a call
    such as joinedload(A.b).options(joinedload(B.c.of_type(poly))) to match
    the behavior of direct chaining e.g.
    joinedload(A.b).joinedload(B.c.of_type(poly)).

    References: #13202

  • [orm] [bug] [inheritance] Fixed issue where using chained loader options such as
    _orm.selectinload() after _orm.joinedload() with
    _orm.PropComparator.of_type() for a polymorphic relationship would
    not properly apply the chained loader option. The loader option is now
    correctly applied when using a call such as
    joinedload(A.b.of_type(poly)).selectinload(poly.SubClass.c) to eagerly
    load related objects.

    References: #13209

typing

  • [typing] [bug] Fixed a typing issue where the typed members of :data:.func would return
    the appropriate class of the same name, however this creates an issue for
    typecheckers such as Zuban and pyrefly that assume PEP 749 style
    typechecking even if the file states that it's a PEP 563 file; they see
    the returned name as indicating the method object and not the class object.
    These typecheckers are actually following along with an upcoming test
    harness that insists on PEP 749 style name resolution for this case
    unconditionally. Since PEP 749 is the way of the future regardless,
    differently-named type aliases have been added for these return types.

    Unknown interpreted text role "data".

    References: #13167

postgresql

  • [postgresql] [bug] Fixed regular expression used when reflecting foreign keys in PostgreSQL to
    support escaped quotes in table names.
    Pull request courtesy of Austin Graham

    References: #10902

mssql

  • [mssql] [usecase] Enhanced the aioodbc dialect to expose the fast_executemany
    attribute of the pyodbc cursor. This allows the fast_executemany
    parameter to work with the mssql+aioodbc dialect. Pull request
    courtesy Georg Sieber.

    References: #13152

  • [mssql] [usecase] Remove warning for SQL Server dialect when a new version is detected.
    The warning was originally added more than 15 years ago due to an unexpected
    value returned when using an old version of FreeTDS.
    The assumption is that since then the issue has been resolved, so make the
    SQL Server dialect behave like the other ones that don't have an upper bound
    check on the version number.

    References: #13185

  • [mssql] [bug] [reflection] Fixed regression from version 2.0.42 caused by #12654 where the
    updated column reflection query would receive SQL Server "type alias" names
    for special types such as sysname, whereas previously the base name
    would be received (e.g. nvarchar for sysname), leading to warnings
    that such types could not be reflected and resulting in NullType,
    rather than the expected NVARCHAR for a type like sysname.
    The column reflection query now joins sys.types a second time to look
    up the base type when the user type name is not present in
    MSDialect.ischema_names, and both names are checked in
    MSDialect.ischema_names for a match. Pull request courtesy Carlos
    Serrano.

    References: #13181, #13182

oracle

  • [oracle] [bug] Fixed issue in Oracle dialect where the _oracle.RAW datatype would
    not reflect the length parameter. Pull request courtesy Daniel Sullivan.

    References: #13150

2.0.48

02 Mar 15:28

Choose a tag to compare

2.0.48

Released: March 2, 2026

engine

  • [engine] [bug] Fixed a critical issue in Engine where connections created in
    conjunction with the DialectEvents.do_connect() event listeners
    would receive shared, mutable collections for the connection arguments,
    leading to a variety of potential issues including unlimited growth of the
    argument list as well as elements within the parameter dictionary being
    shared among concurrent connection calls. In particular this could impact
    do_connect routines making use of complex mutable authentication
    structures.

    References: #13144

2.0.47

24 Feb 16:34

Choose a tag to compare

2.0.47

Released: February 24, 2026

orm

  • [orm] [bug] Fixed issue when using ORM mappings with Python 3.14's PEP 649 feature
    that no longer requires "future annotations", where the ORM's introspection
    of the __init__ method of mapped classes would fail if non-present
    identifiers in annotations were present. The vendored getfullargspec()
    method has been amended to use Format.FORWARDREF under Python 3.14 to
    prevent resolution of names that aren't present.

    References: #13104

engine

  • [engine] [usecase] The connection object returned by _engine.Engine.raw_connection()
    now supports the context manager protocol, automatically returning the
    connection to the pool when exiting the context.

    References: #13116

postgresql

  • [postgresql] [bug] Fixed an issue in the PostgreSQL dialect where foreign key constraint
    reflection would incorrectly swap or fail to capture onupdate and
    ondelete values when these clauses appeared in a different order than
    expected in the constraint definition. This issue primarily affected
    PostgreSQL-compatible databases such as CockroachDB, which may return ON DELETE before ON UPDATE in the constraint definition string. The
    reflection logic now correctly parses both clauses regardless of their
    ordering.

    References: #13105

  • [postgresql] [bug] Fixed issue in the engine_insertmanyvalues feature where using
    PostgreSQL's ON CONFLICT clause with
    _dml.Insert.returning.sort_by_parameter_order enabled would
    generate invalid SQL when the insert used an implicit sentinel (server-side
    autoincrement primary key). The generated SQL would incorrectly declare a
    sentinel counter column in the imp_sen table alias without providing
    corresponding values in the VALUES clause, leading to a
    ProgrammingError indicating column count mismatch. The fix allows batch
    execution mode when embed_values_counter is active, as the embedded
    counter provides the ordering capability needed even with upsert behaviors,
    rather than unnecessarily downgrading to row-at-a-time execution.

    References: #13107

  • [postgresql] [bug] Fixed issue where _postgresql.Insert.on_conflict_do_update()
    parameters were not respecting compilation options such as
    literal_binds=True. Pull request courtesy LoΓ―c Simon.

    References: #13110

  • [postgresql] [bug] Fixed issue where _postgresql.Insert.on_conflict_do_update()
    using parametrized bound parameters in the set_ clause would fail
    when used with executemany batching. For dialects that use the
    use_insertmanyvalues_wo_returning optimization (psycopg2),
    insertmanyvalues is now disabled when there is an ON CONFLICT clause.
    For cases with RETURNING, row-at-a-time mode is used when the SET
    clause contains parametrized bindparams (bindparams that receive
    values from the parameters dict), ensuring each row's parameters are
    correctly applied. ON CONFLICT statements using expressions like
    excluded.<column> continue to batch normally.

    References: #13130

mysql

  • [mysql] [bug] Fixed issue where DDL compilation options were registered to the hard-coded
    dialect name mysql. This made it awkward for MySQL-derived dialects
    like MariaDB, StarRocks, etc. to work with such options when different sets
    of options exist for different platforms. Options are now registered under
    the actual dialect name, and a fallback was added to help avoid errors when
    an option does not exist for that dialect.

    To maintain backwards compatibility, when using the MariaDB dialect with
    the options mysql_with_parser or mysql_using without also specifying
    the corresponding mariadb_ prefixed options, a deprecation warning will
    be emitted. The mysql_ prefixed options will continue to work during
    the deprecation period. Users should update their code to additionally
    specify mariadb_with_parser and mariadb_using when using the
    mariadb:// dialect, or specify both options to support both dialects.

    Pull request courtesy Tiansu Yu.

    References: #13134

sqlite

  • [sqlite] [bug] Fixed issue where _sqlite.Insert.on_conflict_do_update()
    parameters were not respecting compilation options such as
    literal_binds=True. Pull request courtesy LoΓ―c Simon.

    References: #13110

  • [sqlite] [bug] Fixed issue where _sqlite.Insert.on_conflict_do_update()
    using parametrized bound parameters in the set_ clause would fail
    when used with executemany batching. Row-at-a-time mode is now used
    for ON CONFLICT statements with RETURNING that contain parametrized
    bindparams, ensuring each row's parameters are correctly applied. ON
    CONFLICT statements using expressions like excluded.<column>
    continue to batch normally.

    References: #13130

2.0.46

21 Jan 18:03

Choose a tag to compare

2.0.46

Released: January 21, 2026

typing

  • [typing] [bug] Fixed typing issues where ORM mapped classes and aliased entities could not
    be used as keys in result row mappings or as join targets in select
    statements. Patterns such as row._mapping[User],
    row._mapping[aliased(User)], row._mapping[with_polymorphic(...)]
    (rejected by both mypy and Pylance), and .join(aliased(User))
    (rejected by Pylance) are documented and fully supported at runtime but
    were previously rejected by type checkers. The type definitions for
    _KeyType and _FromClauseArgument have been updated to
    accept these ORM entity types.

    References: #13075

postgresql

  • [postgresql] [bug] Fixed issue where PostgreSQL JSONB operators
    _postgresql.JSONB.Comparator.path_match() and
    _postgresql.JSONB.Comparator.path_exists() were applying incorrect
    VARCHAR casts to the right-hand side operand when used with newer
    PostgreSQL drivers such as psycopg. The operators now indicate the
    right-hand type as JSONPATH, which currently results in no casting
    taking place, but is also compatible with explicit casts if the
    implementation were require it at a later point.

    References: #13059

  • [postgresql] [bug] Fixed regression in PostgreSQL dialect where JSONB subscription syntax
    would generate incorrect SQL for cast() expressions returning JSONB,
    causing syntax errors. The dialect now properly wraps cast expressions in
    parentheses when using the [] subscription syntax, generating
    (CAST(...))[index] instead of CAST(...)[index] to comply with
    PostgreSQL syntax requirements. This extends the fix from #12778
    which addressed the same issue for function calls.

    References: #13067

  • [postgresql] [bug] Improved the foreign key reflection regular expression pattern used by the
    PostgreSQL dialect to be more permissive in matching identifier characters,
    allowing it to correctly handle unicode characters in table and column
    names. This change improves compatibility with PostgreSQL variants such as
    CockroachDB that may use different quoting patterns in combination with
    unicode characters in their identifiers. Pull request courtesy Gord
    Thompson.

mariadb

  • [mariadb] [bug] Fixed the SQL compilation for the mariadb sequence "NOCYCLE" keyword that
    is to be emitted when the Sequence.cycle parameter is set to
    False on a Sequence. Pull request courtesy Diego Dupin.

    References: #13070

sqlite

  • [sqlite] [bug] Fixed issue in the aiosqlite driver where SQLAlchemy's setting of
    aiosqlite's worker thread to "daemon" stopped working because the aiosqlite
    architecture moved the location of the worker thread in version 0.22.0.
    This "daemon" flag is necessary so that a program is able to exit if the
    SQLite connection itself was not explicitly closed, which is particularly
    likely with SQLAlchemy as it maintains SQLite connections in a connection
    pool. While it's perfectly fine to call AsyncEngine.dispose()
    before program exit, this is not historically or technically necessary for
    any driver of any known backend, since a primary feature of relational
    databases is durability. The change also implements support for
    "terminate" with aiosqlite when using version version 0.22.1 or greater,
    which implements a sync .stop() method.

    References: #13039

mssql

  • [mssql] [usecase] Added support for the IF EXISTS clause when dropping indexes on SQL
    Server 2016 (13.x) and later versions. The DropIndex.if_exists
    parameter is now honored by the SQL Server dialect, allowing conditional
    index drops that will not raise an error if the index does not exist.
    Pull request courtesy Edgar RamΓ­rez MondragΓ³n.

    References: #13045

2.1.0b1

21 Jan 20:56

Choose a tag to compare

2.1.0b1 Pre-release
Pre-release

2.1.0b1

Released: January 21, 2026

platform

  • [platform] [feature] Free-threaded Python versions are now supported in wheels released on Pypi.
    This integrates with overall free-threaded support added as part of
    #12881 for the 2.0 and 2.1 series, which includes new test suites
    as well as a few improvements to race conditions observed under
    freethreading.

    References: #12881

  • [platform] [change] The greenlet dependency used for asyncio support no longer installs
    by default. This dependency does not publish wheel files for every architecture
    and is not needed for applications that aren't using asyncio features.
    Use the sqlalchemy[asyncio] install target to include this dependency.

    References: #10197

  • [platform] [change] Updated the setup manifest definition to use PEP 621-compliant
    pyproject.toml. Also updated the extra install dependency to comply with
    PEP-685. Thanks for the help of Matt Oberle and KOLANICH on this change.

  • [platform] [change] Python 3.10 or above is now required; support for Python 3.9, 3.8 and 3.7
    is dropped as these versions are EOL.

    References: #10357, #12029, #12819

orm

  • [orm] [feature] The _orm.relationship.back_populates argument to
    _orm.relationship() may now be passed as a Python callable, which
    resolves to either the direct linked ORM attribute, or a string value as
    before. ORM attributes are also accepted directly by
    _orm.relationship.back_populates. This change allows type
    checkers and IDEs to confirm the argument for
    _orm.relationship.back_populates is valid. Thanks to Priyanshu
    Parikh for the help on suggesting and helping to implement this feature.

    References: #10050

  • [orm] [feature] Added new hybrid method hybrid_property.bulk_dml() which
    works in a similar way as hybrid_property.update_expression() for
    bulk ORM operations. A user-defined class method can now populate a bulk
    insert mapping dictionary using the desired hybrid mechanics. New
    documentation is added showing how both of these methods can be used
    including in combination with the new _sql.from_dml_column()
    construct.

    References: #12496

  • [orm] [feature] Added new parameter _orm.composite.return_none_on to
    _orm.composite(), which allows control over if and when this
    composite attribute should resolve to None when queried or retrieved
    from the object directly. By default, a composite object is always present
    on the attribute, including for a pending object which is a behavioral
    change since 2.0. When _orm.composite.return_none_on is
    specified, a callable is passed that returns True or False to indicate if
    the given arguments indicate the composite should be returned as None. This
    parameter may also be set automatically when ORM Annotated Declarative is
    used; if the annotation is given as Mapped[SomeClass|None], a
    _orm.composite.return_none_on rule is applied that will return
    None if all contained columns are themselves None.

    References: #12570

  • [orm] [feature] Added support for per-session execution options that are merged into all
    queries executed within that session. The _orm.Session,
    _orm.sessionmaker, _orm.scoped_session,
    _ext.asyncio.AsyncSession, and
    _ext.asyncio.async_sessionmaker constructors now accept an
    _orm.Session.execution_options parameter that will be applied
    to all explicit query executions (e.g. using _orm.Session.execute(),
    _orm.Session.get(), _orm.Session.scalars()) for that session
    instance.

    References: #12659

  • [orm] [feature] Session autoflush behavior has been simplified to unconditionally flush the
    session each time an execution takes place, regardless of whether an ORM
    statement or Core statement is being executed. This change eliminates the
    previous conditional logic that only flushed when ORM-related statements
    were detected, which had become difficult to define clearly with the unified
    v2 syntax that allows both Core and ORM execution patterns. The change
    provides more consistent and predictable session behavior across all types
    of SQL execution.

    References: #9809

  • [orm] [feature] Added _orm.RegistryEvents event class that allows event listeners
    to be established on a _orm.registry object. The new class
    provides three events: _orm.RegistryEvents.resolve_type_annotation()
    which allows customization of type annotation resolution that can
    supplement or replace the use of the
    registry.type_annotation_map dictionary, including that it can
    be helpful with custom resolution for complex types such as those of
    PEP 695, as well as _orm.RegistryEvents.before_configured() and
    _orm.RegistryEvents.after_configured(), which are registry-local
    forms of the mapper-wide version of these hooks.

    References: #9832

  • [orm] [usecase] The _orm.Session.flush.objects parameter is now
    deprecated.

    References: #10816

  • [orm] [usecase] Added the utility method _orm.Session.merge_all() and
    _orm.Session.delete_all() that operate on a collection
    of instances.

    References: #11776

  • [orm] [usecase] Added support for using _orm.with_expression() to populate a
    _orm.query_expression() attribute that is also configured as the
    polymorphic_on discriminator column. The ORM now detects when a query
    expression column is serving as the polymorphic discriminator and updates
    it to use the column provided via _orm.with_expression(), enabling
    polymorphic loading to work correctly in this scenario. This allows for
    patterns such as where the discriminator value is computed from a related
    table.

    References: #12631

  • [orm] [usecase] Added default implementations of ColumnOperators.desc(),
    ColumnOperators.asc(), ColumnOperators.nulls_first(),
    ColumnOperators.nulls_last() to _orm.composite() attributes,
    by default applying the modifier to all contained columns. Can be
    overridden using a custom comparator.

    References: #12769

  • [orm] [usecase] The _orm.aliased() object now emits warnings when an attribute is
    accessed on an aliased class that cannot be located in the target
    selectable, for those cases where the _orm.aliased() is against a
    different FROM clause than the regular mapped table (such as a subquery).
    This helps users identify cases where column names don't match between the
    aliased class and the underlying selectable. When
    _orm.aliased.adapt_on_names is True, the warning suggests
    checking the column name; when False, it suggests using the
    adapt_on_names parameter for name-based matching.

    References: #12838

  • [orm] [usecase] Improvements to the use case of using Declarative Dataclass Mapping <orm_declarative_native_dataclasses> with intermediary classes that are
    unmapped. As was the existing behavior, classes can subclass
    _orm.MappedAsDataclass alone without a declarative base to act as
    mixins, or along with a declarative base as well as __abstract__ = True
    to define an abstract base. However, the improved behavior scans ORM
    attributes like _orm.mapped_column() in this case to create correct
    dataclasses.field() constructs based on their arguments, allowing for
    more natural ordering of fields without dataclass errors being thrown.
    Additionally, added a new _orm.unmapped_dataclass() decorator
    function, which may be used to create unmapped mixins in a mapped hierarchy
    that is using the _orm.mapped_dataclass() decorator to create mapped
    dataclasses.

    References: #12854

  • [orm] [usecase] Added _orm.DictBundle as a subclass of _orm.Bundle
    that returns dict objects.

    References: #12960

  • [orm] [change] A sweep through class and function names in the ORM renames many classes
    and functions that have no intent of public visibility to be underscored.
    This is to reduce ambiguity as to which APIs are intended to be targeted by
    third party applications and extensions. Third parties are encouraged to
    propose new public APIs in Discussions to the extent they are needed to
    replace those that have been clarified as private.

    References: #10497

  • [orm] [change] The first_init ORM event has been removed. This event was
    non-functional throughout the 1.4 and 2.0 series and could not be invoked
    without raising an internal error, so it is not expected that there is any
    real-world use of this event hook.

    References: #10500

  • [orm] [change] Removed legacy signatures dating back to 0.9 release fro...

Read more

2.0.45

09 Dec 21:05

Choose a tag to compare

2.0.45

Released: December 9, 2025

orm

  • [orm] [bug] Fixed issue where calling Mapper.add_property() within mapper event
    hooks such as MapperEvents.instrument_class(),
    MapperEvents.after_mapper_constructed(), or
    MapperEvents.before_mapper_configured() would raise an
    AttributeError because the mapper's internal property collections were
    not yet initialized. The Mapper.add_property() method now handles
    early-stage property additions correctly, allowing properties including
    column properties, deferred columns, and relationships to be added during
    mapper initialization events. Pull request courtesy G Allajmi.

    References: #12858

  • [orm] [bug] Fixed issue in Python 3.14 where dataclass transformation would fail when
    a mapped class using MappedAsDataclass included a
    relationship() referencing a class that was not available at
    runtime (e.g., within a TYPE_CHECKING block). This occurred when using
    Python 3.14's PEP 649 deferred annotations feature, which is the
    default behavior without a from __future__ import annotations
    directive.

    References: #12952

examples

  • [examples] [bug] Fixed the "short_selects" performance example where the cache was being
    used in all the examples, making it impossible to compare performance with
    and without the cache. Less important comparisons like "lambdas" and
    "baked queries" have been removed.

sql

  • [sql] [bug] Some improvements to the _sql.ClauseElement.params() method to
    replace bound parameters in a query were made, however the ultimate issue
    in #12915 involving ORM _orm.aliased() cannot be fixed fully
    until 2.1, where the method is being rewritten to work without relying on
    Core cloned traversal.

    References: #12915

  • [sql] [bug] Fixed issue where using the ColumnOperators.in_() operator with a
    nested CompoundSelect statement (e.g. an INTERSECT of
    UNION queries) would raise a NotImplementedError when the
    nested compound select was the first argument to the outer compound select.
    The _scalar_type() internal method now properly handles nested compound
    selects.

    References: #12987

typing

  • [typing] [bug] Fixed typing issue where Select.with_for_update() would not support
    lists of ORM entities or other FROM clauses in the
    Select.with_for_update.of parameter. Pull request courtesy
    Shamil.

    References: #12730

  • [typing] [bug] Fixed typing issue where coalesce would not return the correct
    return type when a nullable form of that argument were passed, even though
    this function is meant to select the non-null entry among possibly null
    arguments. Pull request courtesy Yannick PÉROUX.

postgresql

  • [postgresql] [usecase] Added support for reflection of collation in types for PostgreSQL.
    The collation will be set only if different from the default
    one for the type.
    Pull request courtesy Denis Laxalde.

    References: #6511

  • [postgresql] [bug] Fixed issue where PostgreSQL dialect options such as postgresql_include
    on PrimaryKeyConstraint and UniqueConstraint were
    rendered in the wrong position when combined with constraint deferrability
    options like deferrable=True. Pull request courtesy G Allajmi.

    References: #12867

  • [postgresql] [bug] Fixed the structure of the SQL string used for the
    engine_insertmanyvalues feature when an explicit sequence with
    nextval() is used. The SQL function invocation for the sequence has
    been moved from being rendered inline within each tuple inside of VALUES to
    being rendered once in the SELECT that reads from VALUES. This change
    ensures the function is invoked in the correct order as rows are processed,
    rather than assuming PostgreSQL will execute inline function calls within
    VALUES in a particular order. While current PostgreSQL versions appear to
    handle the previous approach correctly, the database does not guarantee
    this behavior for future versions.

    References: #13015

mysql

  • [mysql] [usecase] Added support for MySQL 8.0.1 + FOR SHARE to be emitted for the
    Select.with_for_update() method, which offers compatibility with
    NOWAIT and SKIP LOCKED. The new syntax is used only for MySQL when
    version 8.0.1 or higher is detected. Pull request courtesy JetDrag.

    References: #12964

sqlite

  • [sqlite] [bug] [reflection] A series of improvements have been made for reflection of CHECK constraints
    on SQLite. The reflection logic now correctly handles table names
    containing the strings "CHECK" or "CONSTRAINT", properly supports all four
    SQLite identifier quoting styles (double quotes, single quotes, brackets,
    and backticks) for constraint names, and accurately parses CHECK constraint
    expressions containing parentheses within string literals using balanced
    parenthesis matching with string context tracking. Big thanks to
    GruzdevAV for new test cases and implementation ideas.

    References: #12924

  • [sqlite] [bug] Fixed issue where SQLite dialect would fail to reflect constraint names
    that contained uppercase letters or other characters requiring quoting. The
    regular expressions used to parse primary key, foreign key, and unique
    constraint names from the CREATE TABLE statement have been updated to
    properly handle both quoted and unquoted constraint names.

    References: #12954

tests

  • [tests] [change] A noxfile.py has been added to allow testing with nox. This is a direct
    port of 2.1's move to nox, however leaves the tox.ini file in place and
    retains all test documentation in terms of tox. Version 2.1 will move to
    nox fully, including deprecation warnings for tox and new testing
    documentation.

2.0.44

10 Oct 14:39

Choose a tag to compare

2.0.44

Released: October 10, 2025

platform

  • [platform] [bug] Unblocked automatic greenlet installation for Python 3.14 now that
    there are greenlet wheels on pypi for python 3.14.

orm

  • [orm] [usecase] The way ORM Annotated Declarative interprets Python PEP 695 type aliases
    in Mapped[] annotations has been refined to expand the lookup scheme. A
    PEP 695 type can now be resolved based on either its direct presence in
    _orm.registry.type_annotation_map or its immediate resolved
    value, as long as a recursive lookup across multiple PEP 695 types is
    not required for it to resolve. This change reverses part of the
    restrictions introduced in 2.0.37 as part of #11955, which
    deprecated (and disallowed in 2.1) the ability to resolve any PEP 695
    type that was not explicitly present in
    _orm.registry.type_annotation_map. Recursive lookups of
    PEP 695 types remains deprecated in 2.0 and disallowed in version 2.1,
    as do implicit lookups of NewType types without an entry in
    _orm.registry.type_annotation_map.

    Additionally, new support has been added for generic PEP 695 aliases that
    refer to PEP 593 Annotated constructs containing
    _orm.mapped_column() configurations. See the sections below for
    examples.

    References: #12829

  • [orm] [bug] Fixed a caching issue where _orm.with_loader_criteria() would
    incorrectly reuse cached bound parameter values when used with
    _sql.CompoundSelect constructs such as _sql.union(). The
    issue was caused by the cache key for compound selects not including the
    execution options that are part of the _sql.Executable base class,
    which _orm.with_loader_criteria() uses to apply its criteria
    dynamically. The fix ensures that compound selects and other executable
    constructs properly include execution options in their cache key traversal.

    References: #12905

engine

  • [engine] [bug] Implemented initial support for free-threaded Python by adding new tests
    and reworking the test harness to include Python 3.13t and Python 3.14t in
    test runs. Two concurrency issues have been identified and fixed: the first
    involves initialization of the .c collection on a FromClause, a
    continuation of #12302, where an optional mutex under
    free-threading is added; the second involves synchronization of the pool
    "first_connect" event, which first received thread synchronization in
    #2964, however under free-threading the creation of the mutex
    itself runs under the same free-threading mutex. Support for free-threaded
    wheels on Pypi is implemented as well within the 2.1 series only. Initial
    pull request and test suite courtesy Lysandros Nikolaou.

    References: #12881

sql

  • [sql] [bug] Improved the implementation of UpdateBase.returning() to use more
    robust logic in setting up the .c collection of a derived statement
    such as a CTE. This fixes issues related to RETURNING clauses that feature
    expressions based on returned columns with or without qualifying labels.

    References: #12271

schema

  • [schema] [bug] Fixed issue where _schema.MetaData.reflect() did not forward
    dialect-specific keyword arguments to the _engine.Inspector
    methods, causing options like oracle_resolve_synonyms to be ignored
    during reflection. The method now ensures that all extra kwargs passed to
    _schema.MetaData.reflect() are forwarded to
    _engine.Inspector.get_table_names() and related reflection methods.
    Pull request courtesy LukΓ‘Ε‘ KoΕΎuΕ‘nΓ­k.

    References: #12884

typing

  • [typing] [bug] Fixed typing bug where the Session.execute() method advertised that
    it would return a CursorResult if given an insert/update/delete
    statement. This is not the general case as several flavors of ORM
    insert/update do not actually yield a CursorResult which cannot
    be differentiated at the typing overload level, so the method now yields
    Result in all cases. For those cases where
    CursorResult is known to be returned and the .rowcount
    attribute is required, please use typing.cast().

    References: #12813

  • [typing] [bug] Added new decorator _orm.mapped_as_dataclass(), which is a function
    based form of _orm.registry.mapped_as_dataclass(); the method form
    _orm.registry.mapped_as_dataclass() does not seem to be correctly
    recognized within the scope of PEP 681 in recent mypy versions.

    References: #12855

asyncio

  • [asyncio] [usecase] Generalize the terminate logic employed by the asyncpg dialect to reuse
    it in the aiomysql and asyncmy dialect implementation.

    References: #12273

postgresql

  • [postgresql] [bug] Fixed issue where selecting an enum array column containing NULL values
    would fail to parse properly in the PostgreSQL dialect. The
    _split_enum_values() function now correctly handles NULL entries by
    converting them to Python None values.

    References: #12847

  • [postgresql] [bug] Fixed issue where the _sql.any_() and _sql.all_() aggregation
    operators would not correctly coerce the datatype of the compared value, in
    those cases where the compared value were not a simple int/str etc., such
    as a Python Enum or other custom value. This would lead to execution
    time errors for these values. This issue is essentially the same as
    #6515 which was for the now-legacy ARRAY.any() and
    ARRAY.all() methods.

    References: #12874

sqlite

  • [sqlite] [bug] Fixed issue where SQLite table reflection would fail for tables using
    WITHOUT ROWID and/or STRICT table options when the table contained
    generated columns. The regular expression used to parse CREATE TABLE
    statements for generated column detection has been updated to properly
    handle these SQLite table options that appear after the column definitions.
    Pull request courtesy Tip ten Brink.

    References: #12864

mssql

  • [mssql] [bug] Improved the base implementation of the asyncio cursor such that it
    includes the option for the underlying driver's cursor to be actively
    closed in those cases where it requires await in order to complete the
    close sequence, rather than relying on garbage collection to "close" it,
    when a plain Result is returned that does not use await for
    any of its methods. The previous approach of relying on gc was fine for
    MySQL and SQLite dialects but has caused problems with the aioodbc
    implementation on top of SQL Server. The new option is enabled
    for those dialects which have an "awaitable" cursor.close(), which
    includes the aioodbc, aiomysql, and asyncmy dialects (aiosqlite is also
    modified for 2.1 only).

    References: #12798

  • [mssql] [bug] Fixed issue where the index reflection for SQL Server would
    not correctly return the order of the column inside an index
    when the order of the columns in the index did not match the
    order of the columns in the table.
    Pull request courtesy of Allen Chen.

    References: #12894

  • [mssql] [bug] [reflection] Fixed issue in the MSSQL dialect's foreign key reflection query where
    duplicate rows could be returned when a foreign key column and its
    referenced primary key column have the same name, and both the referencing
    and referenced tables have indexes with the same name. This resulted in an
    "ForeignKeyConstraint with duplicate source column references are not
    supported" error when attempting to reflect such tables. The query has been
    corrected to exclude indexes on the child table when looking for unique
    indexes referenced by foreign keys.

    References: #12907

misc

  • [bug] [ext] Fixed issue caused by an unwanted functional change while typing
    the MutableList class.
    This change also reverts all other functional changes done in
    the same change.

    References: #12802