apache-airflow-providers-postgres 7.0.2__tar.gz → 7.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/PKG-INFO +6 -6
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/README.rst +3 -3
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/changelog.rst +19 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/connections/postgres.rst +9 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/dialects.rst +1 -1
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/index.rst +3 -3
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/provider.yaml +2 -2
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/pyproject.toml +3 -3
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/__init__.py +1 -1
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/hooks/postgres.py +28 -2
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/hooks/test_postgres.py +87 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/.gitignore +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/LICENSE +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/NOTICE +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/.latest-doc-only-change.txt +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/commits.rst +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/conf.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/configurations-ref.rst +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/installing-providers-from-sources.rst +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/integration-logos/Postgres.png +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/operators.rst +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/redirects.txt +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/security.rst +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/assets/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/assets/postgres.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/dialects/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/dialects/postgres.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/get_provider_info.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/src/airflow/providers/postgres/hooks/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/conftest.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/system/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/system/postgres/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/system/postgres/example_postgres.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/assets/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/assets/test_postgres.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/dialects/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/dialects/test_postgres.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/hooks/__init__.py +0 -0
- {apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/tests/unit/postgres/test_provider_dependencies.py +0 -0
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: apache-airflow-providers-postgres
|
|
3
|
-
Version: 7.0
|
|
3
|
+
Version: 7.1.0
|
|
4
4
|
Summary: Provider package apache-airflow-providers-postgres for Apache Airflow
|
|
5
5
|
Keywords: airflow-provider,postgres,airflow,integration
|
|
6
6
|
Author-email: Apache Software Foundation <dev@airflow.apache.org>
|
|
@@ -43,8 +43,8 @@ Requires-Dist: psycopg2-binary>=2.9.9 ; extra == "psycopg2" and ( python_version
|
|
|
43
43
|
Requires-Dist: psycopg2-binary>=2.9.10 ; extra == "psycopg2" and ( python_version >= '3.13')
|
|
44
44
|
Requires-Dist: sqlalchemy>=1.4.54 ; extra == "sqlalchemy"
|
|
45
45
|
Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
|
|
46
|
-
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
47
|
-
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
46
|
+
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/changelog.html
|
|
47
|
+
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0
|
|
48
48
|
Project-URL: Mastodon, https://fosstodon.org/@airflow
|
|
49
49
|
Project-URL: Slack Chat, https://s.apache.org/airflow-slack
|
|
50
50
|
Project-URL: Source Code, https://github.com/apache/airflow
|
|
@@ -86,7 +86,7 @@ Import-Namespace: airflow.providers
|
|
|
86
86
|
|
|
87
87
|
Package ``apache-airflow-providers-postgres``
|
|
88
88
|
|
|
89
|
-
Release: ``7.0
|
|
89
|
+
Release: ``7.1.0``
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
`PostgreSQL <https://www.postgresql.org/>`__
|
|
@@ -99,7 +99,7 @@ This is a provider package for ``postgres`` provider. All classes for this provi
|
|
|
99
99
|
are in ``airflow.providers.postgres`` python package.
|
|
100
100
|
|
|
101
101
|
You can find package information and changelog for the provider
|
|
102
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
102
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/>`_.
|
|
103
103
|
|
|
104
104
|
Installation
|
|
105
105
|
------------
|
|
@@ -164,5 +164,5 @@ Extra Dependencies
|
|
|
164
164
|
=================== ============================================================================================================================================================
|
|
165
165
|
|
|
166
166
|
The changelog for the provider package can be found in the
|
|
167
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
167
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/changelog.html>`_.
|
|
168
168
|
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/README.rst
RENAMED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
Package ``apache-airflow-providers-postgres``
|
|
25
25
|
|
|
26
|
-
Release: ``7.0
|
|
26
|
+
Release: ``7.1.0``
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
`PostgreSQL <https://www.postgresql.org/>`__
|
|
@@ -36,7 +36,7 @@ This is a provider package for ``postgres`` provider. All classes for this provi
|
|
|
36
36
|
are in ``airflow.providers.postgres`` python package.
|
|
37
37
|
|
|
38
38
|
You can find package information and changelog for the provider
|
|
39
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
39
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/>`_.
|
|
40
40
|
|
|
41
41
|
Installation
|
|
42
42
|
------------
|
|
@@ -101,4 +101,4 @@ Extra Dependencies
|
|
|
101
101
|
=================== ============================================================================================================================================================
|
|
102
102
|
|
|
103
103
|
The changelog for the provider package can be found in the
|
|
104
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
104
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/changelog.html>`_.
|
|
@@ -27,6 +27,25 @@
|
|
|
27
27
|
Changelog
|
|
28
28
|
---------
|
|
29
29
|
|
|
30
|
+
7.1.0
|
|
31
|
+
.....
|
|
32
|
+
|
|
33
|
+
Features
|
|
34
|
+
~~~~~~~~
|
|
35
|
+
|
|
36
|
+
* ``Allow keeping PostgresHook SQLAlchemy engines on psycopg2 (#72000)``
|
|
37
|
+
|
|
38
|
+
Doc-only
|
|
39
|
+
~~~~~~~~
|
|
40
|
+
|
|
41
|
+
* ``Fix grammar in the dialects documentation (#73145)``
|
|
42
|
+
|
|
43
|
+
.. Below changes are excluded from the changelog. Move them to
|
|
44
|
+
appropriate section above if needed. Do not delete the lines(!):
|
|
45
|
+
* ``Revert "[main] Upgrade important CI environment (#73308)" (#73621)``
|
|
46
|
+
* ``[main] Upgrade important CI environment (#73308)``
|
|
47
|
+
* ``Prepare providers release 2026-09-22``
|
|
48
|
+
|
|
30
49
|
7.0.2
|
|
31
50
|
.....
|
|
32
51
|
|
|
@@ -108,6 +108,15 @@ Extra (optional)
|
|
|
108
108
|
If not specified than hostname from **Connection Host** is used.
|
|
109
109
|
* ``azure_conn_id`` - Azure Connection ID to be used for authentication via Azure Entra ID. Azure Oauth token
|
|
110
110
|
is retrieved from the azure connection which is used as password for PostgreSQL connection. Scope for the Azure OAuth token can be set in the config option ``azure_oauth_scope`` under the section ``[postgres]``. Requires `apache-airflow-providers-microsoft-azure>=12.8.0`.
|
|
111
|
+
* ``sqlalchemy_scheme`` - The SQLAlchemy ``drivername`` used for the URLs the hook builds
|
|
112
|
+
(``get_uri``, ``get_sqlalchemy_engine``). Must be ``postgresql`` or ``postgresql+<driver>``.
|
|
113
|
+
Since provider 7.0.0 the hook selects psycopg (v3) whenever SQLAlchemy 2.x is installed;
|
|
114
|
+
set this to ``postgresql+psycopg2`` to keep SQLAlchemy engines created from this connection
|
|
115
|
+
on psycopg2. This matters if your Dags rely on psycopg2-specific behaviour — for example,
|
|
116
|
+
psycopg2 sends string parameters without a type so PostgreSQL implicitly coerces them, while
|
|
117
|
+
the psycopg (v3) SQLAlchemy dialect renders typed casts, so inserting string values into
|
|
118
|
+
e.g. ``uuid`` columns (as ``pandas.DataFrame.to_sql`` does) fails with
|
|
119
|
+
*"column is of type uuid but expression is of type character varying"*.
|
|
111
120
|
|
|
112
121
|
Example "extras" field (Amazon RDS PostgreSQL or Amazon Aurora PostgreSQL):
|
|
113
122
|
|
|
@@ -25,7 +25,7 @@ and the :class:`~airflow.providers.jdbc.hooks.jdbc.JdbcHook` are generic hooks w
|
|
|
25
25
|
database that has a driver for it, it needed an abstraction layer which allows us to run specialized queries
|
|
26
26
|
depending of the database to which we connect and that's why dialects where introduced.
|
|
27
27
|
|
|
28
|
-
The default :class:`~airflow.providers.common.sql.dialects.dialect.Dialect` class has following operations
|
|
28
|
+
The default :class:`~airflow.providers.common.sql.dialects.dialect.Dialect` class has the following operations
|
|
29
29
|
available which underneath use SQLAlchemy to execute, but can be overloaded with specialized implementations
|
|
30
30
|
per database:
|
|
31
31
|
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/index.rst
RENAMED
|
@@ -78,7 +78,7 @@ apache-airflow-providers-postgres package
|
|
|
78
78
|
`PostgreSQL <https://www.postgresql.org/>`__
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
Release: 7.0
|
|
81
|
+
Release: 7.1.0
|
|
82
82
|
|
|
83
83
|
Provider package
|
|
84
84
|
----------------
|
|
@@ -162,5 +162,5 @@ Downloading official packages
|
|
|
162
162
|
You can download officially released packages and verify their checksums and signatures from the
|
|
163
163
|
`Official Apache Download site <https://downloads.apache.org/airflow/providers/>`_
|
|
164
164
|
|
|
165
|
-
* `The apache-airflow-providers-postgres 7.0
|
|
166
|
-
* `The apache-airflow-providers-postgres 7.0
|
|
165
|
+
* `The apache-airflow-providers-postgres 7.1.0 sdist package <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0.tar.gz>`_ (`asc <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0.tar.gz.asc>`__, `sha512 <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0.tar.gz.sha512>`__)
|
|
166
|
+
* `The apache-airflow-providers-postgres 7.1.0 wheel package <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0-py3-none-any.whl>`_ (`asc <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0-py3-none-any.whl.asc>`__, `sha512 <https://downloads.apache.org/airflow/providers/apache_airflow_providers_postgres-7.1.0-py3-none-any.whl.sha512>`__)
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/provider.yaml
RENAMED
|
@@ -23,13 +23,13 @@ description: |
|
|
|
23
23
|
|
|
24
24
|
state: ready
|
|
25
25
|
lifecycle: production
|
|
26
|
-
source-date-epoch:
|
|
26
|
+
source-date-epoch: 1790023613
|
|
27
27
|
# Note that those versions are maintained by release manager - do not update them manually
|
|
28
28
|
# with the exception of case where other provider in sources has >= new provider version.
|
|
29
29
|
# In such case adding >= NEW_VERSION and bumping to NEW_VERSION in a provider have
|
|
30
30
|
# to be done in the same PR
|
|
31
31
|
versions:
|
|
32
|
-
- 7.0
|
|
32
|
+
- 7.1.0
|
|
33
33
|
- 7.0.1
|
|
34
34
|
- 7.0.0
|
|
35
35
|
- 6.8.0
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/pyproject.toml
RENAMED
|
@@ -25,7 +25,7 @@ build-backend = "flit_core.buildapi"
|
|
|
25
25
|
|
|
26
26
|
[project]
|
|
27
27
|
name = "apache-airflow-providers-postgres"
|
|
28
|
-
version = "7.0
|
|
28
|
+
version = "7.1.0"
|
|
29
29
|
description = "Provider package apache-airflow-providers-postgres for Apache Airflow"
|
|
30
30
|
readme = "README.rst"
|
|
31
31
|
license = "Apache-2.0"
|
|
@@ -151,8 +151,8 @@ apache-airflow-providers-common-sql = {workspace = true}
|
|
|
151
151
|
apache-airflow-providers-standard = {workspace = true}
|
|
152
152
|
|
|
153
153
|
[project.urls]
|
|
154
|
-
"Documentation" = "https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
155
|
-
"Changelog" = "https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.0
|
|
154
|
+
"Documentation" = "https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0"
|
|
155
|
+
"Changelog" = "https://airflow.apache.org/docs/apache-airflow-providers-postgres/7.1.0/changelog.html"
|
|
156
156
|
"Bug Tracker" = "https://github.com/apache/airflow/issues"
|
|
157
157
|
"Source Code" = "https://github.com/apache/airflow"
|
|
158
158
|
"Slack Chat" = "https://s.apache.org/airflow-slack"
|
|
@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
|
|
|
29
29
|
|
|
30
30
|
__all__ = ["__version__"]
|
|
31
31
|
|
|
32
|
-
__version__ = "7.0
|
|
32
|
+
__version__ = "7.1.0"
|
|
33
33
|
|
|
34
34
|
if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
|
|
35
35
|
"2.11.0"
|
|
@@ -135,6 +135,11 @@ class PostgresHook(DbApiHook):
|
|
|
135
135
|
:param options: Optional. Specifies command-line options to send to the server
|
|
136
136
|
at connection start. For example, setting this to ``-c search_path=myschema``
|
|
137
137
|
sets the session's value of the ``search_path`` to ``myschema``.
|
|
138
|
+
:param sqlalchemy_scheme: Optional. The SQLAlchemy ``drivername`` used for the URLs the hook
|
|
139
|
+
builds (``get_uri``, ``get_sqlalchemy_engine``), e.g. ``postgresql+psycopg2``. Must be
|
|
140
|
+
``postgresql`` or ``postgresql+<driver>``. Defaults to ``postgresql+psycopg`` when
|
|
141
|
+
psycopg (v3) serves SQLAlchemy 2.x and to ``postgresql`` otherwise. Can also be set via
|
|
142
|
+
the connection extra ``sqlalchemy_scheme``; this parameter takes precedence.
|
|
138
143
|
:param enable_log_db_messages: Optional. If enabled logs database messages sent to the client
|
|
139
144
|
during the session. To avoid a memory leak psycopg2 only saves the last 50 messages.
|
|
140
145
|
For details, see: `PostgreSQL logging configuration parameters
|
|
@@ -164,18 +169,39 @@ class PostgresHook(DbApiHook):
|
|
|
164
169
|
default_azure_oauth_scope = "https://ossrdbms-aad.database.windows.net/.default"
|
|
165
170
|
|
|
166
171
|
def __init__(
|
|
167
|
-
self,
|
|
172
|
+
self,
|
|
173
|
+
*args,
|
|
174
|
+
options: str | None = None,
|
|
175
|
+
enable_log_db_messages: bool = False,
|
|
176
|
+
sqlalchemy_scheme: str | None = None,
|
|
177
|
+
**kwargs,
|
|
168
178
|
) -> None:
|
|
169
179
|
super().__init__(*args, **kwargs)
|
|
170
180
|
self.conn: CompatConnection | None = None
|
|
171
181
|
self.database: str | None = kwargs.pop("database", None)
|
|
172
182
|
self.options = options
|
|
173
183
|
self.enable_log_db_messages = enable_log_db_messages
|
|
184
|
+
self._sqlalchemy_scheme = sqlalchemy_scheme
|
|
174
185
|
|
|
175
186
|
@staticmethod
|
|
176
187
|
def __cast_nullable(value, dst_type: type) -> Any:
|
|
177
188
|
return dst_type(value) if value is not None else None
|
|
178
189
|
|
|
190
|
+
@property
|
|
191
|
+
def sqlalchemy_scheme(self) -> str:
|
|
192
|
+
"""SQLAlchemy ``drivername`` used for the URLs built by this hook."""
|
|
193
|
+
scheme = self._sqlalchemy_scheme or self.connection.extra_dejson.get("sqlalchemy_scheme")
|
|
194
|
+
if not scheme:
|
|
195
|
+
return "postgresql+psycopg" if USE_PSYCOPG3 else "postgresql"
|
|
196
|
+
if ":" in scheme or "/" in scheme:
|
|
197
|
+
raise ValueError("The parameter 'sqlalchemy_scheme' must not contain ':' or '/' characters!")
|
|
198
|
+
if scheme != "postgresql" and not scheme.startswith("postgresql+"):
|
|
199
|
+
raise ValueError(
|
|
200
|
+
f"The parameter 'sqlalchemy_scheme' must be 'postgresql' or 'postgresql+<driver>', "
|
|
201
|
+
f"got: {scheme!r}"
|
|
202
|
+
)
|
|
203
|
+
return scheme
|
|
204
|
+
|
|
179
205
|
@property
|
|
180
206
|
def sqlalchemy_url(self) -> URL:
|
|
181
207
|
try:
|
|
@@ -192,7 +218,7 @@ class PostgresHook(DbApiHook):
|
|
|
192
218
|
if conn.extra_dejson.get("iam", False):
|
|
193
219
|
conn.login, conn.password, conn.port = self.get_iam_token(conn)
|
|
194
220
|
return URL.create(
|
|
195
|
-
drivername=
|
|
221
|
+
drivername=self.sqlalchemy_scheme,
|
|
196
222
|
username=self.__cast_nullable(conn.login, str),
|
|
197
223
|
password=self.__cast_nullable(conn.password, str),
|
|
198
224
|
host=self.__cast_nullable(conn.host, str),
|
|
@@ -633,6 +633,93 @@ class TestPostgresHookConnPPG3:
|
|
|
633
633
|
)
|
|
634
634
|
|
|
635
635
|
|
|
636
|
+
class TestPostgresHookSqlalchemyScheme:
|
|
637
|
+
"""Tests for overriding the SQLAlchemy ``drivername`` via the sqlalchemy_scheme extra/parameter."""
|
|
638
|
+
|
|
639
|
+
@staticmethod
|
|
640
|
+
def get_hook(extra: dict | None = None, **hook_kwargs) -> PostgresHook:
|
|
641
|
+
conn = Connection(
|
|
642
|
+
login="login-conn", password="password-conn", host="host", schema="database", extra=extra
|
|
643
|
+
)
|
|
644
|
+
return PostgresHook(connection=conn, **hook_kwargs)
|
|
645
|
+
|
|
646
|
+
@pytest.mark.parametrize("scheme", ["postgresql", "postgresql+psycopg2", "postgresql+psycopg"])
|
|
647
|
+
def test_sqlalchemy_scheme_from_extra(self, scheme):
|
|
648
|
+
hook = self.get_hook(extra=dict(sqlalchemy_scheme=scheme))
|
|
649
|
+
expected = f"{scheme}://login-conn:password-conn@host/database"
|
|
650
|
+
assert hook.sqlalchemy_url.render_as_string(hide_password=False) == expected
|
|
651
|
+
|
|
652
|
+
def test_sqlalchemy_scheme_parameter_takes_precedence_over_extra(self):
|
|
653
|
+
hook = self.get_hook(
|
|
654
|
+
extra=dict(sqlalchemy_scheme="postgresql"), sqlalchemy_scheme="postgresql+psycopg2"
|
|
655
|
+
)
|
|
656
|
+
expected = "postgresql+psycopg2://login-conn:password-conn@host/database"
|
|
657
|
+
assert hook.sqlalchemy_url.render_as_string(hide_password=False) == expected
|
|
658
|
+
|
|
659
|
+
def test_get_uri_with_sqlalchemy_scheme(self):
|
|
660
|
+
hook = self.get_hook(extra=dict(sqlalchemy_scheme="postgresql+psycopg2"))
|
|
661
|
+
assert hook.get_uri() == "postgresql+psycopg2://login-conn:password-conn@host/database"
|
|
662
|
+
|
|
663
|
+
@pytest.mark.parametrize("scheme", ["mysql", "mysql+pymysql", "postgres+psycopg2"])
|
|
664
|
+
def test_sqlalchemy_scheme_with_wrong_dialect(self, scheme):
|
|
665
|
+
hook = self.get_hook(extra=dict(sqlalchemy_scheme=scheme))
|
|
666
|
+
with pytest.raises(
|
|
667
|
+
ValueError, match="'sqlalchemy_scheme' must be 'postgresql' or 'postgresql\\+<driver>'"
|
|
668
|
+
):
|
|
669
|
+
hook.sqlalchemy_url
|
|
670
|
+
|
|
671
|
+
@pytest.mark.parametrize("scheme", ["postgresql+psycopg2://malicious", "postgresql+psycopg2/malicious"])
|
|
672
|
+
def test_sqlalchemy_scheme_with_forbidden_characters(self, scheme):
|
|
673
|
+
hook = self.get_hook(extra=dict(sqlalchemy_scheme=scheme))
|
|
674
|
+
with pytest.raises(ValueError, match="must not contain ':' or '/' characters"):
|
|
675
|
+
hook.sqlalchemy_url
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
@pytest.mark.backend("postgres")
|
|
679
|
+
class TestPostgresHookPandasToSqlUuid:
|
|
680
|
+
"""DataFrame.to_sql with string values into a uuid column: fails on psycopg3 because SQLAlchemy
|
|
681
|
+
renders typed bind casts, works when the connection opts back into psycopg2 via sqlalchemy_scheme."""
|
|
682
|
+
|
|
683
|
+
table = "test_pandas_to_sql_uuid_table"
|
|
684
|
+
|
|
685
|
+
PSYCOPG3_XFAIL_REASON = (
|
|
686
|
+
"The psycopg3 SQLAlchemy dialect renders typed bind casts, so string params fail with "
|
|
687
|
+
"'column is of type uuid but expression is of type character varying' instead of being "
|
|
688
|
+
"implicitly coerced as under psycopg2. Tracked upstream in "
|
|
689
|
+
"https://github.com/pandas-dev/pandas/issues/63511, "
|
|
690
|
+
"https://github.com/apache/arrow/pull/50325, "
|
|
691
|
+
"https://github.com/sqlalchemy/sqlalchemy/discussions/10839 and "
|
|
692
|
+
"https://github.com/sqlalchemy/sqlalchemy/issues/12060"
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
def teardown_method(self):
|
|
696
|
+
with PostgresHook().get_conn() as conn:
|
|
697
|
+
with conn.cursor() as cur:
|
|
698
|
+
cur.execute(f"DROP TABLE IF EXISTS {self.table}")
|
|
699
|
+
|
|
700
|
+
def insert_string_uuid_df(self, hook: PostgresHook) -> None:
|
|
701
|
+
engine = hook.get_sqlalchemy_engine()
|
|
702
|
+
with engine.begin() as conn:
|
|
703
|
+
conn.execute(sqlalchemy.text(f"CREATE TABLE {self.table} (id UUID PRIMARY KEY, item TEXT)"))
|
|
704
|
+
df = pd.DataFrame({"id": ["b29d6cda-04ca-4073-8ef8-4f70d35e41e2"], "item": ["laptop"]})
|
|
705
|
+
df.to_sql(self.table, engine, if_exists="append", index=False)
|
|
706
|
+
|
|
707
|
+
@pytest.mark.skipif(not USE_PSYCOPG3, reason="psycopg v3 or sqlalchemy v2 not available")
|
|
708
|
+
@pytest.mark.xfail(
|
|
709
|
+
raises=(sqlalchemy.exc.ProgrammingError, pd.errors.DatabaseError),
|
|
710
|
+
strict=True,
|
|
711
|
+
reason=PSYCOPG3_XFAIL_REASON,
|
|
712
|
+
)
|
|
713
|
+
def test_to_sql_string_uuid_fails_on_psycopg3(self):
|
|
714
|
+
self.insert_string_uuid_df(PostgresHook())
|
|
715
|
+
|
|
716
|
+
def test_to_sql_string_uuid_works_with_psycopg2_scheme(self):
|
|
717
|
+
hook = PostgresHook(sqlalchemy_scheme="postgresql+psycopg2")
|
|
718
|
+
self.insert_string_uuid_df(hook)
|
|
719
|
+
with hook.get_sqlalchemy_engine().connect() as conn:
|
|
720
|
+
assert conn.execute(sqlalchemy.text(f"SELECT COUNT(*) FROM {self.table}")).scalar() == 1
|
|
721
|
+
|
|
722
|
+
|
|
636
723
|
@pytest.mark.backend("postgres")
|
|
637
724
|
class TestPostgresHook:
|
|
638
725
|
"""Tests that are identical between psycopg2 and psycopg3."""
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/.gitignore
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/commits.rst
RENAMED
|
File without changes
|
{apache_airflow_providers_postgres-7.0.2 → apache_airflow_providers_postgres-7.1.0}/docs/conf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|