apache-airflow-providers-microsoft-azure 10.0.0rc1__py3-none-any.whl → 10.1.0__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.
@@ -0,0 +1,281 @@
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
+ from __future__ import annotations
19
+
20
+ from copy import deepcopy
21
+ from typing import (
22
+ TYPE_CHECKING,
23
+ Any,
24
+ Callable,
25
+ Sequence,
26
+ )
27
+
28
+ from airflow.exceptions import AirflowException, TaskDeferred
29
+ from airflow.models import BaseOperator
30
+ from airflow.providers.microsoft.azure.hooks.msgraph import KiotaRequestAdapterHook
31
+ from airflow.providers.microsoft.azure.triggers.msgraph import (
32
+ MSGraphTrigger,
33
+ ResponseSerializer,
34
+ )
35
+ from airflow.utils.xcom import XCOM_RETURN_KEY
36
+
37
+ if TYPE_CHECKING:
38
+ from io import BytesIO
39
+
40
+ from kiota_abstractions.request_adapter import ResponseType
41
+ from kiota_abstractions.request_information import QueryParams
42
+ from msgraph_core import APIVersion
43
+
44
+ from airflow.utils.context import Context
45
+
46
+
47
+ class MSGraphAsyncOperator(BaseOperator):
48
+ """
49
+ A Microsoft Graph API operator which allows you to execute REST call to the Microsoft Graph API.
50
+
51
+ https://learn.microsoft.com/en-us/graph/use-the-api
52
+
53
+ .. seealso::
54
+ For more information on how to use this operator, take a look at the guide:
55
+ :ref:`howto/operator:MSGraphAsyncOperator`
56
+
57
+ :param url: The url being executed on the Microsoft Graph API (templated).
58
+ :param response_type: The expected return type of the response as a string. Possible value are: `bytes`,
59
+ `str`, `int`, `float`, `bool` and `datetime` (default is None).
60
+ :param method: The HTTP method being used to do the REST call (default is GET).
61
+ :param conn_id: The HTTP Connection ID to run the operator against (templated).
62
+ :param key: The key that will be used to store `XCom's` ("return_value" is default).
63
+ :param timeout: The HTTP timeout being used by the `KiotaRequestAdapter` (default is None).
64
+ When no timeout is specified or set to None then there is no HTTP timeout on each request.
65
+ :param proxies: A dict defining the HTTP proxies to be used (default is None).
66
+ :param api_version: The API version of the Microsoft Graph API to be used (default is v1).
67
+ You can pass an enum named APIVersion which has 2 possible members v1 and beta,
68
+ or you can pass a string as `v1.0` or `beta`.
69
+ :param result_processor: Function to further process the response from MS Graph API
70
+ (default is lambda: context, response: response). When the response returned by the
71
+ `KiotaRequestAdapterHook` are bytes, then those will be base64 encoded into a string.
72
+ :param serializer: Class which handles response serialization (default is ResponseSerializer).
73
+ Bytes will be base64 encoded into a string, so it can be stored as an XCom.
74
+ """
75
+
76
+ template_fields: Sequence[str] = (
77
+ "url",
78
+ "response_type",
79
+ "path_parameters",
80
+ "url_template",
81
+ "query_parameters",
82
+ "headers",
83
+ "data",
84
+ "conn_id",
85
+ )
86
+
87
+ def __init__(
88
+ self,
89
+ *,
90
+ url: str,
91
+ response_type: ResponseType | None = None,
92
+ path_parameters: dict[str, Any] | None = None,
93
+ url_template: str | None = None,
94
+ method: str = "GET",
95
+ query_parameters: dict[str, QueryParams] | None = None,
96
+ headers: dict[str, str] | None = None,
97
+ data: dict[str, Any] | str | BytesIO | None = None,
98
+ conn_id: str = KiotaRequestAdapterHook.default_conn_name,
99
+ key: str = XCOM_RETURN_KEY,
100
+ timeout: float | None = None,
101
+ proxies: dict | None = None,
102
+ api_version: APIVersion | None = None,
103
+ pagination_function: Callable[[MSGraphAsyncOperator, dict], tuple[str, dict]] | None = None,
104
+ result_processor: Callable[[Context, Any], Any] = lambda context, result: result,
105
+ serializer: type[ResponseSerializer] = ResponseSerializer,
106
+ **kwargs: Any,
107
+ ):
108
+ super().__init__(**kwargs)
109
+ self.url = url
110
+ self.response_type = response_type
111
+ self.path_parameters = path_parameters
112
+ self.url_template = url_template
113
+ self.method = method
114
+ self.query_parameters = query_parameters
115
+ self.headers = headers
116
+ self.data = data
117
+ self.conn_id = conn_id
118
+ self.key = key
119
+ self.timeout = timeout
120
+ self.proxies = proxies
121
+ self.api_version = api_version
122
+ self.pagination_function = pagination_function or self.paginate
123
+ self.result_processor = result_processor
124
+ self.serializer: ResponseSerializer = serializer()
125
+ self.results: list[Any] | None = None
126
+
127
+ def execute(self, context: Context) -> None:
128
+ self.defer(
129
+ trigger=MSGraphTrigger(
130
+ url=self.url,
131
+ response_type=self.response_type,
132
+ path_parameters=self.path_parameters,
133
+ url_template=self.url_template,
134
+ method=self.method,
135
+ query_parameters=self.query_parameters,
136
+ headers=self.headers,
137
+ data=self.data,
138
+ conn_id=self.conn_id,
139
+ timeout=self.timeout,
140
+ proxies=self.proxies,
141
+ api_version=self.api_version,
142
+ serializer=type(self.serializer),
143
+ ),
144
+ method_name=self.execute_complete.__name__,
145
+ )
146
+
147
+ def execute_complete(
148
+ self,
149
+ context: Context,
150
+ event: dict[Any, Any] | None = None,
151
+ ) -> Any:
152
+ """
153
+ Execute callback when MSGraphTrigger finishes execution.
154
+
155
+ This method gets executed automatically when MSGraphTrigger completes its execution.
156
+ """
157
+ self.log.debug("context: %s", context)
158
+
159
+ if event:
160
+ self.log.debug("%s completed with %s: %s", self.task_id, event.get("status"), event)
161
+
162
+ if event.get("status") == "failure":
163
+ raise AirflowException(event.get("message"))
164
+
165
+ response = event.get("response")
166
+
167
+ self.log.debug("response: %s", response)
168
+
169
+ if response:
170
+ response = self.serializer.deserialize(response)
171
+
172
+ self.log.debug("deserialize response: %s", response)
173
+
174
+ result = self.result_processor(context, response)
175
+
176
+ self.log.debug("processed response: %s", result)
177
+
178
+ event["response"] = result
179
+
180
+ try:
181
+ self.trigger_next_link(response, method_name=self.pull_execute_complete.__name__)
182
+ except TaskDeferred as exception:
183
+ self.append_result(
184
+ result=result,
185
+ append_result_as_list_if_absent=True,
186
+ )
187
+ self.push_xcom(context=context, value=self.results)
188
+ raise exception
189
+
190
+ self.append_result(result=result)
191
+ self.log.debug("results: %s", self.results)
192
+
193
+ return self.results
194
+ return None
195
+
196
+ def append_result(
197
+ self,
198
+ result: Any,
199
+ append_result_as_list_if_absent: bool = False,
200
+ ):
201
+ self.log.debug("value: %s", result)
202
+
203
+ if isinstance(self.results, list):
204
+ if isinstance(result, list):
205
+ self.results.extend(result)
206
+ else:
207
+ self.results.append(result)
208
+ else:
209
+ if append_result_as_list_if_absent:
210
+ if isinstance(result, list):
211
+ self.results = result
212
+ else:
213
+ self.results = [result]
214
+ else:
215
+ self.results = result
216
+
217
+ def push_xcom(self, context: Context, value) -> None:
218
+ self.log.debug("do_xcom_push: %s", self.do_xcom_push)
219
+ if self.do_xcom_push:
220
+ self.log.info("Pushing XCom with key '%s': %s", self.key, value)
221
+ self.xcom_push(context=context, key=self.key, value=value)
222
+
223
+ def pull_execute_complete(self, context: Context, event: dict[Any, Any] | None = None) -> Any:
224
+ self.results = list(
225
+ self.xcom_pull(
226
+ context=context,
227
+ task_ids=self.task_id,
228
+ dag_id=self.dag_id,
229
+ key=self.key,
230
+ )
231
+ or []
232
+ )
233
+ self.log.info(
234
+ "Pulled XCom with task_id '%s' and dag_id '%s' and key '%s': %s",
235
+ self.task_id,
236
+ self.dag_id,
237
+ self.key,
238
+ self.results,
239
+ )
240
+ return self.execute_complete(context, event)
241
+
242
+ @staticmethod
243
+ def paginate(operator: MSGraphAsyncOperator, response: dict) -> tuple[Any, dict[str, Any] | None]:
244
+ odata_count = response.get("@odata.count")
245
+ if odata_count and operator.query_parameters:
246
+ query_parameters = deepcopy(operator.query_parameters)
247
+ top = query_parameters.get("$top")
248
+ odata_count = response.get("@odata.count")
249
+
250
+ if top and odata_count:
251
+ if len(response.get("value", [])) == top:
252
+ skip = (
253
+ sum(map(lambda result: len(result["value"]), operator.results)) + top
254
+ if operator.results
255
+ else top
256
+ )
257
+ query_parameters["$skip"] = skip
258
+ return operator.url, query_parameters
259
+ return response.get("@odata.nextLink"), operator.query_parameters
260
+
261
+ def trigger_next_link(self, response, method_name="execute_complete") -> None:
262
+ if isinstance(response, dict):
263
+ url, query_parameters = self.pagination_function(self, response)
264
+
265
+ self.log.debug("url: %s", url)
266
+ self.log.debug("query_parameters: %s", query_parameters)
267
+
268
+ if url:
269
+ self.defer(
270
+ trigger=MSGraphTrigger(
271
+ url=url,
272
+ query_parameters=query_parameters,
273
+ response_type=self.response_type,
274
+ conn_id=self.conn_id,
275
+ timeout=self.timeout,
276
+ proxies=self.proxies,
277
+ api_version=self.api_version,
278
+ serializer=type(self.serializer),
279
+ ),
280
+ method_name=method_name,
281
+ )
@@ -0,0 +1,177 @@
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
+ from __future__ import annotations
19
+
20
+ from typing import TYPE_CHECKING, Any, Callable, Sequence
21
+
22
+ from airflow.exceptions import AirflowException
23
+ from airflow.providers.microsoft.azure.hooks.msgraph import KiotaRequestAdapterHook
24
+ from airflow.providers.microsoft.azure.triggers.msgraph import MSGraphTrigger, ResponseSerializer
25
+ from airflow.sensors.base import BaseSensorOperator
26
+ from airflow.triggers.temporal import TimeDeltaTrigger
27
+
28
+ if TYPE_CHECKING:
29
+ from datetime import timedelta
30
+ from io import BytesIO
31
+
32
+ from kiota_abstractions.request_information import QueryParams
33
+ from kiota_http.httpx_request_adapter import ResponseType
34
+ from msgraph_core import APIVersion
35
+
36
+ from airflow.utils.context import Context
37
+
38
+
39
+ class MSGraphSensor(BaseSensorOperator):
40
+ """
41
+ A Microsoft Graph API sensor which allows you to poll an async REST call to the Microsoft Graph API.
42
+
43
+ :param url: The url being executed on the Microsoft Graph API (templated).
44
+ :param response_type: The expected return type of the response as a string. Possible value are: `bytes`,
45
+ `str`, `int`, `float`, `bool` and `datetime` (default is None).
46
+ :param method: The HTTP method being used to do the REST call (default is GET).
47
+ :param conn_id: The HTTP Connection ID to run the operator against (templated).
48
+ :param proxies: A dict defining the HTTP proxies to be used (default is None).
49
+ :param api_version: The API version of the Microsoft Graph API to be used (default is v1).
50
+ You can pass an enum named APIVersion which has 2 possible members v1 and beta,
51
+ or you can pass a string as `v1.0` or `beta`.
52
+ :param event_processor: Function which checks the response from MS Graph API (default is the
53
+ `default_event_processor` method) and returns a boolean. When the result is True, the sensor
54
+ will stop poking, otherwise it will continue until it's True or times out.
55
+ :param result_processor: Function to further process the response from MS Graph API
56
+ (default is lambda: context, response: response). When the response returned by the
57
+ `KiotaRequestAdapterHook` are bytes, then those will be base64 encoded into a string.
58
+ :param serializer: Class which handles response serialization (default is ResponseSerializer).
59
+ Bytes will be base64 encoded into a string, so it can be stored as an XCom.
60
+ """
61
+
62
+ template_fields: Sequence[str] = (
63
+ "url",
64
+ "response_type",
65
+ "path_parameters",
66
+ "url_template",
67
+ "query_parameters",
68
+ "headers",
69
+ "data",
70
+ "conn_id",
71
+ )
72
+
73
+ def __init__(
74
+ self,
75
+ url: str,
76
+ response_type: ResponseType | None = None,
77
+ path_parameters: dict[str, Any] | None = None,
78
+ url_template: str | None = None,
79
+ method: str = "GET",
80
+ query_parameters: dict[str, QueryParams] | None = None,
81
+ headers: dict[str, str] | None = None,
82
+ data: dict[str, Any] | str | BytesIO | None = None,
83
+ conn_id: str = KiotaRequestAdapterHook.default_conn_name,
84
+ proxies: dict | None = None,
85
+ api_version: APIVersion | None = None,
86
+ event_processor: Callable[[Context, Any], bool] = lambda context, e: e.get("status") == "Succeeded",
87
+ result_processor: Callable[[Context, Any], Any] = lambda context, result: result,
88
+ serializer: type[ResponseSerializer] = ResponseSerializer,
89
+ retry_delay: timedelta | float = 60,
90
+ **kwargs,
91
+ ):
92
+ super().__init__(retry_delay=retry_delay, **kwargs)
93
+ self.url = url
94
+ self.response_type = response_type
95
+ self.path_parameters = path_parameters
96
+ self.url_template = url_template
97
+ self.method = method
98
+ self.query_parameters = query_parameters
99
+ self.headers = headers
100
+ self.data = data
101
+ self.conn_id = conn_id
102
+ self.proxies = proxies
103
+ self.api_version = api_version
104
+ self.event_processor = event_processor
105
+ self.result_processor = result_processor
106
+ self.serializer = serializer()
107
+
108
+ def execute(self, context: Context):
109
+ self.defer(
110
+ trigger=MSGraphTrigger(
111
+ url=self.url,
112
+ response_type=self.response_type,
113
+ path_parameters=self.path_parameters,
114
+ url_template=self.url_template,
115
+ method=self.method,
116
+ query_parameters=self.query_parameters,
117
+ headers=self.headers,
118
+ data=self.data,
119
+ conn_id=self.conn_id,
120
+ timeout=self.timeout,
121
+ proxies=self.proxies,
122
+ api_version=self.api_version,
123
+ serializer=type(self.serializer),
124
+ ),
125
+ method_name=self.execute_complete.__name__,
126
+ )
127
+
128
+ def retry_execute(
129
+ self,
130
+ context: Context,
131
+ ) -> Any:
132
+ self.execute(context=context)
133
+
134
+ def execute_complete(
135
+ self,
136
+ context: Context,
137
+ event: dict[Any, Any] | None = None,
138
+ ) -> Any:
139
+ """
140
+ Execute callback when MSGraphSensor finishes execution.
141
+
142
+ This method gets executed automatically when MSGraphTrigger completes its execution.
143
+ """
144
+ self.log.debug("context: %s", context)
145
+
146
+ if event:
147
+ self.log.debug("%s completed with %s: %s", self.task_id, event.get("status"), event)
148
+
149
+ if event.get("status") == "failure":
150
+ raise AirflowException(event.get("message"))
151
+
152
+ response = event.get("response")
153
+
154
+ self.log.debug("response: %s", response)
155
+
156
+ if response:
157
+ response = self.serializer.deserialize(response)
158
+
159
+ self.log.debug("deserialize response: %s", response)
160
+
161
+ is_done = self.event_processor(context, response)
162
+
163
+ self.log.debug("is_done: %s", is_done)
164
+
165
+ if is_done:
166
+ result = self.result_processor(context, response)
167
+
168
+ self.log.debug("processed response: %s", result)
169
+
170
+ return result
171
+
172
+ self.defer(
173
+ trigger=TimeDeltaTrigger(self.retry_delay),
174
+ method_name=self.retry_execute.__name__,
175
+ )
176
+
177
+ return None
@@ -0,0 +1,231 @@
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
+ from __future__ import annotations
19
+
20
+ import json
21
+ import locale
22
+ from base64 import b64encode
23
+ from contextlib import suppress
24
+ from datetime import datetime
25
+ from json import JSONDecodeError
26
+ from typing import (
27
+ TYPE_CHECKING,
28
+ Any,
29
+ AsyncIterator,
30
+ Sequence,
31
+ )
32
+ from uuid import UUID
33
+
34
+ import pendulum
35
+
36
+ from airflow.providers.microsoft.azure.hooks.msgraph import KiotaRequestAdapterHook
37
+ from airflow.triggers.base import BaseTrigger, TriggerEvent
38
+ from airflow.utils.module_loading import import_string
39
+
40
+ if TYPE_CHECKING:
41
+ from io import BytesIO
42
+
43
+ from kiota_abstractions.request_adapter import RequestAdapter
44
+ from kiota_abstractions.request_information import QueryParams
45
+ from kiota_http.httpx_request_adapter import ResponseType
46
+ from msgraph_core import APIVersion
47
+
48
+
49
+ class ResponseSerializer:
50
+ """ResponseSerializer serializes the response as a string."""
51
+
52
+ def __init__(self, encoding: str | None = None):
53
+ self.encoding = encoding or locale.getpreferredencoding()
54
+
55
+ def serialize(self, response) -> str | None:
56
+ def convert(value) -> str | None:
57
+ if value is not None:
58
+ if isinstance(value, UUID):
59
+ return str(value)
60
+ if isinstance(value, datetime):
61
+ return value.isoformat()
62
+ if isinstance(value, pendulum.DateTime):
63
+ return value.to_iso8601_string() # Adjust the format as needed
64
+ raise TypeError(f"Object of type {type(value)} is not JSON serializable!")
65
+ return None
66
+
67
+ if response is not None:
68
+ if isinstance(response, bytes):
69
+ return b64encode(response).decode(self.encoding)
70
+ with suppress(JSONDecodeError):
71
+ return json.dumps(response, default=convert)
72
+ return response
73
+ return None
74
+
75
+ def deserialize(self, response) -> Any:
76
+ if isinstance(response, str):
77
+ with suppress(JSONDecodeError):
78
+ response = json.loads(response)
79
+ return response
80
+
81
+
82
+ class MSGraphTrigger(BaseTrigger):
83
+ """
84
+ A Microsoft Graph API trigger which allows you to execute an async REST call to the Microsoft Graph API.
85
+
86
+ :param url: The url being executed on the Microsoft Graph API (templated).
87
+ :param response_type: The expected return type of the response as a string. Possible value are: `bytes`,
88
+ `str`, `int`, `float`, `bool` and `datetime` (default is None).
89
+ :param method: The HTTP method being used to do the REST call (default is GET).
90
+ :param conn_id: The HTTP Connection ID to run the operator against (templated).
91
+ :param timeout: The HTTP timeout being used by the `KiotaRequestAdapter` (default is None).
92
+ When no timeout is specified or set to None then there is no HTTP timeout on each request.
93
+ :param proxies: A dict defining the HTTP proxies to be used (default is None).
94
+ :param api_version: The API version of the Microsoft Graph API to be used (default is v1).
95
+ You can pass an enum named APIVersion which has 2 possible members v1 and beta,
96
+ or you can pass a string as `v1.0` or `beta`.
97
+ :param serializer: Class which handles response serialization (default is ResponseSerializer).
98
+ Bytes will be base64 encoded into a string, so it can be stored as an XCom.
99
+ """
100
+
101
+ template_fields: Sequence[str] = (
102
+ "url",
103
+ "response_type",
104
+ "path_parameters",
105
+ "url_template",
106
+ "query_parameters",
107
+ "headers",
108
+ "data",
109
+ "conn_id",
110
+ )
111
+
112
+ def __init__(
113
+ self,
114
+ url: str,
115
+ response_type: ResponseType | None = None,
116
+ path_parameters: dict[str, Any] | None = None,
117
+ url_template: str | None = None,
118
+ method: str = "GET",
119
+ query_parameters: dict[str, QueryParams] | None = None,
120
+ headers: dict[str, str] | None = None,
121
+ data: dict[str, Any] | str | BytesIO | None = None,
122
+ conn_id: str = KiotaRequestAdapterHook.default_conn_name,
123
+ timeout: float | None = None,
124
+ proxies: dict | None = None,
125
+ api_version: APIVersion | None = None,
126
+ serializer: type[ResponseSerializer] = ResponseSerializer,
127
+ ):
128
+ super().__init__()
129
+ self.hook = KiotaRequestAdapterHook(
130
+ conn_id=conn_id,
131
+ timeout=timeout,
132
+ proxies=proxies,
133
+ api_version=api_version,
134
+ )
135
+ self.url = url
136
+ self.response_type = response_type
137
+ self.path_parameters = path_parameters
138
+ self.url_template = url_template
139
+ self.method = method
140
+ self.query_parameters = query_parameters
141
+ self.headers = headers
142
+ self.data = data
143
+ self.serializer: ResponseSerializer = self.resolve_type(serializer, default=ResponseSerializer)()
144
+
145
+ @classmethod
146
+ def resolve_type(cls, value: str | type, default) -> type:
147
+ if isinstance(value, str):
148
+ with suppress(ImportError):
149
+ return import_string(value)
150
+ return default
151
+ return value or default
152
+
153
+ def serialize(self) -> tuple[str, dict[str, Any]]:
154
+ """Serialize the HttpTrigger arguments and classpath."""
155
+ api_version = self.api_version.value if self.api_version else None
156
+ return (
157
+ f"{self.__class__.__module__}.{self.__class__.__name__}",
158
+ {
159
+ "conn_id": self.conn_id,
160
+ "timeout": self.timeout,
161
+ "proxies": self.proxies,
162
+ "api_version": api_version,
163
+ "serializer": f"{self.serializer.__class__.__module__}.{self.serializer.__class__.__name__}",
164
+ "url": self.url,
165
+ "path_parameters": self.path_parameters,
166
+ "url_template": self.url_template,
167
+ "method": self.method,
168
+ "query_parameters": self.query_parameters,
169
+ "headers": self.headers,
170
+ "data": self.data,
171
+ "response_type": self.response_type,
172
+ },
173
+ )
174
+
175
+ def get_conn(self) -> RequestAdapter:
176
+ return self.hook.get_conn()
177
+
178
+ @property
179
+ def conn_id(self) -> str:
180
+ return self.hook.conn_id
181
+
182
+ @property
183
+ def timeout(self) -> float | None:
184
+ return self.hook.timeout
185
+
186
+ @property
187
+ def proxies(self) -> dict | None:
188
+ return self.hook.proxies
189
+
190
+ @property
191
+ def api_version(self) -> APIVersion:
192
+ return self.hook.api_version
193
+
194
+ async def run(self) -> AsyncIterator[TriggerEvent]:
195
+ """Make a series of asynchronous HTTP calls via a KiotaRequestAdapterHook."""
196
+ try:
197
+ response = await self.hook.run(
198
+ url=self.url,
199
+ response_type=self.response_type,
200
+ path_parameters=self.path_parameters,
201
+ method=self.method,
202
+ query_parameters=self.query_parameters,
203
+ headers=self.headers,
204
+ data=self.data,
205
+ )
206
+
207
+ self.log.debug("response: %s", response)
208
+
209
+ if response:
210
+ response_type = type(response)
211
+
212
+ self.log.debug("response type: %s", response_type)
213
+
214
+ yield TriggerEvent(
215
+ {
216
+ "status": "success",
217
+ "type": f"{response_type.__module__}.{response_type.__name__}",
218
+ "response": self.serializer.serialize(response),
219
+ }
220
+ )
221
+ else:
222
+ yield TriggerEvent(
223
+ {
224
+ "status": "success",
225
+ "type": None,
226
+ "response": None,
227
+ }
228
+ )
229
+ except Exception as e:
230
+ self.log.exception("An error occurred: %s", e)
231
+ yield TriggerEvent({"status": "failure", "message": str(e)})