apache-airflow-providers-http 5.0.0rc1__tar.gz → 5.2.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_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0}/PKG-INFO +11 -28
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0}/README.rst +4 -22
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0}/pyproject.toml +17 -10
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/LICENSE +0 -52
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/__init__.py +1 -1
- apache_airflow_providers_http-5.2.0/src/airflow/providers/http/exceptions.py +27 -0
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/get_provider_info.py +11 -11
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/hooks/http.py +114 -103
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/operators/http.py +6 -1
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/sensors/http.py +5 -1
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/triggers/http.py +18 -13
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/hooks/__init__.py +0 -0
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/operators/__init__.py +0 -0
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/sensors/__init__.py +0 -0
- {apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0/src}/airflow/providers/http/triggers/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: apache-airflow-providers-http
|
3
|
-
Version: 5.0
|
3
|
+
Version: 5.2.0
|
4
4
|
Summary: Provider package apache-airflow-providers-http for Apache Airflow
|
5
5
|
Keywords: airflow-provider,http,airflow,integration
|
6
6
|
Author-email: Apache Software Foundation <dev@airflow.apache.org>
|
@@ -20,37 +20,20 @@ Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
22
22
|
Classifier: Topic :: System :: Monitoring
|
23
|
+
Requires-Dist: apache-airflow>=2.9.0
|
24
|
+
Requires-Dist: requests>=2.27.0,<3
|
25
|
+
Requires-Dist: requests-toolbelt>=0.4.0
|
23
26
|
Requires-Dist: aiohttp>=3.9.2,!=3.11.0
|
24
|
-
Requires-Dist: apache-airflow>=2.9.0rc0
|
25
27
|
Requires-Dist: asgiref>=2.3.0
|
26
|
-
Requires-Dist: requests-toolbelt>=0.4.0
|
27
|
-
Requires-Dist: requests>=2.27.0,<3
|
28
28
|
Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
|
29
|
-
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
30
|
-
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
29
|
+
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/changelog.html
|
30
|
+
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0
|
31
31
|
Project-URL: Slack Chat, https://s.apache.org/airflow-slack
|
32
32
|
Project-URL: Source Code, https://github.com/apache/airflow
|
33
33
|
Project-URL: Twitter, https://x.com/ApacheAirflow
|
34
34
|
Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
|
35
35
|
|
36
36
|
|
37
|
-
.. Licensed to the Apache Software Foundation (ASF) under one
|
38
|
-
or more contributor license agreements. See the NOTICE file
|
39
|
-
distributed with this work for additional information
|
40
|
-
regarding copyright ownership. The ASF licenses this file
|
41
|
-
to you under the Apache License, Version 2.0 (the
|
42
|
-
"License"); you may not use this file except in compliance
|
43
|
-
with the License. You may obtain a copy of the License at
|
44
|
-
|
45
|
-
.. http://www.apache.org/licenses/LICENSE-2.0
|
46
|
-
|
47
|
-
.. Unless required by applicable law or agreed to in writing,
|
48
|
-
software distributed under the License is distributed on an
|
49
|
-
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
50
|
-
KIND, either express or implied. See the License for the
|
51
|
-
specific language governing permissions and limitations
|
52
|
-
under the License.
|
53
|
-
|
54
37
|
.. Licensed to the Apache Software Foundation (ASF) under one
|
55
38
|
or more contributor license agreements. See the NOTICE file
|
56
39
|
distributed with this work for additional information
|
@@ -68,8 +51,7 @@ Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
|
|
68
51
|
specific language governing permissions and limitations
|
69
52
|
under the License.
|
70
53
|
|
71
|
-
.. NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE
|
72
|
-
OVERWRITTEN WHEN PREPARING PACKAGES.
|
54
|
+
.. NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE OVERWRITTEN!
|
73
55
|
|
74
56
|
.. IF YOU WANT TO MODIFY TEMPLATE FOR THIS FILE, YOU SHOULD MODIFY THE TEMPLATE
|
75
57
|
`PROVIDER_README_TEMPLATE.rst.jinja2` IN the `dev/breeze/src/airflow_breeze/templates` DIRECTORY
|
@@ -77,7 +59,7 @@ Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
|
|
77
59
|
|
78
60
|
Package ``apache-airflow-providers-http``
|
79
61
|
|
80
|
-
Release: ``5.
|
62
|
+
Release: ``5.2.0``
|
81
63
|
|
82
64
|
|
83
65
|
`Hypertext Transfer Protocol (HTTP) <https://www.w3.org/Protocols/>`__
|
@@ -90,7 +72,7 @@ This is a provider package for ``http`` provider. All classes for this provider
|
|
90
72
|
are in ``airflow.providers.http`` python package.
|
91
73
|
|
92
74
|
You can find package information and changelog for the provider
|
93
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
75
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/>`_.
|
94
76
|
|
95
77
|
Installation
|
96
78
|
------------
|
@@ -115,4 +97,5 @@ PIP package Version required
|
|
115
97
|
===================== ====================
|
116
98
|
|
117
99
|
The changelog for the provider package can be found in the
|
118
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
100
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/changelog.html>`_.
|
101
|
+
|
@@ -1,21 +1,4 @@
|
|
1
1
|
|
2
|
-
.. Licensed to the Apache Software Foundation (ASF) under one
|
3
|
-
or more contributor license agreements. See the NOTICE file
|
4
|
-
distributed with this work for additional information
|
5
|
-
regarding copyright ownership. The ASF licenses this file
|
6
|
-
to you under the Apache License, Version 2.0 (the
|
7
|
-
"License"); you may not use this file except in compliance
|
8
|
-
with the License. You may obtain a copy of the License at
|
9
|
-
|
10
|
-
.. http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
|
12
|
-
.. Unless required by applicable law or agreed to in writing,
|
13
|
-
software distributed under the License is distributed on an
|
14
|
-
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
-
KIND, either express or implied. See the License for the
|
16
|
-
specific language governing permissions and limitations
|
17
|
-
under the License.
|
18
|
-
|
19
2
|
.. Licensed to the Apache Software Foundation (ASF) under one
|
20
3
|
or more contributor license agreements. See the NOTICE file
|
21
4
|
distributed with this work for additional information
|
@@ -33,8 +16,7 @@
|
|
33
16
|
specific language governing permissions and limitations
|
34
17
|
under the License.
|
35
18
|
|
36
|
-
.. NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE
|
37
|
-
OVERWRITTEN WHEN PREPARING PACKAGES.
|
19
|
+
.. NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE OVERWRITTEN!
|
38
20
|
|
39
21
|
.. IF YOU WANT TO MODIFY TEMPLATE FOR THIS FILE, YOU SHOULD MODIFY THE TEMPLATE
|
40
22
|
`PROVIDER_README_TEMPLATE.rst.jinja2` IN the `dev/breeze/src/airflow_breeze/templates` DIRECTORY
|
@@ -42,7 +24,7 @@
|
|
42
24
|
|
43
25
|
Package ``apache-airflow-providers-http``
|
44
26
|
|
45
|
-
Release: ``5.
|
27
|
+
Release: ``5.2.0``
|
46
28
|
|
47
29
|
|
48
30
|
`Hypertext Transfer Protocol (HTTP) <https://www.w3.org/Protocols/>`__
|
@@ -55,7 +37,7 @@ This is a provider package for ``http`` provider. All classes for this provider
|
|
55
37
|
are in ``airflow.providers.http`` python package.
|
56
38
|
|
57
39
|
You can find package information and changelog for the provider
|
58
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
40
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/>`_.
|
59
41
|
|
60
42
|
Installation
|
61
43
|
------------
|
@@ -80,4 +62,4 @@ PIP package Version required
|
|
80
62
|
===================== ====================
|
81
63
|
|
82
64
|
The changelog for the provider package can be found in the
|
83
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
65
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/changelog.html>`_.
|
{apache_airflow_providers_http-5.0.0rc1 → apache_airflow_providers_http-5.2.0}/pyproject.toml
RENAMED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# Licensed to the Apache Software Foundation (ASF) under one
|
3
2
|
# or more contributor license agreements. See the NOTICE file
|
4
3
|
# distributed with this work for additional information
|
@@ -16,10 +15,9 @@
|
|
16
15
|
# specific language governing permissions and limitations
|
17
16
|
# under the License.
|
18
17
|
|
19
|
-
# NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE
|
20
|
-
# OVERWRITTEN WHEN PREPARING PACKAGES.
|
18
|
+
# NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE OVERWRITTEN!
|
21
19
|
|
22
|
-
# IF YOU WANT TO MODIFY THIS FILE, YOU SHOULD MODIFY THE TEMPLATE
|
20
|
+
# IF YOU WANT TO MODIFY THIS FILE EXCEPT DEPENDENCIES, YOU SHOULD MODIFY THE TEMPLATE
|
23
21
|
# `pyproject_TEMPLATE.toml.jinja2` IN the `dev/breeze/src/airflow_breeze/templates` DIRECTORY
|
24
22
|
[build-system]
|
25
23
|
requires = ["flit_core==3.10.1"]
|
@@ -27,7 +25,7 @@ build-backend = "flit_core.buildapi"
|
|
27
25
|
|
28
26
|
[project]
|
29
27
|
name = "apache-airflow-providers-http"
|
30
|
-
version = "5.
|
28
|
+
version = "5.2.0"
|
31
29
|
description = "Provider package apache-airflow-providers-http for Apache Airflow"
|
32
30
|
readme = "README.rst"
|
33
31
|
authors = [
|
@@ -53,17 +51,23 @@ classifiers = [
|
|
53
51
|
"Topic :: System :: Monitoring",
|
54
52
|
]
|
55
53
|
requires-python = "~=3.9"
|
54
|
+
|
55
|
+
# The dependencies should be modified in place in the generated file
|
56
|
+
# Any change in the dependencies is preserved when the file is regenerated
|
56
57
|
dependencies = [
|
58
|
+
"apache-airflow>=2.9.0",
|
59
|
+
# The 2.26.0 release of requests got rid of the chardet LGPL mandatory dependency, allowing us to
|
60
|
+
# release it as a requirement for airflow
|
61
|
+
"requests>=2.27.0,<3",
|
62
|
+
"requests-toolbelt>=0.4.0",
|
63
|
+
# aiohttp 3.11.0 had incompatible change: https://github.com/aio-libs/aiohttp/issues/9866
|
57
64
|
"aiohttp>=3.9.2,!=3.11.0",
|
58
|
-
"apache-airflow>=2.9.0rc0",
|
59
65
|
"asgiref>=2.3.0",
|
60
|
-
"requests-toolbelt>=0.4.0",
|
61
|
-
"requests>=2.27.0,<3",
|
62
66
|
]
|
63
67
|
|
64
68
|
[project.urls]
|
65
|
-
"Documentation" = "https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
66
|
-
"Changelog" = "https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
69
|
+
"Documentation" = "https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0"
|
70
|
+
"Changelog" = "https://airflow.apache.org/docs/apache-airflow-providers-http/5.2.0/changelog.html"
|
67
71
|
"Bug Tracker" = "https://github.com/apache/airflow/issues"
|
68
72
|
"Source Code" = "https://github.com/apache/airflow"
|
69
73
|
"Slack Chat" = "https://s.apache.org/airflow-slack"
|
@@ -75,3 +79,6 @@ provider_info = "airflow.providers.http.get_provider_info:get_provider_info"
|
|
75
79
|
|
76
80
|
[tool.flit.module]
|
77
81
|
name = "airflow.providers.http"
|
82
|
+
|
83
|
+
[tool.pytest.ini_options]
|
84
|
+
ignore = "tests/system/"
|
@@ -199,55 +199,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
199
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200
200
|
See the License for the specific language governing permissions and
|
201
201
|
limitations under the License.
|
202
|
-
|
203
|
-
============================================================================
|
204
|
-
APACHE AIRFLOW SUBCOMPONENTS:
|
205
|
-
|
206
|
-
The Apache Airflow project contains subcomponents with separate copyright
|
207
|
-
notices and license terms. Your use of the source code for the these
|
208
|
-
subcomponents is subject to the terms and conditions of the following
|
209
|
-
licenses.
|
210
|
-
|
211
|
-
|
212
|
-
========================================================================
|
213
|
-
Third party Apache 2.0 licenses
|
214
|
-
========================================================================
|
215
|
-
|
216
|
-
The following components are provided under the Apache 2.0 License.
|
217
|
-
See project link for details. The text of each license is also included
|
218
|
-
at 3rd-party-licenses/LICENSE-[project].txt.
|
219
|
-
|
220
|
-
(ALv2 License) hue v4.3.0 (https://github.com/cloudera/hue/)
|
221
|
-
(ALv2 License) jqclock v2.3.0 (https://github.com/JohnRDOrazio/jQuery-Clock-Plugin)
|
222
|
-
(ALv2 License) bootstrap3-typeahead v4.0.2 (https://github.com/bassjobsen/Bootstrap-3-Typeahead)
|
223
|
-
(ALv2 License) connexion v2.7.0 (https://github.com/zalando/connexion)
|
224
|
-
|
225
|
-
========================================================================
|
226
|
-
MIT licenses
|
227
|
-
========================================================================
|
228
|
-
|
229
|
-
The following components are provided under the MIT License. See project link for details.
|
230
|
-
The text of each license is also included at 3rd-party-licenses/LICENSE-[project].txt.
|
231
|
-
|
232
|
-
(MIT License) jquery v3.5.1 (https://jquery.org/license/)
|
233
|
-
(MIT License) dagre-d3 v0.6.4 (https://github.com/cpettitt/dagre-d3)
|
234
|
-
(MIT License) bootstrap v3.4.1 (https://github.com/twbs/bootstrap/)
|
235
|
-
(MIT License) d3-tip v0.9.1 (https://github.com/Caged/d3-tip)
|
236
|
-
(MIT License) dataTables v1.10.25 (https://datatables.net)
|
237
|
-
(MIT License) normalize.css v3.0.2 (http://necolas.github.io/normalize.css/)
|
238
|
-
(MIT License) ElasticMock v1.3.2 (https://github.com/vrcmarcos/elasticmock)
|
239
|
-
(MIT License) MomentJS v2.24.0 (http://momentjs.com/)
|
240
|
-
(MIT License) eonasdan-bootstrap-datetimepicker v4.17.49 (https://github.com/eonasdan/bootstrap-datetimepicker/)
|
241
|
-
|
242
|
-
========================================================================
|
243
|
-
BSD 3-Clause licenses
|
244
|
-
========================================================================
|
245
|
-
The following components are provided under the BSD 3-Clause license. See project links for details.
|
246
|
-
The text of each license is also included at 3rd-party-licenses/LICENSE-[project].txt.
|
247
|
-
|
248
|
-
(BSD 3 License) d3 v5.16.0 (https://d3js.org)
|
249
|
-
(BSD 3 License) d3-shape v2.1.0 (https://github.com/d3/d3-shape)
|
250
|
-
(BSD 3 License) cgroupspy 0.2.1 (https://github.com/cloudsigma/cgroupspy)
|
251
|
-
|
252
|
-
========================================================================
|
253
|
-
See 3rd-party-licenses/LICENSES-ui.txt for packages used in `/airflow/www`
|
@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
|
|
29
29
|
|
30
30
|
__all__ = ["__version__"]
|
31
31
|
|
32
|
-
__version__ = "5.
|
32
|
+
__version__ = "5.2.0"
|
33
33
|
|
34
34
|
if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
|
35
35
|
"2.9.0"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
from __future__ import annotations
|
18
|
+
|
19
|
+
from airflow.exceptions import AirflowException
|
20
|
+
|
21
|
+
|
22
|
+
class HttpErrorException(AirflowException):
|
23
|
+
"""Exception raised for HTTP error in Http hook."""
|
24
|
+
|
25
|
+
|
26
|
+
class HttpMethodException(AirflowException):
|
27
|
+
"""Exception raised for invalid HTTP methods in Http hook."""
|
@@ -15,8 +15,7 @@
|
|
15
15
|
# specific language governing permissions and limitations
|
16
16
|
# under the License.
|
17
17
|
|
18
|
-
# NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE
|
19
|
-
# OVERWRITTEN WHEN PREPARING PACKAGES.
|
18
|
+
# NOTE! THIS FILE IS AUTOMATICALLY GENERATED AND WILL BE OVERWRITTEN!
|
20
19
|
#
|
21
20
|
# IF YOU WANT TO MODIFY THIS FILE, YOU SHOULD MODIFY THE TEMPLATE
|
22
21
|
# `get_provider_info_TEMPLATE.py.jinja2` IN the `dev/breeze/src/airflow_breeze/templates` DIRECTORY
|
@@ -28,8 +27,9 @@ def get_provider_info():
|
|
28
27
|
"name": "Hypertext Transfer Protocol (HTTP)",
|
29
28
|
"description": "`Hypertext Transfer Protocol (HTTP) <https://www.w3.org/Protocols/>`__\n",
|
30
29
|
"state": "ready",
|
31
|
-
"source-date-epoch":
|
30
|
+
"source-date-epoch": 1739963578,
|
32
31
|
"versions": [
|
32
|
+
"5.2.0",
|
33
33
|
"5.0.0",
|
34
34
|
"4.13.3",
|
35
35
|
"4.13.2",
|
@@ -68,19 +68,12 @@ def get_provider_info():
|
|
68
68
|
"1.1.0",
|
69
69
|
"1.0.0",
|
70
70
|
],
|
71
|
-
"dependencies": [
|
72
|
-
"apache-airflow>=2.9.0",
|
73
|
-
"requests>=2.27.0,<3",
|
74
|
-
"requests-toolbelt>=0.4.0",
|
75
|
-
"aiohttp>=3.9.2,!=3.11.0",
|
76
|
-
"asgiref>=2.3.0",
|
77
|
-
],
|
78
71
|
"integrations": [
|
79
72
|
{
|
80
73
|
"integration-name": "Hypertext Transfer Protocol (HTTP)",
|
81
74
|
"external-doc-url": "https://www.w3.org/Protocols/",
|
82
75
|
"how-to-guide": ["/docs/apache-airflow-providers-http/operators.rst"],
|
83
|
-
"logo": "/integration-logos/
|
76
|
+
"logo": "/docs/integration-logos/HTTP.png",
|
84
77
|
"tags": ["protocol"],
|
85
78
|
}
|
86
79
|
],
|
@@ -111,4 +104,11 @@ def get_provider_info():
|
|
111
104
|
"connection-types": [
|
112
105
|
{"hook-class-name": "airflow.providers.http.hooks.http.HttpHook", "connection-type": "http"}
|
113
106
|
],
|
107
|
+
"dependencies": [
|
108
|
+
"apache-airflow>=2.9.0",
|
109
|
+
"requests>=2.27.0,<3",
|
110
|
+
"requests-toolbelt>=0.4.0",
|
111
|
+
"aiohttp>=3.9.2,!=3.11.0",
|
112
|
+
"asgiref>=2.3.0",
|
113
|
+
],
|
114
114
|
}
|
@@ -17,21 +17,22 @@
|
|
17
17
|
# under the License.
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
-
import asyncio
|
21
20
|
from typing import TYPE_CHECKING, Any, Callable
|
22
21
|
from urllib.parse import urlparse
|
23
22
|
|
24
23
|
import aiohttp
|
25
|
-
import requests
|
26
24
|
import tenacity
|
27
25
|
from aiohttp import ClientResponseError
|
28
26
|
from asgiref.sync import sync_to_async
|
27
|
+
from requests import PreparedRequest, Request, Response, Session
|
29
28
|
from requests.auth import HTTPBasicAuth
|
29
|
+
from requests.exceptions import ConnectionError, HTTPError
|
30
30
|
from requests.models import DEFAULT_REDIRECT_LIMIT
|
31
31
|
from requests_toolbelt.adapters.socket_options import TCPKeepAliveAdapter
|
32
32
|
|
33
33
|
from airflow.exceptions import AirflowException
|
34
34
|
from airflow.hooks.base import BaseHook
|
35
|
+
from airflow.providers.http.exceptions import HttpErrorException, HttpMethodException
|
35
36
|
|
36
37
|
if TYPE_CHECKING:
|
37
38
|
from aiohttp.client_reqrep import ClientResponse
|
@@ -47,6 +48,39 @@ def _url_from_endpoint(base_url: str | None, endpoint: str | None) -> str:
|
|
47
48
|
return (base_url or "") + (endpoint or "")
|
48
49
|
|
49
50
|
|
51
|
+
def _process_extra_options_from_connection(conn: Connection, extra_options: dict[str, Any]) -> dict:
|
52
|
+
extra = conn.extra_dejson
|
53
|
+
stream = extra.pop("stream", None)
|
54
|
+
cert = extra.pop("cert", None)
|
55
|
+
proxies = extra.pop("proxies", extra.pop("proxy", None))
|
56
|
+
timeout = extra.pop("timeout", None)
|
57
|
+
verify_ssl = extra.pop("verify", extra.pop("verify_ssl", None))
|
58
|
+
allow_redirects = extra.pop("allow_redirects", None)
|
59
|
+
max_redirects = extra.pop("max_redirects", None)
|
60
|
+
trust_env = extra.pop("trust_env", None)
|
61
|
+
check_response = extra.pop("check_response", None)
|
62
|
+
|
63
|
+
if stream is not None and "stream" not in extra_options:
|
64
|
+
extra_options["stream"] = stream
|
65
|
+
if cert is not None and "cert" not in extra_options:
|
66
|
+
extra_options["cert"] = cert
|
67
|
+
if proxies is not None and "proxy" not in extra_options:
|
68
|
+
extra_options["proxy"] = proxies
|
69
|
+
if timeout is not None and "timeout" not in extra_options:
|
70
|
+
extra_options["timeout"] = timeout
|
71
|
+
if verify_ssl is not None and "verify_ssl" not in extra_options:
|
72
|
+
extra_options["verify_ssl"] = verify_ssl
|
73
|
+
if allow_redirects is not None and "allow_redirects" not in extra_options:
|
74
|
+
extra_options["allow_redirects"] = allow_redirects
|
75
|
+
if max_redirects is not None and "max_redirects" not in extra_options:
|
76
|
+
extra_options["max_redirects"] = max_redirects
|
77
|
+
if trust_env is not None and "trust_env" not in extra_options:
|
78
|
+
extra_options["trust_env"] = trust_env
|
79
|
+
if check_response is not None and "check_response" not in extra_options:
|
80
|
+
extra_options["check_response"] = check_response
|
81
|
+
return extra
|
82
|
+
|
83
|
+
|
50
84
|
class HttpHook(BaseHook):
|
51
85
|
"""
|
52
86
|
Interact with HTTP servers.
|
@@ -69,6 +103,8 @@ class HttpHook(BaseHook):
|
|
69
103
|
default_conn_name = "http_default"
|
70
104
|
conn_type = "http"
|
71
105
|
hook_name = "HTTP"
|
106
|
+
default_host = ""
|
107
|
+
default_headers: dict[str, str] = {}
|
72
108
|
|
73
109
|
def __init__(
|
74
110
|
self,
|
@@ -109,26 +145,31 @@ class HttpHook(BaseHook):
|
|
109
145
|
|
110
146
|
# headers may be passed through directly or in the "extra" field in the connection
|
111
147
|
# definition
|
112
|
-
def get_conn(
|
148
|
+
def get_conn(
|
149
|
+
self, headers: dict[Any, Any] | None = None, extra_options: dict[str, Any] | None = None
|
150
|
+
) -> Session:
|
113
151
|
"""
|
114
152
|
Create a Requests HTTP session.
|
115
153
|
|
116
154
|
:param headers: Additional headers to be passed through as a dictionary.
|
155
|
+
:param extra_options: additional options to be used when executing the request
|
117
156
|
:return: A configured requests.Session object.
|
118
157
|
"""
|
119
|
-
session =
|
158
|
+
session = Session()
|
120
159
|
connection = self.get_connection(self.http_conn_id)
|
121
160
|
self._set_base_url(connection)
|
122
161
|
session = self._configure_session_from_auth(session, connection)
|
123
162
|
if connection.extra:
|
124
|
-
session = self._configure_session_from_extra(session, connection)
|
163
|
+
session = self._configure_session_from_extra(session, connection, extra_options)
|
125
164
|
session = self._configure_session_from_mount_adapters(session)
|
165
|
+
if self.default_headers:
|
166
|
+
session.headers.update(self.default_headers)
|
126
167
|
if headers:
|
127
168
|
session.headers.update(headers)
|
128
169
|
return session
|
129
170
|
|
130
171
|
def _set_base_url(self, connection: Connection) -> None:
|
131
|
-
host = connection.host or
|
172
|
+
host = connection.host or self.default_host
|
132
173
|
schema = connection.schema or "http"
|
133
174
|
# RFC 3986 (https://www.rfc-editor.org/rfc/rfc3986.html#page-16)
|
134
175
|
if "://" in host:
|
@@ -141,9 +182,7 @@ class HttpHook(BaseHook):
|
|
141
182
|
if not parsed.scheme:
|
142
183
|
raise ValueError(f"Invalid base URL: Missing scheme in {self.base_url}")
|
143
184
|
|
144
|
-
def _configure_session_from_auth(
|
145
|
-
self, session: requests.Session, connection: Connection
|
146
|
-
) -> requests.Session:
|
185
|
+
def _configure_session_from_auth(self, session: Session, connection: Connection) -> Session:
|
147
186
|
session.auth = self._extract_auth(connection)
|
148
187
|
return session
|
149
188
|
|
@@ -155,24 +194,24 @@ class HttpHook(BaseHook):
|
|
155
194
|
return None
|
156
195
|
|
157
196
|
def _configure_session_from_extra(
|
158
|
-
self, session:
|
159
|
-
) ->
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
session.proxies =
|
164
|
-
session.stream =
|
165
|
-
session.verify =
|
166
|
-
session.cert =
|
167
|
-
session.max_redirects =
|
168
|
-
session.trust_env =
|
197
|
+
self, session: Session, connection: Connection, extra_options: dict[str, Any] | None = None
|
198
|
+
) -> Session:
|
199
|
+
if extra_options is None:
|
200
|
+
extra_options = {}
|
201
|
+
headers = _process_extra_options_from_connection(connection, extra_options)
|
202
|
+
session.proxies = extra_options.pop("proxies", extra_options.pop("proxy", {}))
|
203
|
+
session.stream = extra_options.pop("stream", False)
|
204
|
+
session.verify = extra_options.pop("verify", extra_options.pop("verify_ssl", True))
|
205
|
+
session.cert = extra_options.pop("cert", None)
|
206
|
+
session.max_redirects = extra_options.pop("max_redirects", DEFAULT_REDIRECT_LIMIT)
|
207
|
+
session.trust_env = extra_options.pop("trust_env", True)
|
169
208
|
try:
|
170
|
-
session.headers.update(
|
209
|
+
session.headers.update(headers)
|
171
210
|
except TypeError:
|
172
211
|
self.log.warning("Connection to %s has invalid extra field.", connection.host)
|
173
212
|
return session
|
174
213
|
|
175
|
-
def _configure_session_from_mount_adapters(self, session:
|
214
|
+
def _configure_session_from_mount_adapters(self, session: Session) -> Session:
|
176
215
|
scheme = urlparse(self.base_url).scheme
|
177
216
|
if not scheme:
|
178
217
|
raise ValueError(
|
@@ -207,25 +246,25 @@ class HttpHook(BaseHook):
|
|
207
246
|
"""
|
208
247
|
extra_options = extra_options or {}
|
209
248
|
|
210
|
-
session = self.get_conn(headers)
|
249
|
+
session = self.get_conn(headers, extra_options)
|
211
250
|
|
212
251
|
url = self.url_from_endpoint(endpoint)
|
213
252
|
|
214
253
|
if self.method == "GET":
|
215
254
|
# GET uses params
|
216
|
-
req =
|
255
|
+
req = Request(self.method, url, params=data, headers=headers, **request_kwargs)
|
217
256
|
elif self.method == "HEAD":
|
218
257
|
# HEAD doesn't use params
|
219
|
-
req =
|
258
|
+
req = Request(self.method, url, headers=headers, **request_kwargs)
|
220
259
|
else:
|
221
260
|
# Others use data
|
222
|
-
req =
|
261
|
+
req = Request(self.method, url, data=data, headers=headers, **request_kwargs)
|
223
262
|
|
224
263
|
prepped_request = session.prepare_request(req)
|
225
264
|
self.log.debug("Sending '%s' to url: %s", self.method, url)
|
226
265
|
return self.run_and_check(session, prepped_request, extra_options)
|
227
266
|
|
228
|
-
def check_response(self, response:
|
267
|
+
def check_response(self, response: Response) -> None:
|
229
268
|
"""
|
230
269
|
Check the status code and raise on failure.
|
231
270
|
|
@@ -235,15 +274,15 @@ class HttpHook(BaseHook):
|
|
235
274
|
"""
|
236
275
|
try:
|
237
276
|
response.raise_for_status()
|
238
|
-
except
|
277
|
+
except HTTPError:
|
239
278
|
self.log.error("HTTP error: %s", response.reason)
|
240
279
|
self.log.error(response.text)
|
241
280
|
raise AirflowException(str(response.status_code) + ":" + response.reason)
|
242
281
|
|
243
282
|
def run_and_check(
|
244
283
|
self,
|
245
|
-
session:
|
246
|
-
prepped_request:
|
284
|
+
session: Session,
|
285
|
+
prepped_request: PreparedRequest,
|
247
286
|
extra_options: dict[Any, Any],
|
248
287
|
) -> Any:
|
249
288
|
"""
|
@@ -279,7 +318,7 @@ class HttpHook(BaseHook):
|
|
279
318
|
self.check_response(response)
|
280
319
|
return response
|
281
320
|
|
282
|
-
except
|
321
|
+
except ConnectionError as ex:
|
283
322
|
self.log.warning("%s Tenacity will retry to execute the operation", ex)
|
284
323
|
raise ex
|
285
324
|
|
@@ -359,6 +398,7 @@ class HttpAsyncHook(BaseHook):
|
|
359
398
|
|
360
399
|
async def run(
|
361
400
|
self,
|
401
|
+
session: aiohttp.ClientSession,
|
362
402
|
endpoint: str | None = None,
|
363
403
|
data: dict[str, Any] | str | None = None,
|
364
404
|
json: dict[str, Any] | str | None = None,
|
@@ -399,7 +439,7 @@ class HttpAsyncHook(BaseHook):
|
|
399
439
|
if conn.login:
|
400
440
|
auth = self.auth_type(conn.login, conn.password)
|
401
441
|
if conn.extra:
|
402
|
-
extra =
|
442
|
+
extra = _process_extra_options_from_connection(conn=conn, extra_options=extra_options)
|
403
443
|
|
404
444
|
try:
|
405
445
|
_headers.update(extra)
|
@@ -410,80 +450,51 @@ class HttpAsyncHook(BaseHook):
|
|
410
450
|
|
411
451
|
url = _url_from_endpoint(self.base_url, endpoint)
|
412
452
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
453
|
+
if self.method == "GET":
|
454
|
+
request_func = session.get
|
455
|
+
elif self.method == "POST":
|
456
|
+
request_func = session.post
|
457
|
+
elif self.method == "PATCH":
|
458
|
+
request_func = session.patch
|
459
|
+
elif self.method == "HEAD":
|
460
|
+
request_func = session.head
|
461
|
+
elif self.method == "PUT":
|
462
|
+
request_func = session.put
|
463
|
+
elif self.method == "DELETE":
|
464
|
+
request_func = session.delete
|
465
|
+
elif self.method == "OPTIONS":
|
466
|
+
request_func = session.options
|
467
|
+
else:
|
468
|
+
raise HttpMethodException(f"Unexpected HTTP Method: {self.method}")
|
469
|
+
|
470
|
+
for attempt in range(1, 1 + self.retry_limit):
|
471
|
+
response = await request_func(
|
472
|
+
url,
|
473
|
+
params=data if self.method == "GET" else None,
|
474
|
+
data=data if self.method in ("POST", "PUT", "PATCH") else None,
|
475
|
+
json=json,
|
476
|
+
headers=_headers,
|
477
|
+
auth=auth,
|
478
|
+
**extra_options,
|
479
|
+
)
|
480
|
+
try:
|
481
|
+
response.raise_for_status()
|
482
|
+
except ClientResponseError as e:
|
483
|
+
self.log.warning(
|
484
|
+
"[Try %d of %d] Request to %s failed.",
|
485
|
+
attempt,
|
486
|
+
self.retry_limit,
|
433
487
|
url,
|
434
|
-
params=data if self.method == "GET" else None,
|
435
|
-
data=data if self.method in ("POST", "PUT", "PATCH") else None,
|
436
|
-
json=json,
|
437
|
-
headers=_headers,
|
438
|
-
auth=auth,
|
439
|
-
**extra_options,
|
440
488
|
)
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
attempt,
|
447
|
-
self.retry_limit,
|
448
|
-
url,
|
449
|
-
)
|
450
|
-
if not self._retryable_error_async(e) or attempt == self.retry_limit:
|
451
|
-
self.log.exception("HTTP error with status: %s", e.status)
|
452
|
-
# In this case, the user probably made a mistake.
|
453
|
-
# Don't retry.
|
454
|
-
raise AirflowException(f"{e.status}:{e.message}")
|
455
|
-
else:
|
456
|
-
await asyncio.sleep(self.retry_delay)
|
457
|
-
else:
|
458
|
-
return response
|
489
|
+
if not self._retryable_error_async(e) or attempt == self.retry_limit:
|
490
|
+
self.log.exception("HTTP error with status: %s", e.status)
|
491
|
+
# In this case, the user probably made a mistake.
|
492
|
+
# Don't retry.
|
493
|
+
raise HttpErrorException(f"{e.status}:{e.message}")
|
459
494
|
else:
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
def _process_extra_options_from_connection(cls, conn: Connection, extra_options: dict) -> dict:
|
464
|
-
extra = conn.extra_dejson
|
465
|
-
extra.pop("stream", None)
|
466
|
-
extra.pop("cert", None)
|
467
|
-
proxies = extra.pop("proxies", extra.pop("proxy", None))
|
468
|
-
timeout = extra.pop("timeout", None)
|
469
|
-
verify_ssl = extra.pop("verify", extra.pop("verify_ssl", None))
|
470
|
-
allow_redirects = extra.pop("allow_redirects", None)
|
471
|
-
max_redirects = extra.pop("max_redirects", None)
|
472
|
-
trust_env = extra.pop("trust_env", None)
|
473
|
-
|
474
|
-
if proxies is not None and "proxy" not in extra_options:
|
475
|
-
extra_options["proxy"] = proxies
|
476
|
-
if timeout is not None and "timeout" not in extra_options:
|
477
|
-
extra_options["timeout"] = timeout
|
478
|
-
if verify_ssl is not None and "verify_ssl" not in extra_options:
|
479
|
-
extra_options["verify_ssl"] = verify_ssl
|
480
|
-
if allow_redirects is not None and "allow_redirects" not in extra_options:
|
481
|
-
extra_options["allow_redirects"] = allow_redirects
|
482
|
-
if max_redirects is not None and "max_redirects" not in extra_options:
|
483
|
-
extra_options["max_redirects"] = max_redirects
|
484
|
-
if trust_env is not None and "trust_env" not in extra_options:
|
485
|
-
extra_options["trust_env"] = trust_env
|
486
|
-
return extra
|
495
|
+
return response
|
496
|
+
|
497
|
+
raise NotImplementedError # should not reach this, but makes mypy happy
|
487
498
|
|
488
499
|
def _retryable_error_async(self, exception: ClientResponseError) -> bool:
|
489
500
|
"""
|
@@ -35,7 +35,12 @@ if TYPE_CHECKING:
|
|
35
35
|
from requests.auth import AuthBase
|
36
36
|
|
37
37
|
from airflow.providers.http.hooks.http import HttpHook
|
38
|
-
|
38
|
+
|
39
|
+
try:
|
40
|
+
from airflow.sdk.definitions.context import Context
|
41
|
+
except ImportError:
|
42
|
+
# TODO: Remove once provider drops support for Airflow 2
|
43
|
+
from airflow.utils.context import Context
|
39
44
|
|
40
45
|
|
41
46
|
class HttpOperator(BaseOperator):
|
@@ -28,7 +28,11 @@ from airflow.providers.http.triggers.http import HttpSensorTrigger
|
|
28
28
|
from airflow.sensors.base import BaseSensorOperator
|
29
29
|
|
30
30
|
if TYPE_CHECKING:
|
31
|
-
|
31
|
+
try:
|
32
|
+
from airflow.sdk.definitions.context import Context
|
33
|
+
except ImportError:
|
34
|
+
# TODO: Remove once provider drops support for Airflow 2
|
35
|
+
from airflow.utils.context import Context
|
32
36
|
|
33
37
|
|
34
38
|
class HttpSensor(BaseSensorOperator):
|
@@ -22,6 +22,7 @@ import pickle
|
|
22
22
|
from collections.abc import AsyncIterator
|
23
23
|
from typing import TYPE_CHECKING, Any
|
24
24
|
|
25
|
+
import aiohttp
|
25
26
|
import requests
|
26
27
|
from requests.cookies import RequestsCookieJar
|
27
28
|
from requests.structures import CaseInsensitiveDict
|
@@ -94,13 +95,15 @@ class HttpTrigger(BaseTrigger):
|
|
94
95
|
auth_type=self.auth_type,
|
95
96
|
)
|
96
97
|
try:
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
98
|
+
async with aiohttp.ClientSession() as session:
|
99
|
+
client_response = await hook.run(
|
100
|
+
session=session,
|
101
|
+
endpoint=self.endpoint,
|
102
|
+
data=self.data,
|
103
|
+
headers=self.headers,
|
104
|
+
extra_options=self.extra_options,
|
105
|
+
)
|
106
|
+
response = await self._convert_response(client_response)
|
104
107
|
yield TriggerEvent(
|
105
108
|
{
|
106
109
|
"status": "success",
|
@@ -181,12 +184,14 @@ class HttpSensorTrigger(BaseTrigger):
|
|
181
184
|
hook = self._get_async_hook()
|
182
185
|
while True:
|
183
186
|
try:
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
187
|
+
async with aiohttp.ClientSession() as session:
|
188
|
+
await hook.run(
|
189
|
+
session=session,
|
190
|
+
endpoint=self.endpoint,
|
191
|
+
data=self.data,
|
192
|
+
headers=self.headers,
|
193
|
+
extra_options=self.extra_options,
|
194
|
+
)
|
190
195
|
yield TriggerEvent(True)
|
191
196
|
return
|
192
197
|
except AirflowException as exc:
|
File without changes
|
File without changes
|
File without changes
|