Coverage for birdplan/yaml/pyaml.py: 100%
34 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
1#
2# SPDX-License-Identifier: GPL-3.0-or-later
3#
4# Copyright (C) 2019-2024, AllWorldIT.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <https://www.gnu.org/licenses/>.
19"""BirdPlan YAML handling."""
21import io
22import pathlib
23from typing import Any, Optional, Tuple, Union
25import yaml as pyaml
26from yaml import YAMLError
28from .base import YAMLBase
30__all__ = ["YAML", "YAMLError"]
33class BirdPlanSafeLoader(pyaml.SafeLoader): # pylint: disable=too-many-ancestors
34 """Safe YAML loader wtih some specific datatypes."""
36 def construct_python_tuple(self, node: Any) -> Tuple[Any, ...]:
37 """Tuple constructor."""
38 return tuple(self.construct_sequence(node))
41class BirdPlanSafeDumper(pyaml.SafeDumper):
42 """Safe YAML dumper with some specific datatypes."""
44 def represent_tuple(self, data: Tuple[Any, ...]) -> pyaml.nodes.SequenceNode:
45 """Tuple representer."""
46 return self.represent_sequence("tag:yaml.org,2002:python/tuple", data, flow_style=True)
49BirdPlanSafeLoader.add_constructor("tag:yaml.org,2002:python/tuple", BirdPlanSafeLoader.construct_python_tuple)
50BirdPlanSafeDumper.add_representer(tuple, BirdPlanSafeDumper.represent_tuple)
53class YAML(YAMLBase):
54 """YAML class."""
56 def __init__(self) -> None:
57 """Initialize our parser YAML."""
59 def load(self, yaml: Union[str, pathlib.Path, io.IOBase]) -> Any:
60 """Load YAML string."""
62 yaml_data: str = ""
63 # Handle strings
64 if isinstance(yaml, str):
65 yaml_data = yaml
66 # Handle path objects
67 elif isinstance(yaml, pathlib.Path):
68 with open(yaml, "r", encoding="UTF-8") as yaml_file:
69 yaml_data = yaml_file.read()
70 # Whats left over is file objects
71 elif isinstance(yaml, io.IOBase):
72 yaml_data = yaml.read()
74 return pyaml.load(yaml_data, BirdPlanSafeLoader) # nosec
76 def dump(self, data: Any, stream: Optional[Union[pathlib.Path, io.IOBase]] = None) -> Any:
77 """Dump to YAML."""
79 if stream:
80 # Handle path objects
81 if isinstance(stream, pathlib.Path):
82 with open(stream, "w", encoding="UTF-8") as dump_file:
83 return pyaml.dump(data, stream=dump_file, encoding="UTF-8", Dumper=BirdPlanSafeDumper)
84 # Whats left over is file objects
85 return pyaml.dump(
86 data,
87 stream=stream,
88 encoding="UTF-8",
89 Dumper=BirdPlanSafeDumper,
90 )
92 # Create a string IO object and dump the YAML data to it
93 dumpstr = io.StringIO() # pragma: no cover
94 with dumpstr: # pragma: no cover
95 pyaml.dump(data, dumpstr, encoding="UTF-8", Dumper=BirdPlanSafeDumper)
96 return dumpstr.getvalue()