apache-airflow-providers-http 5.3.4__py3-none-any.whl → 5.4.0rc1__py3-none-any.whl
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.
Potentially problematic release.
This version of apache-airflow-providers-http might be problematic. Click here for more details.
- airflow/providers/http/__init__.py +1 -1
- airflow/providers/http/triggers/http.py +112 -14
- airflow/providers/http/version_compat.py +1 -0
- {apache_airflow_providers_http-5.3.4.dist-info → apache_airflow_providers_http-5.4.0rc1.dist-info}/METADATA +7 -7
- {apache_airflow_providers_http-5.3.4.dist-info → apache_airflow_providers_http-5.4.0rc1.dist-info}/RECORD +7 -7
- {apache_airflow_providers_http-5.3.4.dist-info → apache_airflow_providers_http-5.4.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_http-5.3.4.dist-info → apache_airflow_providers_http-5.4.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -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.4.0"
|
|
33
33
|
|
|
34
34
|
if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
|
|
35
35
|
"2.10.0"
|
|
@@ -18,20 +18,30 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import asyncio
|
|
20
20
|
import base64
|
|
21
|
+
import importlib
|
|
22
|
+
import inspect
|
|
21
23
|
import pickle
|
|
24
|
+
import sys
|
|
22
25
|
from collections.abc import AsyncIterator
|
|
23
26
|
from importlib import import_module
|
|
24
27
|
from typing import TYPE_CHECKING, Any
|
|
25
28
|
|
|
26
29
|
import aiohttp
|
|
27
30
|
import requests
|
|
31
|
+
from asgiref.sync import sync_to_async
|
|
28
32
|
from requests.cookies import RequestsCookieJar
|
|
29
33
|
from requests.structures import CaseInsensitiveDict
|
|
30
34
|
|
|
31
35
|
from airflow.exceptions import AirflowException
|
|
32
36
|
from airflow.providers.http.hooks.http import HttpAsyncHook
|
|
37
|
+
from airflow.providers.http.version_compat import AIRFLOW_V_3_0_PLUS
|
|
33
38
|
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
|
34
39
|
|
|
40
|
+
if AIRFLOW_V_3_0_PLUS:
|
|
41
|
+
from airflow.triggers.base import BaseEventTrigger
|
|
42
|
+
else:
|
|
43
|
+
from airflow.triggers.base import BaseTrigger as BaseEventTrigger # type: ignore
|
|
44
|
+
|
|
35
45
|
if TYPE_CHECKING:
|
|
36
46
|
from aiohttp.client_reqrep import ClientResponse
|
|
37
47
|
|
|
@@ -105,21 +115,9 @@ class HttpTrigger(BaseTrigger):
|
|
|
105
115
|
|
|
106
116
|
async def run(self) -> AsyncIterator[TriggerEvent]:
|
|
107
117
|
"""Make a series of asynchronous http calls via a http hook."""
|
|
108
|
-
hook =
|
|
109
|
-
method=self.method,
|
|
110
|
-
http_conn_id=self.http_conn_id,
|
|
111
|
-
auth_type=self.auth_type,
|
|
112
|
-
)
|
|
118
|
+
hook = self._get_async_hook()
|
|
113
119
|
try:
|
|
114
|
-
|
|
115
|
-
client_response = await hook.run(
|
|
116
|
-
session=session,
|
|
117
|
-
endpoint=self.endpoint,
|
|
118
|
-
data=self.data,
|
|
119
|
-
headers=self.headers,
|
|
120
|
-
extra_options=self.extra_options,
|
|
121
|
-
)
|
|
122
|
-
response = await self._convert_response(client_response)
|
|
120
|
+
response = await self._get_response(hook)
|
|
123
121
|
yield TriggerEvent(
|
|
124
122
|
{
|
|
125
123
|
"status": "success",
|
|
@@ -129,6 +127,25 @@ class HttpTrigger(BaseTrigger):
|
|
|
129
127
|
except Exception as e:
|
|
130
128
|
yield TriggerEvent({"status": "error", "message": str(e)})
|
|
131
129
|
|
|
130
|
+
def _get_async_hook(self) -> HttpAsyncHook:
|
|
131
|
+
return HttpAsyncHook(
|
|
132
|
+
method=self.method,
|
|
133
|
+
http_conn_id=self.http_conn_id,
|
|
134
|
+
auth_type=self.auth_type,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
async def _get_response(self, hook):
|
|
138
|
+
async with aiohttp.ClientSession() as session:
|
|
139
|
+
client_response = await hook.run(
|
|
140
|
+
session=session,
|
|
141
|
+
endpoint=self.endpoint,
|
|
142
|
+
data=self.data,
|
|
143
|
+
headers=self.headers,
|
|
144
|
+
extra_options=self.extra_options,
|
|
145
|
+
)
|
|
146
|
+
response = await self._convert_response(client_response)
|
|
147
|
+
return response
|
|
148
|
+
|
|
132
149
|
@staticmethod
|
|
133
150
|
async def _convert_response(client_response: ClientResponse) -> requests.Response:
|
|
134
151
|
"""Convert aiohttp.client_reqrep.ClientResponse to requests.Response."""
|
|
@@ -219,3 +236,84 @@ class HttpSensorTrigger(BaseTrigger):
|
|
|
219
236
|
method=self.method,
|
|
220
237
|
http_conn_id=self.http_conn_id,
|
|
221
238
|
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class HttpEventTrigger(HttpTrigger, BaseEventTrigger):
|
|
242
|
+
"""
|
|
243
|
+
HttpEventTrigger for event-based DAG scheduling when the API response satisfies the response check.
|
|
244
|
+
|
|
245
|
+
:param response_check_path: Path to the function that evaluates whether the API response
|
|
246
|
+
passes the conditions set by the user to fire the trigger. The method must be asynchronous.
|
|
247
|
+
:param http_conn_id: http connection id that has the base
|
|
248
|
+
API url i.e https://www.google.com/ and optional authentication credentials. Default
|
|
249
|
+
headers can also be specified in the Extra field in json format.
|
|
250
|
+
:param auth_type: The auth type for the service
|
|
251
|
+
:param method: The API method to be called
|
|
252
|
+
:param endpoint: Endpoint to be called, i.e. ``resource/v1/query?``.
|
|
253
|
+
:param headers: Additional headers to be passed through as a dict.
|
|
254
|
+
:param data: Payload to be uploaded or request parameters.
|
|
255
|
+
:param extra_options: Additional kwargs to pass when creating a request.
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
def __init__(
|
|
259
|
+
self,
|
|
260
|
+
response_check_path: str,
|
|
261
|
+
http_conn_id: str = "http_default",
|
|
262
|
+
auth_type: Any = None,
|
|
263
|
+
method: str = "GET",
|
|
264
|
+
endpoint: str | None = None,
|
|
265
|
+
headers: dict[str, str] | None = None,
|
|
266
|
+
data: dict[str, Any] | str | None = None,
|
|
267
|
+
extra_options: dict[str, Any] | None = None,
|
|
268
|
+
):
|
|
269
|
+
super().__init__(http_conn_id, auth_type, method, endpoint, headers, data, extra_options)
|
|
270
|
+
self.response_check_path = response_check_path
|
|
271
|
+
|
|
272
|
+
def serialize(self) -> tuple[str, dict[str, Any]]:
|
|
273
|
+
"""Serialize HttpEventTrigger arguments and classpath."""
|
|
274
|
+
return (
|
|
275
|
+
self.__class__.__module__ + "." + self.__class__.__qualname__,
|
|
276
|
+
{
|
|
277
|
+
"http_conn_id": self.http_conn_id,
|
|
278
|
+
"method": self.method,
|
|
279
|
+
"auth_type": self.auth_type,
|
|
280
|
+
"endpoint": self.endpoint,
|
|
281
|
+
"headers": self.headers,
|
|
282
|
+
"data": self.data,
|
|
283
|
+
"extra_options": self.extra_options,
|
|
284
|
+
"response_check_path": self.response_check_path,
|
|
285
|
+
},
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
async def run(self) -> AsyncIterator[TriggerEvent]:
|
|
289
|
+
"""Make a series of asynchronous http calls via a http hook until the response passes the response check."""
|
|
290
|
+
hook = super()._get_async_hook()
|
|
291
|
+
try:
|
|
292
|
+
while True:
|
|
293
|
+
response = await super()._get_response(hook)
|
|
294
|
+
if await self._run_response_check(response):
|
|
295
|
+
break
|
|
296
|
+
yield TriggerEvent(
|
|
297
|
+
{
|
|
298
|
+
"status": "success",
|
|
299
|
+
"response": base64.standard_b64encode(pickle.dumps(response)).decode("ascii"),
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
except Exception as e:
|
|
303
|
+
self.log.error("status: error, message: %s", str(e))
|
|
304
|
+
|
|
305
|
+
async def _import_from_response_check_path(self):
|
|
306
|
+
"""Import the response check callable from the path provided by the user."""
|
|
307
|
+
module_path, func_name = self.response_check_path.rsplit(".", 1)
|
|
308
|
+
if module_path in sys.modules:
|
|
309
|
+
module = await sync_to_async(importlib.reload)(sys.modules[module_path])
|
|
310
|
+
module = await sync_to_async(importlib.import_module)(module_path)
|
|
311
|
+
return getattr(module, func_name)
|
|
312
|
+
|
|
313
|
+
async def _run_response_check(self, response) -> bool:
|
|
314
|
+
"""Run the response_check callable provided by the user."""
|
|
315
|
+
response_check = await self._import_from_response_check_path()
|
|
316
|
+
if not inspect.iscoroutinefunction(response_check):
|
|
317
|
+
raise AirflowException("The response_check callable is not asynchronous.")
|
|
318
|
+
check = await response_check(response)
|
|
319
|
+
return check
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apache-airflow-providers-http
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.4.0rc1
|
|
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,14 +20,14 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: System :: Monitoring
|
|
23
|
-
Requires-Dist: apache-airflow>=2.10.
|
|
23
|
+
Requires-Dist: apache-airflow>=2.10.0rc1
|
|
24
24
|
Requires-Dist: requests>=2.32.0,<3
|
|
25
25
|
Requires-Dist: requests-toolbelt>=1.0.0
|
|
26
26
|
Requires-Dist: aiohttp>=3.12.14
|
|
27
27
|
Requires-Dist: asgiref>=2.3.0
|
|
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.staged.apache.org/docs/apache-airflow-providers-http/5.4.0/changelog.html
|
|
30
|
+
Project-URL: Documentation, https://airflow.staged.apache.org/docs/apache-airflow-providers-http/5.4.0
|
|
31
31
|
Project-URL: Mastodon, https://fosstodon.org/@airflow
|
|
32
32
|
Project-URL: Slack Chat, https://s.apache.org/airflow-slack
|
|
33
33
|
Project-URL: Source Code, https://github.com/apache/airflow
|
|
@@ -58,7 +58,7 @@ Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
|
|
|
58
58
|
|
|
59
59
|
Package ``apache-airflow-providers-http``
|
|
60
60
|
|
|
61
|
-
Release: ``5.
|
|
61
|
+
Release: ``5.4.0``
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
`Hypertext Transfer Protocol (HTTP) <https://www.w3.org/Protocols/>`__
|
|
@@ -71,7 +71,7 @@ This is a provider package for ``http`` provider. All classes for this provider
|
|
|
71
71
|
are in ``airflow.providers.http`` python package.
|
|
72
72
|
|
|
73
73
|
You can find package information and changelog for the provider
|
|
74
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
|
74
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-http/5.4.0/>`_.
|
|
75
75
|
|
|
76
76
|
Installation
|
|
77
77
|
------------
|
|
@@ -96,5 +96,5 @@ PIP package Version required
|
|
|
96
96
|
===================== ==================
|
|
97
97
|
|
|
98
98
|
The changelog for the provider package can be found in the
|
|
99
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.
|
|
99
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-http/5.4.0/changelog.html>`_.
|
|
100
100
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
airflow/providers/http/LICENSE,sha256=gXPVwptPlW1TJ4HSuG5OMPg-a3h43OGMkZRR1rpwfJA,10850
|
|
2
|
-
airflow/providers/http/__init__.py,sha256=
|
|
2
|
+
airflow/providers/http/__init__.py,sha256=TkZJvkSq4g9quBruQL2QpSuh8OpLxS2hgjzIW2oScwU,1493
|
|
3
3
|
airflow/providers/http/exceptions.py,sha256=WnIEj0cnAS746uRF1661tCEBc_Uuo0bMEIMrQyEb9nc,1084
|
|
4
4
|
airflow/providers/http/get_provider_info.py,sha256=eJrWksE0KVCB32BavHb64imCUZZIoWyJYnsBj8UsS9Y,2657
|
|
5
|
-
airflow/providers/http/version_compat.py,sha256=
|
|
5
|
+
airflow/providers/http/version_compat.py,sha256=v-uQ9ARthMV1C075gyNfc1w7xDtcxQzLH0zpuoB9rB0,2083
|
|
6
6
|
airflow/providers/http/hooks/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
|
|
7
7
|
airflow/providers/http/hooks/http.py,sha256=MoEyhIJtXB9sNy-Avrrm2oVc4VugAlBSq18CAvylJgo,22587
|
|
8
8
|
airflow/providers/http/operators/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
|
|
@@ -10,8 +10,8 @@ airflow/providers/http/operators/http.py,sha256=KzviUKRlf0-Omam9bjQuguWhvHmQTtlZ
|
|
|
10
10
|
airflow/providers/http/sensors/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
|
|
11
11
|
airflow/providers/http/sensors/http.py,sha256=4lIgV7-3AUy64tAv9N5lKiDtWYaqaVHG_cXkz_Gijq8,8502
|
|
12
12
|
airflow/providers/http/triggers/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
|
|
13
|
-
airflow/providers/http/triggers/http.py,sha256=
|
|
14
|
-
apache_airflow_providers_http-5.
|
|
15
|
-
apache_airflow_providers_http-5.
|
|
16
|
-
apache_airflow_providers_http-5.
|
|
17
|
-
apache_airflow_providers_http-5.
|
|
13
|
+
airflow/providers/http/triggers/http.py,sha256=67Ri86fOubQJtto_cF2aOo9U7xA46Qjg60LqfdFgn6M,12709
|
|
14
|
+
apache_airflow_providers_http-5.4.0rc1.dist-info/entry_points.txt,sha256=65Rk4MYlxxtwo7y7-uNv4KS7MfoBnILhMjRQmNbRo1Q,100
|
|
15
|
+
apache_airflow_providers_http-5.4.0rc1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
16
|
+
apache_airflow_providers_http-5.4.0rc1.dist-info/METADATA,sha256=2RsnhxmkagmnYvCiZFgS1bA3jm4nE1KxyXgdGjno88g,4108
|
|
17
|
+
apache_airflow_providers_http-5.4.0rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|