22
22
from __future__ import unicode_literals
23
23
24
24
import http .client
25
- from typing import Dict
25
+ from typing import Optional , Dict
26
26
from typing import Union
27
27
import warnings
28
28
@@ -476,22 +476,37 @@ def from_http_status(status_code, message, **kwargs):
476
476
return error
477
477
478
478
479
- def from_http_response (response ):
480
- """Create a :class:`GoogleAPICallError` from a :class:`requests.Response`.
479
+ def _format_rest_error_message (error , method , url ):
480
+ method = method .upper () if method else None
481
+ message = "{method} {url}: {error}" .format (
482
+ method = method ,
483
+ url = url ,
484
+ error = error ,
485
+ )
486
+ return message
487
+
488
+
489
+ # NOTE: We're moving away from `from_http_status` because it expects an aiohttp response compared
490
+ # to `format_http_response_error` which expects a more abstract response from google.auth and is
491
+ # compatible with both sync and async response types.
492
+ # TODO(https://github.com/googleapis/python-api-core/issues/691): Add type hint for response.
493
+ def format_http_response_error (
494
+ response , method : str , url : str , payload : Optional [Dict ] = None
495
+ ):
496
+ """Create a :class:`GoogleAPICallError` from a google auth rest response.
481
497
482
498
Args:
483
- response (requests.Response): The HTTP response.
499
+ response Union[google.auth.transport.Response, google.auth.aio.transport.Response]: The HTTP response.
500
+ method Optional(str): The HTTP request method.
501
+ url Optional(str): The HTTP request url.
502
+ payload Optional(dict): The HTTP response payload. If not passed in, it is read from response for a response type of google.auth.transport.Response.
484
503
485
504
Returns:
486
505
GoogleAPICallError: An instance of the appropriate subclass of
487
506
:class:`GoogleAPICallError`, with the message and errors populated
488
507
from the response.
489
508
"""
490
- try :
491
- payload = response .json ()
492
- except ValueError :
493
- payload = {"error" : {"message" : response .text or "unknown error" }}
494
-
509
+ payload = {} if not payload else payload
495
510
error_message = payload .get ("error" , {}).get ("message" , "unknown error" )
496
511
errors = payload .get ("error" , {}).get ("errors" , ())
497
512
# In JSON, details are already formatted in developer-friendly way.
@@ -504,12 +519,7 @@ def from_http_response(response):
504
519
)
505
520
)
506
521
error_info = error_info [0 ] if error_info else None
507
-
508
- message = "{method} {url}: {error}" .format (
509
- method = response .request .method ,
510
- url = response .request .url ,
511
- error = error_message ,
512
- )
522
+ message = _format_rest_error_message (error_message , method , url )
513
523
514
524
exception = from_http_status (
515
525
response .status_code ,
@@ -522,6 +532,26 @@ def from_http_response(response):
522
532
return exception
523
533
524
534
535
+ def from_http_response (response ):
536
+ """Create a :class:`GoogleAPICallError` from a :class:`requests.Response`.
537
+
538
+ Args:
539
+ response (requests.Response): The HTTP response.
540
+
541
+ Returns:
542
+ GoogleAPICallError: An instance of the appropriate subclass of
543
+ :class:`GoogleAPICallError`, with the message and errors populated
544
+ from the response.
545
+ """
546
+ try :
547
+ payload = response .json ()
548
+ except ValueError :
549
+ payload = {"error" : {"message" : response .text or "unknown error" }}
550
+ return format_http_response_error (
551
+ response , response .request .method , response .request .url , payload
552
+ )
553
+
554
+
525
555
def exception_class_for_grpc_status (status_code ):
526
556
"""Return the exception class for a specific :class:`grpc.StatusCode`.
527
557
0 commit comments