Providers: Make psycopg (v3) the default synchronous Postgres driver#69526
Open
Dev-iL wants to merge 7 commits into
Open
Providers: Make psycopg (v3) the default synchronous Postgres driver#69526Dev-iL wants to merge 7 commits into
Dev-iL wants to merge 7 commits into
Conversation
Dev-iL
requested review from
dheerajturaga,
hussein-awala,
o-nikolas and
shahar1
as code owners
July 7, 2026 06:32
1 task
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
2 times, most recently
from
July 7, 2026 19:01
c8ebd84 to
99b185f
Compare
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
from
July 8, 2026 06:53
99b185f to
8cb5cff
Compare
shahar1
reviewed
Jul 9, 2026
shahar1
previously requested changes
Jul 10, 2026
shahar1
left a comment
Contributor
There was a problem hiding this comment.
Blocking to avoid accidental merges until we figure out this one:
#69526 (comment)
1 task
Contributor
|
Quickest fix: git fetch upstream main && git rebase upstream/main
rm uv.lock && uv lock
git add uv.lock && git rebase --continue
git push --force-with-leaseAutomated nudge — ignore if you're not ready to rebase. This comment is updated in place on future |
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
from
July 11, 2026 14:47
8cb5cff to
6a6eaf8
Compare
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
2 times, most recently
from
July 16, 2026 11:11
5b116e0 to
5fa442d
Compare
eladkal
reviewed
Jul 16, 2026
shahar1
approved these changes
Jul 16, 2026
shahar1
reviewed
Jul 16, 2026
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
from
July 17, 2026 08:21
5fa442d to
ad60554
Compare
PostgresHook no longer requires psycopg2 at import time: the psycopg2-specific connection, cursor, and execute_values imports are now lazy/guarded and raise a clear AirflowOptionalProviderFeatureException if psycopg2 genuinely needs to be used but isn't installed. A new [psycopg2] extra is added for the eventual opt-in. psycopg2-binary nonetheless stays a default dependency for now: this provider still supports Airflow cores older than 3.4.0, which normalize the synchronous metadata-database connection to postgresql+psycopg2:// and have no psycopg fallback, and Airflow 2.11 ships SQLAlchemy 1.4, which has no native psycopg (v3) dialect at all. Dropping psycopg2 as a default would break those cores. It becomes opt-in-only once the minimum supported Airflow is >= 3.4.0, together with asyncpg. Part of the migration tracked in apache#68453.
The hardcoded fallback that derives [celery] result_backend from sql_alchemy_conn when a driverless postgresql:// URL is configured targeted postgresql+psycopg2:// explicitly. Update it to target postgresql+psycopg:// to match the sync Postgres driver default change in apache-airflow and apache-airflow-providers-postgres — but only when psycopg (v3) is actually importable, since providers/celery's own dependency floor doesn't guarantee SQLAlchemy 2.0+/psycopg, falling back to postgresql+psycopg2:// otherwise (the same guard PostgresHook itself uses). Part of the migration tracked in apache#68453.
register_adapter(list/dict, Json) is psycopg2-specific and previously ran unconditionally, forcing psycopg2 to be importable even when the resolved PostgresHook connection is on psycopg3 (a no-op there). Only import and call it when PostgresHook is actually on the psycopg2 path, so the module imports cleanly without psycopg2 installed. Part of the migration tracked in apache#68453.
from pgvector.psycopg2 import register_vector ran unconditionally at module level, forcing psycopg2 to be importable regardless of which driver the underlying PostgresHook connection actually uses, and was always called even when the connection is on psycopg3 — where it's the wrong helper entirely (psycopg3 has its own pgvector.psycopg registration API). Make the import lazy, call the helper matching PostgresHook.USE_PSYCOPG3, and raise a clear AirflowOptionalProviderFeatureException if the needed driver's pgvector integration is missing. Fixes apache#69443. Part of the migration tracked in apache#68453.
RedshiftSQLHook.get_sqlalchemy_engine() built its SQLAlchemy engine from a bare postgresql:// URI, relying on SQLAlchemy's implicit default of the psycopg2 DB-API. Now that apache-airflow-providers-postgres no longer bundles psycopg2-binary by default, that import fails wherever psycopg2 genuinely isn't installed. Resolve an explicit driver instead: prefer psycopg (v3), fall back to psycopg2, and raise a clear error only if neither is installed. Also updates the Batch, ECS, and Lambda executor setup guides' example postgresql+psycopg2:// connection strings to postgresql+psycopg://, since those stale examples would otherwise break for anyone following them as-is under the new default. Part of the migration tracked in apache#68453.
SQLAlchemy resolves a bare postgresql:// scheme to the psycopg2 DB-API by default, regardless of what Airflow's own config does. Any DbApiHook subclass whose connection type maps to a bare postgresql:// URI (rather than delegating to PostgresHook's own driver-aware sqlalchemy_url) broke once apache-airflow-providers-postgres stopped hard-requiring psycopg2. get_sqlalchemy_engine() now retries with an explicit driver — psycopg (v3) preferred, psycopg2 as fallback — only for that specific bare-scheme failure; any other scheme's error still propagates unchanged. Part of the migration tracked in apache#68453.
The bare postgresql:// retry silently substituted psycopg or psycopg2 for the driver SQLAlchemy couldn't resolve, giving users no signal that anything had changed on their behalf. RedshiftSQLHook's matching eager driver resolution had the same silent-substitution gap, but at the changelog level: a Redshift user with both drivers installed moves from psycopg2 to psycopg (v3) with no note explaining why.
Dev-iL
force-pushed
the
2607/ppg3_providers
branch
from
July 17, 2026 12:16
ad60554 to
ab776e5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes:
related:
Makes
psycopg(v3) the default synchronous Postgres driver across the providers, mirroring the async default switch (#69089). psycopg3 is used wherever it actually works (SQLAlchemy 2.0+);psycopg2-binarystays installed by default as a fallback so nothing regresses on the Airflow versions this provider still supports.Why psycopg2 stays a default dependency (not demoted to an extra)
An earlier revision of this PR moved
psycopg2-binaryto an opt-in[psycopg2]extra. That regresses every core older than 3.4.0, so it now stays a default dependency — gated to become opt-in only once the minimum supported Airflow is 3.4.0. The reasons mirror #69690 (which keptasyncpginstalled by default for the same class of reason on the async side):postgresql+psycopg2://. On every currently released core,configuration.py::_upgrade_postgres_metastore_connrewrites a barepostgresql:/// legacypostgres:///postgres+psycopg2://sql_alchemy_connto explicitpostgresql+psycopg2://, andsettings.pybuilds the metadata engine from that string with no psycopg fallback. Dropping psycopg2 breaks the metadata DB.postgresql+psycopg(v3) dialect at all. Since this provider still supportsapache-airflow>=2.11.0, psycopg2 is the only viable sync driver there.So
psycopg[binary],psycopg2-binary, andasyncpgare all default dependencies. The removal of the psycopg2/asyncpg defaults is deferred, gated on the floor bump to 3.4.0, and noted at the workaround site (tracked at #68453).Relationship to #69469 (the core half)
The sync switch for Airflow's own metadata DB lives in core #69469: it flips
_upgrade_postgres_metastore_connto derivepostgresql+psycopg://when psycopg (v3) is importable (gated to land in 3.4.0), mirroring the async_USE_PSYCOPG3guard.Because this PR keeps both sync drivers installed by default, it is robust to #69469's presence and to merge order: whether core normalizes the conn to
+psycopg2://(pre-#69469) or+psycopg://(post-#69469), the driver behind that scheme is always present. The two PRs can merge in either order and release independently without a broken window. The eventual removal of the psycopg2 default is what's coupled to #69469 shipping in every supported core — deferred to the 3.4.0 floor bump.What changed (6 commits, one per package)
providers/postgres—PostgresHookno longer requires psycopg2 at import time: the psycopg2-specific connection / cursor /execute_valuesimports are lazy/guarded and raise a clearAirflowOptionalProviderFeatureExceptionif psycopg2 is genuinely needed but missing. A new[psycopg2]extra is added for the eventual opt-in.psycopg2-binaryremains a default dependency for the backward-compat reasons above; a regression test asserts bothpsycopg2-binaryandasyncpgstay default (non-extra) dependencies.providers/celery— the[celery] result_backendderivation from a driverlesssql_alchemy_connnow targetspostgresql+psycopg://(matching the new sync default) when psycopg (v3) is importable, falling back topostgresql+psycopg2://otherwise — mirroring the same guardPostgresHookuses.providers/google—BigQueryToPostgresOperator's psycopg2-specificregister_adapter(list/dict, Json)now only runs when the resolvedPostgresHookconnection is actually on psycopg2 (a no-op on psycopg3), so the module imports cleanly without psycopg2 installed.providers/pgvector—PgVectorIngestOperator._register_vectornow calls the registration helper matching the connection's actual driver (pgvector.psycopg2.register_vectorvs.pgvector.psycopg.register_vector) instead of always assuming psycopg2, fixing a pre-existing bug. Its "psycopg (v3) integration missing" error now points atpip install --upgrade pgvector.providers/amazon—RedshiftSQLHook.get_sqlalchemy_engine()resolves an explicit driver (prefers psycopg on SQLAlchemy 2.0+, falls back to psycopg2, clear error if neither) instead of relying on SQLAlchemy's implicit psycopg2 default for a barepostgresql://URI.get_uri()'s own bare-scheme contract is untouched. Also updates the Batch/ECS/Lambda executor docs' example connection strings topostgresql+psycopg://.providers/common/sql—DbApiHook.get_sqlalchemy_engine()retries with an explicit driver only for the specific "barepostgresqlscheme, driver import failed" case; any other scheme's failure still propagates unchanged, keeping the class DB-agnostic. The retry prefers psycopg only on SQLAlchemy 2.0+ (which has the nativepostgresql+psycopgdialect) and falls back to psycopg2 otherwise, so it stays correct on Airflow 2.11's SQLAlchemy 1.4. This is the generalsafety net: any current or future
DbApiHooksubclass with a postgres-compatibleconn_typethat doesn't overridesqlalchemy_urlis covered by this fix, not just the two concrete cases (amazon, google) found so far.Test plan
USE_PSYCOPG3branches in celery/google/pgvector;PgVectorIngestOperatorregistering against both a psycopg2-backed and a psycopg3-backed connection; andget_sqlalchemy_engine's driver-resolution / retry / re-raise / no-retry-for-other-schemes behavior in both amazon and common.sql — including the new SQLAlchemy-1.4 case that must fall back to psycopg2 rather than psycopg (v3).psycopg2-binaryandasyncpgremain default (non-extra) dependencies ofapache-airflow-providers-postgres, so a future change can't silently demote either driver back to an extra and reintroduce the<3.4.0regression.Was generative AI tooling used to co-author this PR?
{pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.