jsonlib.py (2637B)
1 import re 2 import json 3 from typing import Any, AnyStr, Callable, Dict, IO, Text 4 5 6 __all__ = ["load", "dump_local", "dump_local", "dump_dist", "dumps_dist"] 7 8 9 try: 10 import ujson 11 except ImportError: 12 has_ujson = False 13 else: 14 has_ujson = True 15 16 # 17 # load 18 # 19 20 if has_ujson: 21 load: Callable[[IO[AnyStr]], Any] = ujson.load 22 23 else: 24 load = json.load 25 26 27 # 28 # loads 29 # 30 31 if has_ujson: 32 loads: Callable[[AnyStr], Any] = ujson.loads 33 34 else: 35 loads = json.loads 36 37 38 # 39 # dump/dumps_local options for some libraries 40 # 41 _ujson_dump_local_kwargs: Dict[str, Any] = { 42 'ensure_ascii': False, 43 'escape_forward_slashes': False, 44 'indent': 1, 45 'reject_bytes': True, 46 } 47 48 49 _json_dump_local_kwargs: Dict[str, Any] = { 50 'ensure_ascii': False, 51 'indent': 1, 52 'separators': (',', ': '), 53 } 54 55 56 # 57 # dump_local (for local, non-distributed usage of JSON) 58 # 59 60 if has_ujson: 61 def dump_local(obj: Any, fp: IO[str]) -> None: 62 return ujson.dump(obj, fp, **_ujson_dump_local_kwargs) 63 64 else: 65 def dump_local(obj: Any, fp: IO[str]) -> None: 66 return json.dump(obj, fp, **_json_dump_local_kwargs) 67 68 69 # 70 # dumps_local (for local, non-distributed usage of JSON) 71 # 72 73 if has_ujson: 74 def dumps_local(obj: Any) -> Text: 75 return ujson.dumps(obj, **_ujson_dump_local_kwargs) 76 77 else: 78 def dumps_local(obj: Any) -> Text: 79 return json.dumps(obj, **_json_dump_local_kwargs) 80 81 82 # 83 # dump/dumps_dist (for distributed usage of JSON where files should safely roundtrip) 84 # 85 86 _ujson_dump_dist_kwargs: Dict[str, Any] = { 87 'sort_keys': True, 88 'indent': 1, 89 'reject_bytes': True, 90 'escape_forward_slashes': False, 91 } 92 93 94 _json_dump_dist_kwargs: Dict[str, Any] = { 95 'sort_keys': True, 96 'indent': 1, 97 'separators': (',', ': '), 98 } 99 100 101 if has_ujson: 102 if ujson.dumps([], indent=1) == "[]": 103 # optimistically see if https://github.com/ultrajson/ultrajson/issues/429 is fixed 104 def _ujson_fixup(s: str) -> str: 105 return s 106 else: 107 _ujson_fixup_re = re.compile(r"([\[{])[\n\x20]+([}\]])") 108 109 def _ujson_fixup(s: str) -> str: 110 return _ujson_fixup_re.sub( 111 lambda m: m.group(1) + m.group(2), 112 s 113 ) 114 115 def dump_dist(obj: Any, fp: IO[str]) -> None: 116 fp.write(_ujson_fixup(ujson.dumps(obj, **_ujson_dump_dist_kwargs))) 117 118 def dumps_dist(obj: Any) -> Text: 119 return _ujson_fixup(ujson.dumps(obj, **_ujson_dump_dist_kwargs)) 120 else: 121 def dump_dist(obj: Any, fp: IO[str]) -> None: 122 json.dump(obj, fp, **_json_dump_dist_kwargs) 123 124 def dumps_dist(obj: Any) -> Text: 125 return json.dumps(obj, **_json_dump_dist_kwargs)