yaml.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import datetime # pylint: disable=unused-import; doctest
  2. import pathlib
  3. import typing
  4. import yaml
  5. from yamily import Person
  6. class _Loader(yaml.SafeLoader):
  7. # pylint: disable=too-many-ancestors
  8. def __init__(self, stream):
  9. super().__init__(stream)
  10. self.add_constructor("!person", self._construct_person)
  11. @staticmethod
  12. def _construct_person(loader: "_Loader", node: yaml.nodes.MappingNode) -> Person:
  13. (person_attrs,) = loader.construct_yaml_map(node)
  14. person = Person(person_attrs["identifier"])
  15. if "name" in person_attrs:
  16. person.name = person_attrs["name"]
  17. if "birth_date" in person_attrs:
  18. person.birth_date = person_attrs["birth_date"]
  19. if "mother" in person_attrs:
  20. person.mother = Person(person_attrs["mother"])
  21. if "father" in person_attrs:
  22. person.father = Person(person_attrs["father"])
  23. return person
  24. class Dumper(yaml.SafeDumper):
  25. """
  26. >>> p = Person('alice')
  27. >>> p.name = 'Alice'
  28. >>> p.birth_date = datetime.date(1976, 2, 1)
  29. >>> print(yaml.dump(p, Dumper=Dumper))
  30. !person
  31. birth_date: 1976-02-01
  32. identifier: alice
  33. name: Alice
  34. <BLANKLINE>
  35. >>> p = Person('bob')
  36. >>> p.mother = Person('bob-mum')
  37. >>> p.father = Person('bob-father')
  38. >>> print(yaml.dump(p, Dumper=Dumper))
  39. !person
  40. father: !person
  41. identifier: bob-father
  42. identifier: bob
  43. mother: !person
  44. identifier: bob-mum
  45. <BLANKLINE>
  46. """
  47. # pylint: disable=too-many-ancestors
  48. def __init__(self, stream, **kwargs):
  49. super().__init__(stream, **kwargs)
  50. self.add_representer(Person, self._represent_person)
  51. @staticmethod
  52. def _represent_person(dumper: "_Dumper", person: Person) -> yaml.nodes.MappingNode:
  53. person_attrs = {"identifier": person.identifier}
  54. if person.name is not None:
  55. person_attrs["name"] = person.name
  56. if person.birth_date is not None:
  57. person_attrs["birth_date"] = person.birth_date
  58. if person.mother is not None:
  59. person_attrs["mother"] = person.mother
  60. if person.father is not None:
  61. person_attrs["father"] = person.father
  62. return dumper.represent_mapping("!person", person_attrs)
  63. def read(yaml_path: typing.Union[str, pathlib.Path]) -> Person:
  64. """
  65. >>> read('persons/erika-mustermann.yml')
  66. Person(erika-mustermann, Erika Mustermann, *1957-08-12)
  67. >>> maxl = read('persons/max-mustermann.yml')
  68. >>> maxl
  69. Person(max-mustermann, Max Mustermann, *1976-02-01)
  70. >>> maxl.mother
  71. Person(erika-mustermann)
  72. >>> maxl.father
  73. Person(thomas-mustermann)
  74. """
  75. if isinstance(yaml_path, str):
  76. return read(pathlib.Path(yaml_path))
  77. with yaml_path.open("r") as yaml_file:
  78. return yaml.load(yaml_file, Loader=_Loader)