2.1 Changelog

2.1.0b1

no release date

orm

  • [orm] [feature]

    The relationship.back_populates argument to 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 relationship.back_populates. This change allows type checkers and IDEs to confirm the argument for relationship.back_populates is valid. Thanks to Priyanshu Parikh for the help on suggesting and helping to implement this feature.

    References: #10050

  • [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 from the SessionEvents.after_bulk_update() and SessionEvents.after_bulk_delete().

    References: #10721

  • [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] [bug]

    The relationship.secondary parameter no longer uses Python eval() to evaluate the given string. This parameter when passed a string should resolve to a table name that’s present in the local MetaData collection only, and never needs to be any kind of Python expression otherwise. To use a real deferred callable based on a name that may not be locally present yet, use a lambda instead.

    References: #10564

  • [orm] [bug]

    Revised the set “binary” operators for the association proxy set() interface to correctly raise TypeError for invalid use of the |, &, ^, and - operators, as well as the in-place mutation versions of these methods, to match the behavior of standard Python set() as well as SQLAlchemy ORM’s “intstrumented” set implementation.

    References: #11349

  • [orm]

    Ignore Session.join_transaction_mode in all cases when the bind provided to the Session is an Engine. Previously if an event that executed before the session logic, like ConnectionEvents.engine_connect(), left the connection with an active transaction, the Session.join_transaction_mode behavior took place, leading to a surprising behavior.

    References: #11163

engine

  • [engine] [usecase]

    Added new execution option Connection.execution_options.driver_column_names. This option disables the “name normalize” step that takes place against the DBAPI cursor.description for uppercase-default backends like Oracle, and will cause the keys of a result set (e.g. named tuple names, dictionary keys in Row._mapping, etc.) to be exactly what was delivered in cursor.description. This is mostly useful for plain textual statements using text() or Connection.exec_driver_sql().

    References: #10789

  • [engine] [change]

    An empty sequence passed to any execute() method now raised a deprecation warning, since such an executemany is invalid. Pull request courtesy of Carlos Sousa.

    References: #9647

  • [engine] [bug]

    Adjusted URL parsing and stringification to apply url quoting to the “database” portion of the URL. This allows a URL where the “database” portion includes special characters such as question marks to be accommodated.

    References: #11234

sql

  • [sql] [change]

    the Numeric and Float SQL types have been separated out so that Float no longer inherits from Numeric; instead, they both extend from a common mixin NumericCommon. This corrects for some architectural shortcomings where numeric and float types are typically separate, and establishes more consistency with Integer also being a distinct type. The change should not have any end-user implications except for code that may be using isinstance() to test for the Numeric datatype; third party dialects which rely upon specific implementation types for numeric and/or float may also require adjustment to maintain compatibility.

    References: #5252

  • [sql] [change]

    The .c and .columns attributes on the Select and TextualSelect constructs, which are not instances of FromClause, have been removed completely, in addition to the .select() method as well as other codepaths which would implicitly generate a subquery from a Select without the need to explicitly call the Select.subquery() method.

    In the case of .c and .columns, these attributes were never useful in practice and have caused a great deal of confusion, hence were deprecated back in version 1.4, and have emitted warnings since that version. Accessing the columns that are specific to a Select construct is done via the Select.selected_columns attribute, which was added in version 1.4 to suit the use case that users often expected .c to accomplish. In the larger sense, implicit production of subqueries works against SQLAlchemy’s modern practice of making SQL structure as explicit as possible.

    Note that this is not related to the usual FromClause.c and FromClause.columns attributes, common to objects such as Table and Subquery, which are unaffected by this change.

    References: #10236

  • [sql] [bug]

    Fixed issue in name normalization (e.g. “uppercase” backends like Oracle) where using a TextualSelect would not properly maintain as uppercase column names that were quoted as uppercase, even though the TextualSelect includes a Column that explicitly holds this uppercase name.

    References: #10788

  • [sql] [bug]

    Enhanced the caching structure of the over.rows and over.range so that different numerical values for the rows / range fields are cached on the same cache key, to the extent that the underlying SQL does not actually change (i.e. “unbounded”, “current row”, negative/positive status will still change the cache key). This prevents the use of many different numerical range/rows value for a query that is otherwise identical from filling up the SQL cache.

    Note that the semi-private compiler method _format_frame_clause() is removed by this fix, replaced with a new method visit_frame_clause(). Third party dialects which may have referred to this method will need to change the name and revise the approach to rendering the correct SQL for that dialect.

    References: #11515

schema

  • [schema] [bug]

    The Float and Numeric types are no longer automatically considered as auto-incrementing columns when the Column.autoincrement parameter is left at its default of "auto" on a Column that is part of the primary key. When the parameter is set to True, a Numeric type will be accepted as an auto-incrementing datatype for primary key columns, but only if its scale is explicitly given as zero; otherwise, an error is raised. This is a change from 2.0 where all numeric types including floats were automatically considered as “autoincrement” for primary key columns.

    References: #11811

  • [schema]

    Deprecate Oracle only parameters Sequence.order, Identity.order and Identity.on_null. They should be configured using the dialect kwargs oracle_order and oracle_on_null.

    References: #10247

typing

  • [typing] [feature]

    The Row object now no longer makes use of an intermediary Tuple in order to represent its individual element types; instead, the individual element types are present directly, via new PEP 646 integration, now available in more recent versions of Mypy. Mypy 1.7 or greater is now required for statements, results and rows to be correctly typed. Pull request courtesy Yurii Karabas.

    References: #10635

asyncio

  • [asyncio] [change]

    Adapted all asyncio dialects, including aiosqlite, aiomysql, asyncmy, psycopg, asyncpg to use the generic asyncio connection adapter first added in #6521 for the aioodbc DBAPI, allowing these dialects to take advantage of a common framework.

    References: #10415

  • [asyncio] [change]

    Added an initialize step to the import of sqlalchemy.ext.asyncio so that greenlet will be imported only when the asyncio extension is first imported. Alternatively, the greenlet library is still imported lazily on first use to support use case that don’t make direct use of the SQLAlchemy asyncio extension.

    References: #10296

  • [asyncio] [change]

    Removed the compatibility async_fallback mode for async dialects, since it’s no longer used by SQLAlchemy tests. Also removed the internal function await_fallback() and renamed the internal function await_only() to await_(). No change is expected to user code.

mariadb

  • [mariadb] [usecase]

    Modified the MariaDB dialect so that when using the Uuid datatype with MariaDB >= 10.7, leaving the Uuid.native_uuid parameter at its default of True, the native UUID datatype will be rendered in DDL and used for database communication, rather than CHAR(32) (the non-native UUID type) as was the case previously. This is a behavioral change since 2.0, where the generic Uuid datatype delivered CHAR(32) for all MySQL and MariaDB variants. Support for all major DBAPIs is implemented including support for less common “insertmanyvalues” scenarios where UUID values are generated in different ways for primary keys. Thanks much to Volodymyr Kochetkov for delivering the PR.

    References: #10339

mssql

  • [mssql] [bug]

    Fix mssql+pyodbc issue where valid plus signs in an already-unquoted odbc_connect= (raw DBAPI) connection string are replaced with spaces.

    The pyodbc connector would unconditionally pass the odbc_connect value to unquote_plus(), even if it was not required. So, if the (unquoted) odbc_connect value contained PWD=pass+word that would get changed to PWD=pass word, and the login would fail. One workaround was to quote just the plus sign — PWD=pass%2Bword — which would then get unquoted to PWD=pass+word.

    References: #11250

misc

  • [change] [installation]

    Python 3.9 or above is now required; support for Python 3.8 and 3.7 is dropped as these versions are EOL.

    References: #10357, #12029

  • [change] [installation]

    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

  • [change] [setup]

    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.