Coverage for src/mlopus/utils/yaml.py: 80%
30 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-07-13 14:49 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-07-13 14:49 +0000
1import functools
2from dataclasses import is_dataclass, asdict
3from datetime import datetime
4from pathlib import Path
5from typing import Any
7import yaml
9from mlopus.utils import typing_utils, import_utils, pydantic, time_utils
11loads = functools.partial(yaml.load, Loader=yaml.Loader)
14class Dumper(yaml.Dumper):
15 """Dumper that handles multiline strings, sets, types, dataclasses, datetime, Path and pydantic objects."""
17 def represent_data(self, data):
18 """Dumper that handles multiline strings, types, dataclasses, datetime and pydantic objects."""
19 if isinstance(data, str) and "\n" in data:
20 data = "\n".join([line.rstrip() for line in data.split("\n")])
21 return self.represent_scalar("tag:yaml.org,2002:str", data, style="|")
23 elif isinstance(data, BaseException):
24 data = {"type": import_utils.fq_name(type(data)), "message": str(data)}
26 elif type_ := typing_utils.as_type(data):
27 data = import_utils.fq_name(type_)
29 elif p_obj := pydantic.as_model_obj(data):
30 data = p_obj.dict()
32 elif is_dataclass(type(data)):
33 data = asdict(data)
35 elif isinstance(data, datetime):
36 data = time_utils.safe_repr(data)
38 elif isinstance(data, set):
39 data = list(data)
41 elif isinstance(data, Path):
42 data = str(data)
44 return super().represent_data(data)
47def dumps(data: Any) -> str:
48 """Dumper that handles multiline strings, types, dataclasses, datetime and pydantic objects."""
49 return yaml.dump(data, sort_keys=False, Dumper=Dumper)