rel_2_0_38
Breaking Changes📦 sqlalchemyView on GitHub →
⚠ 1 breaking✨ 1 features🐛 6 fixes🔧 6 symbols
Summary
SQLAlchemy 2.0.38 introduces a new asyncio.shield() safeguard for asyncpg termination, fixes several bugs across engines and dialects, and changes the default aiosqlite pool, which may require a migration step.
⚠️ Breaking Changes
- The default connection pool for the aiosqlite dialect was changed from NullPool to AsyncAdaptedQueuePool, which may break code that relied on NullPool behavior. To fix, explicitly specify NullPool (e.g., poolclass=NullPool) or adjust your pool usage accordingly.
Migration Steps
- If your application relies on the aiosqlite dialect using NullPool, explicitly set poolclass=NullPool when creating the engine.
- Review any custom pool configurations for aiosqlite to ensure they are compatible with AsyncAdaptedQueuePool.
- No other migration steps are required for this release.
✨ New Features
- Added an asyncio.shield() call within the asyncpg driver’s connection termination process to ensure termination completes under anyio.
🐛 Bug Fixes
- Fixed event‑related issue where invoking Engine.execution_options() multiple times with event‑registering parameters (e.g., isolation_level) caused internal errors during event registration.
- Reorganized the internals that generate the .c collection on a FromClause to make it safe for concurrent access, fixing issues in the Oracle dialect and other use cases.
- Fixed SQL composition bug where a None value inside an in_() expression bypassed the expanded bind‑parameter logic, breaking caching.
- Adjusted the asyncpg connection wrapper so that connection.transaction() sends None for isolation_level when not set, allowing asyncpg to use the server‑level default instead of a hard‑coded read_committed.
- Fixed a bug in the MySQL statement compiler where _mysql.Insert.on_duplicate_key_update() could not compile when passed ORM‑mapped attributes (InstrumentedAttribute objects) as keys.
- Changed the default connection pool used by the aiosqlite dialect from NullPool to AsyncAdaptedQueuePool, aligning it with the pysqlite dialect change.
🔧 Affected Symbols
sqlalchemy.engine.Engine.execution_optionssqlalchemy.sql.FromClause.csqlalchemy.sql.expression.in_sqlalchemy.dialects.postgresql.asyncpg.AsyncPGConnection.transactionsqlalchemy.dialects.mysql._mysql.Insert.on_duplicate_key_updatesqlalchemy.dialects.sqlite.aiosqlite.AsyncAdaptedQueuePool