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.

@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
29
29
 
30
30
  __all__ = ["__version__"]
31
31
 
32
- __version__ = "5.3.4"
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 = HttpAsyncHook(
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
- async with aiohttp.ClientSession() as session:
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
@@ -33,6 +33,7 @@ def get_base_airflow_version_tuple() -> tuple[int, int, int]:
33
33
 
34
34
 
35
35
  AIRFLOW_V_3_0_PLUS = get_base_airflow_version_tuple() >= (3, 0, 0)
36
+
36
37
  AIRFLOW_V_3_1_PLUS: bool = get_base_airflow_version_tuple() >= (3, 1, 0)
37
38
 
38
39
  if AIRFLOW_V_3_1_PLUS:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apache-airflow-providers-http
3
- Version: 5.3.4
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.0
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.3.4/changelog.html
30
- Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-http/5.3.4
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.3.4``
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.3.4/>`_.
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.3.4/changelog.html>`_.
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=RmrtyqR3ka6J3c4gx9P5sv3P4biGxAWT5wulO7Yiqz4,1493
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=MGhWZkvkF4S7MI6wOQmQrUCKHJ2vqDe1WjSkQNyAtRU,2082
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=DG4_20edkRT44grqB5Gyx8pD0ueYsTURpsBMRwO1SNQ,8501
14
- apache_airflow_providers_http-5.3.4.dist-info/entry_points.txt,sha256=65Rk4MYlxxtwo7y7-uNv4KS7MfoBnILhMjRQmNbRo1Q,100
15
- apache_airflow_providers_http-5.3.4.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
16
- apache_airflow_providers_http-5.3.4.dist-info/METADATA,sha256=24sxYo0EMGgNm3B5NMm8W1zrlMtoqLQHcxH6TX0XKvQ,4088
17
- apache_airflow_providers_http-5.3.4.dist-info/RECORD,,
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,,