|
16 | 16 | import base64
|
17 | 17 | import errno
|
18 | 18 | import functools
|
| 19 | +import importlib |
19 | 20 | import os
|
20 | 21 | import platform
|
21 | 22 | import queue
|
|
27 | 28 | from datetime import datetime
|
28 | 29 | from operator import itemgetter, methodcaller
|
29 | 30 | from statistics import mean
|
30 |
| -from typing import Dict, List, Union |
| 31 | +from typing import Any, Dict, List, Union |
31 | 32 | from urllib.error import HTTPError, URLError
|
32 | 33 | from urllib.parse import urlparse
|
33 | 34 | from urllib.request import Request, urlopen
|
|
36 | 37 |
|
37 | 38 | from defusedxml.xmlrpc import monkey_patch
|
38 | 39 |
|
39 |
| -# Optionally use orjson if available |
| 40 | +# Correct issue #1025 by monkey path the xmlrpc lib |
| 41 | +monkey_patch() |
| 42 | + |
| 43 | +# Prefer faster libs for JSON (de)serialization |
| 44 | +# Preference Order: orjson > ujson > json (builtin) |
40 | 45 | try:
|
41 | 46 | import orjson as json
|
| 47 | + |
| 48 | + json.dumps = functools.partial(json.dumps, option=json.OPT_NON_STR_KEYS) |
42 | 49 | except ImportError:
|
43 |
| - import json |
| 50 | + # Need to log info but importing logger will cause cyclic imports |
| 51 | + pass |
44 | 52 |
|
45 |
| -# Correct issue #1025 by monkey path the xmlrpc lib |
46 |
| -monkey_patch() |
| 53 | +if 'json' not in globals(): |
| 54 | + try: |
| 55 | + # Note: ujson is not officially supported |
| 56 | + # Available as a fallback to allow orjson's unsupported platforms to use a faster serialization lib |
| 57 | + import ujson as json |
| 58 | + except ImportError: |
| 59 | + import json |
| 60 | + |
| 61 | + # To allow ujson & json dumps to serialize datetime |
| 62 | + def _json_default(v: Any) -> Any: |
| 63 | + if isinstance(v, datetime): |
| 64 | + return v.isoformat() |
| 65 | + return v |
| 66 | + |
| 67 | + json.dumps = functools.partial(json.dumps, default=_json_default) |
47 | 68 |
|
48 | 69 | ##############
|
49 | 70 | # GLOBALS VARS
|
@@ -166,7 +187,7 @@ def subsample(data, sampling):
|
166 | 187 | return [mean(data[s * sampling_length : (s + 1) * sampling_length]) for s in range(0, sampling)]
|
167 | 188 |
|
168 | 189 |
|
169 |
| -def time_serie_subsample(data, sampling): |
| 190 | +def time_series_subsample(data, sampling): |
170 | 191 | """Compute a simple mean subsampling.
|
171 | 192 |
|
172 | 193 | Data should be a list of set (time, value)
|
@@ -303,20 +324,22 @@ def urlopen_auth(url, username, password):
|
303 | 324 | return urlopen(
|
304 | 325 | Request(
|
305 | 326 | url,
|
306 |
| - headers={'Authorization': 'Basic ' + base64.b64encode((f'{username}:{password}').encode()).decode()}, |
| 327 | + headers={'Authorization': 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode()}, |
307 | 328 | )
|
308 | 329 | )
|
309 | 330 |
|
310 | 331 |
|
311 |
| -def json_dumps(data) -> str: |
| 332 | +def json_dumps(data) -> bytes: |
312 | 333 | """Return the object data in a JSON format.
|
313 | 334 |
|
314 | 335 | Manage the issue #815 for Windows OS with UnicodeDecodeError catching.
|
315 | 336 | """
|
316 | 337 | try:
|
317 |
| - return json.dumps(data) |
| 338 | + res = json.dumps(data) |
318 | 339 | except UnicodeDecodeError:
|
319 |
| - return json.dumps(data, ensure_ascii=False) |
| 340 | + res = json.dumps(data, ensure_ascii=False) |
| 341 | + # ujson & json libs return strings, but our contract expects bytes |
| 342 | + return b(res) |
320 | 343 |
|
321 | 344 |
|
322 | 345 | def json_loads(data: Union[str, bytes, bytearray]) -> Union[Dict, List]:
|
|
0 commit comments