Skip to content

Commit cae8f33

Browse files
committed
httpx async_send_each prototype
1 parent 387f11a commit cae8f33

File tree

6 files changed

+566
-20
lines changed

6 files changed

+566
-20
lines changed

firebase_admin/_utils.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
import json
1818
from platform import python_version
19+
from typing import Callable, Optional, Union
1920

2021
import google.auth
2122
import requests
23+
import httpx
2224

2325
import firebase_admin
2426
from firebase_admin import exceptions
@@ -128,6 +130,37 @@ def handle_platform_error_from_requests(error, handle_func=None):
128130

129131
return exc if exc else _handle_func_requests(error, message, error_dict)
130132

133+
def handle_platform_error_from_httpx(
134+
error: httpx.HTTPError,
135+
handle_func: Optional[Callable[...,Optional[exceptions.FirebaseError]]] = None
136+
) -> exceptions.FirebaseError:
137+
"""Constructs a ``FirebaseError`` from the given httpx error.
138+
139+
This can be used to handle errors returned by Google Cloud Platform (GCP) APIs.
140+
141+
Args:
142+
error: An error raised by the httpx module while making an HTTP call to a GCP API.
143+
handle_func: A function that can be used to handle platform errors in a custom way. When
144+
specified, this function will be called with three arguments. It has the same
145+
signature as ```_handle_func_httpx``, but may return ``None``.
146+
147+
Returns:
148+
FirebaseError: A ``FirebaseError`` that can be raised to the user code.
149+
"""
150+
151+
if isinstance(error, httpx.HTTPStatusError):
152+
response = error.response
153+
content = response.content.decode()
154+
status_code = response.status_code
155+
error_dict, message = _parse_platform_error(content, status_code)
156+
exc = None
157+
if handle_func:
158+
exc = handle_func(error, message, error_dict)
159+
160+
return exc if exc else _handle_func_httpx(error, message, error_dict)
161+
else:
162+
return handle_httpx_error(error)
163+
131164

132165
def handle_operation_error(error):
133166
"""Constructs a ``FirebaseError`` from the given operation error.
@@ -204,6 +237,60 @@ def handle_requests_error(error, message=None, code=None):
204237
err_type = _error_code_to_exception_type(code)
205238
return err_type(message=message, cause=error, http_response=error.response)
206239

240+
def _handle_func_httpx(error: httpx.HTTPError, message, error_dict) -> exceptions.FirebaseError:
241+
"""Constructs a ``FirebaseError`` from the given GCP error.
242+
243+
Args:
244+
error: An error raised by the httpx module while making an HTTP call.
245+
message: A message to be included in the resulting ``FirebaseError``.
246+
error_dict: Parsed GCP error response.
247+
248+
Returns:
249+
FirebaseError: A ``FirebaseError`` that can be raised to the user code or None.
250+
"""
251+
code = error_dict.get('status')
252+
return handle_httpx_error(error, message, code)
253+
254+
255+
def handle_httpx_error(error: httpx.HTTPError, message=None, code=None) -> exceptions.FirebaseError:
256+
"""Constructs a ``FirebaseError`` from the given httpx error.
257+
258+
This method is agnostic of the remote service that produced the error, whether it is a GCP
259+
service or otherwise. Therefore, this method does not attempt to parse the error response in
260+
any way.
261+
262+
Args:
263+
error: An error raised by the httpx module while making an HTTP call.
264+
message: A message to be included in the resulting ``FirebaseError`` (optional). If not
265+
specified the string representation of the ``error`` argument is used as the message.
266+
code: A GCP error code that will be used to determine the resulting error type (optional).
267+
If not specified the HTTP status code on the error response is used to determine a
268+
suitable error code.
269+
270+
Returns:
271+
FirebaseError: A ``FirebaseError`` that can be raised to the user code.
272+
"""
273+
if isinstance(error, httpx.TimeoutException):
274+
return exceptions.DeadlineExceededError(
275+
message='Timed out while making an API call: {0}'.format(error),
276+
cause=error)
277+
if isinstance(error, httpx.ConnectError):
278+
return exceptions.UnavailableError(
279+
message='Failed to establish a connection: {0}'.format(error),
280+
cause=error)
281+
if isinstance(error, httpx.HTTPStatusError):
282+
print("printing status error", error)
283+
if not code:
284+
code = _http_status_to_error_code(error.response.status_code)
285+
if not message:
286+
message = str(error)
287+
288+
err_type = _error_code_to_exception_type(code)
289+
return err_type(message=message, cause=error, http_response=error.response)
290+
291+
return exceptions.UnknownError(
292+
message='Unknown error while making a remote service call: {0}'.format(error),
293+
cause=error)
207294

208295
def _http_status_to_error_code(status):
209296
"""Maps an HTTP status to a platform error code."""

0 commit comments

Comments
 (0)