|
6 | 6 | import copy |
7 | 7 | import datetime |
8 | 8 | import functools |
| 9 | +import io |
9 | 10 | import logging |
10 | 11 | import os |
11 | | -from typing import Dict, List, Union |
| 12 | +from typing import Any, Dict, List, Union |
12 | 13 |
|
13 | 14 | import requests |
14 | 15 | import taskcluster_urls as liburls |
@@ -69,13 +70,32 @@ def get_taskcluster_client(service: str): |
69 | 70 | return getattr(taskcluster, service[0].upper() + service[1:])(options) |
70 | 71 |
|
71 | 72 |
|
72 | | -def _handle_artifact(path, response): |
| 73 | +def _handle_artifact( |
| 74 | + path: str, response: Union[requests.Response, Dict[str, Any]] |
| 75 | +) -> Any: |
| 76 | + if isinstance(response, dict): |
| 77 | + # When taskcluster client returns non-JSON responses, it wraps them in {"response": <Response>} |
| 78 | + if "response" in response and isinstance( |
| 79 | + response["response"], requests.Response |
| 80 | + ): |
| 81 | + response = response["response"] |
| 82 | + else: |
| 83 | + # If we already a dict (parsed JSON), return it directly. |
| 84 | + return response |
| 85 | + |
| 86 | + # We have a response object, load the content based on the path extension. |
73 | 87 | if path.endswith(".json"): |
74 | 88 | return response.json() |
75 | 89 |
|
76 | 90 | if path.endswith(".yml"): |
77 | 91 | return yaml.load_stream(response.content) |
78 | 92 |
|
| 93 | + # Otherwise return raw response content |
| 94 | + if hasattr(response.raw, "tell") and response.raw.tell() > 0: |
| 95 | + # Stream was already read, create a new one from content. This can |
| 96 | + # happen when mocking with responses. |
| 97 | + return io.BytesIO(response.content) |
| 98 | + |
79 | 99 | response.raw.read = functools.partial(response.raw.read, decode_content=True) |
80 | 100 | return response.raw |
81 | 101 |
|
|
0 commit comments