yaml.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. """
  9. >>> alice_yaml = '''
  10. ... !person
  11. ... identifier: alice
  12. ... name: Alice Test
  13. ... birth_date: 1976-02-01
  14. ... mother: mum
  15. ... father: dad
  16. ... '''
  17. >>> alice = yaml.load(alice_yaml, Loader=_Loader)
  18. >>> alice
  19. Person(alice, Alice Test, *1976-02-01)
  20. >>> alice.mother
  21. Person(mum)
  22. >>> alice.father
  23. Person(dad)
  24. >>> alice_yaml = '''
  25. ... !person
  26. ... identifier: alice
  27. ... name: Alice Test
  28. ... birth_date: 1976-02-01
  29. ... mother: !person
  30. ... identifier: mum
  31. ... father: !person
  32. ... identifier: dad
  33. ... name: Dad Test
  34. ... '''
  35. >>> alice = yaml.load(alice_yaml, Loader=_Loader)
  36. >>> alice
  37. Person(alice, Alice Test, *1976-02-01)
  38. >>> alice.mother
  39. Person(mum)
  40. >>> alice.father
  41. Person(dad, Dad Test)
  42. """
  43. def __init__(self, stream):
  44. super().__init__(stream)
  45. self.add_constructor("!person", self._construct_person)
  46. @staticmethod
  47. def _construct_person(loader: "_Loader", node: yaml.nodes.MappingNode) -> Person:
  48. (person_attrs,) = loader.construct_yaml_map(node)
  49. person = Person(person_attrs["identifier"])
  50. if "name" in person_attrs:
  51. person.name = person_attrs["name"]
  52. if "birth_date" in person_attrs:
  53. person.birth_date = person_attrs["birth_date"]
  54. if "mother" in person_attrs:
  55. if isinstance(person_attrs["mother"], Person):
  56. person.mother = person_attrs["mother"]
  57. else:
  58. person.mother = Person(person_attrs["mother"])
  59. if "father" in person_attrs:
  60. if isinstance(person_attrs["father"], Person):
  61. person.father = person_attrs["father"]
  62. else:
  63. person.father = Person(person_attrs["father"])
  64. return person
  65. class Dumper(yaml.SafeDumper):
  66. """
  67. >>> p = Person('alice')
  68. >>> p.name = 'Alice'
  69. >>> p.birth_date = datetime.date(1976, 2, 1)
  70. >>> print(yaml.dump(p, Dumper=Dumper))
  71. !person
  72. birth_date: 1976-02-01
  73. identifier: alice
  74. name: Alice
  75. <BLANKLINE>
  76. >>> p = Person('bob')
  77. >>> p.mother = Person('bob-mum')
  78. >>> p.father = Person('bob-father')
  79. >>> print(yaml.dump(p, Dumper=Dumper))
  80. !person
  81. father: !person
  82. identifier: bob-father
  83. identifier: bob
  84. mother: !person
  85. identifier: bob-mum
  86. <BLANKLINE>
  87. """
  88. # pylint: disable=too-many-ancestors
  89. def __init__(self, stream, **kwargs):
  90. super().__init__(stream, **kwargs)
  91. self.add_representer(Person, self._represent_person)
  92. @staticmethod
  93. def _represent_person(dumper: "_Dumper", person: Person) -> yaml.nodes.MappingNode:
  94. person_attrs = {"identifier": person.identifier}
  95. if person.name is not None:
  96. person_attrs["name"] = person.name
  97. if person.birth_date is not None:
  98. person_attrs["birth_date"] = person.birth_date
  99. if person.mother is not None:
  100. person_attrs["mother"] = person.mother
  101. if person.father is not None:
  102. person_attrs["father"] = person.father
  103. return dumper.represent_mapping("!person", person_attrs)
  104. def read(yaml_path: typing.Union[str, pathlib.Path]) -> Person:
  105. """
  106. >>> read('persons/erika-mustermann.yml')
  107. Person(erika-mustermann, Erika Mustermann, *1957-08-12)
  108. >>> maxl = read('persons/max-mustermann.yml')
  109. >>> maxl
  110. Person(max-mustermann, Max Mustermann, *1976-02-01)
  111. >>> maxl.mother
  112. Person(erika-mustermann)
  113. >>> maxl.father
  114. Person(thomas-mustermann)
  115. """
  116. if isinstance(yaml_path, str):
  117. return read(pathlib.Path(yaml_path))
  118. with yaml_path.open("r") as yaml_file:
  119. return yaml.load(yaml_file, Loader=_Loader)