def test_doesnt_load_non_iterable() -> None: non_iterable = '{"a": 1}' with pytest.raises( TypeError, match= r"{'a': 1} is a dict, expected a top-level list from JSON source", ): autotui.namedtuple_sequence_loads(non_iterable, X)
def test_basic_sequence_dumps_loads() -> None: x = [X(a=1), X(a=5)] xlist_str: str = autotui.namedtuple_sequence_dumps(x, indent=None) assert xlist_str == """[{"a": 1}, {"a": 5}]""" back_to_x: List[X] = autotui.namedtuple_sequence_loads(xlist_str, to=X) assert type(back_to_x) == list assert back_to_x[0] == X(a=1) assert back_to_x[1] == X(a=5)
def test_recursive() -> None: obj = Wrapper(y=5, z=Internal(x=10)) [dumped_obj] = json.loads(autotui.namedtuple_sequence_dumps([obj])) assert dumped_obj["y"] == 5 assert type(dumped_obj["z"]) == dict assert dumped_obj["z"]["x"] == 10 # dump to JSON and re-load [reloaded] = autotui.namedtuple_sequence_loads(json.dumps([dumped_obj]), to=Wrapper) assert obj == reloaded
def save_from(nt: Type[NamedTuple], use_input: TextIO, partial: bool = False) -> None: json_text: str = use_input.read() p = datafile(namedtuple_func_name(nt)) items: List[NamedTuple] = load_from(nt, p, allow_empty=True) new_items: List[NamedTuple] = [] if partial: # load the list as json blobs os.environ["AUTOTUI_DISABLE_WARNINGS"] = "1" # ignore null warnings blobs: List[Dict[str, Any]] = [] for b in namedtuple_sequence_loads(json_text, nt): blobs.append( {k: v for k, v in b._asdict().items() if v is not None}) del os.environ["AUTOTUI_DISABLE_WARNINGS"] for bd in blobs: new_nt = prompt_namedtuple(nt, attr_use_values=bd) new_items.append(new_nt) else: new_items.extend(namedtuple_sequence_loads(json_text, nt)) items.extend(new_items) dump_to(items, p)
def test_custom_handles_serializers() -> None: t = Temperature("20C") assert t.celsius == 20.0 # just test creating the namedtuple prompt handler = autotui.AutoHandler(func=Temperature, catch_errors=[TypeError, ValueError]) funcs = autotui.namedtuple_prompt_funcs( Reading, type_validators={Temperature: handler}) assert len(funcs.keys()) == 2 f = tempfile.NamedTemporaryFile(delete=False) type_serializers = {Temperature: serialize_temp} attr_deserializers = {"temp": deserialize_temp} d1 = datetime.now() d2 = datetime.now() readings: List[Reading] = [ Reading(when=d1, temp=Temperature("20C")), Reading(when=d2, temp=Temperature("19C")), ] with open(f.name, "w") as fp: autotui.namedtuple_sequence_dump(readings, fp, type_serializers=type_serializers) # loads first, check warning when no deserializer provided with open(f.name) as fp: str_contents = fp.read() with warnings.catch_warnings(record=True) as record: readings_back = autotui.namedtuple_sequence_loads(str_contents, to=Reading) assert len(record) >= 1 assert "No known way to deserialize" in str(record[0].message) assert len(readings_back) == 2 assert readings_back[0].temp == 20.0 # then load properly with open(f.name) as fp: rbr = autotui.namedtuple_sequence_load( fp, to=Reading, attr_deserializers=attr_deserializers) assert len(rbr) == 2 assert int(rbr[0].when.timestamp()) == int(d1.timestamp()) assert rbr[0].temp == Temperature("20C") # delete file os.unlink(f.name)
# the type of the value thats loaded from JSON # dump to JSON a_str: str = namedtuple_sequence_dumps( [a], type_serializers={ timedelta: to_seconds, }, indent=None, ) # load from JSON a_load = namedtuple_sequence_loads( a_str, to=Action, type_deserializers={ timedelta: from_seconds, }, )[0] # can also specify with attributes instead of types a_load2 = namedtuple_sequence_loads( a_str, to=Action, attr_deserializers={ "duration": from_seconds, }, )[0] print(a) print(a_str)
def complex_loads(): namedtuple_sequence_loads( complex_json, Complex, type_deserializers=complex_type_deserializer )
def typical_loads(): namedtuple_sequence_loads(typical_json, Typical)
import autotui from typing import NamedTuple from datetime import datetime # something to persist to a file class Water(NamedTuple): at: datetime glass_count: float w = autotui.prompt_namedtuple(Water) print(w) s = autotui.namedtuple_sequence_dumps([w], indent=None) print(s) b = autotui.namedtuple_sequence_loads(s, to=Water) print(b[0])