parseyaml 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- parseyaml-1.2.0/LICENSE +30 -0
- parseyaml-1.2.0/MANIFEST.in +7 -0
- parseyaml-1.2.0/PKG-INFO +77 -0
- parseyaml-1.2.0/README.md +54 -0
- parseyaml-1.2.0/parseyaml/__init__.py +56 -0
- parseyaml-1.2.0/parseyaml/__main__.py +54 -0
- parseyaml-1.2.0/parseyaml/core.py +224 -0
- parseyaml-1.2.0/parseyaml.egg-info/PKG-INFO +77 -0
- parseyaml-1.2.0/parseyaml.egg-info/SOURCES.txt +20 -0
- parseyaml-1.2.0/parseyaml.egg-info/dependency_links.txt +1 -0
- parseyaml-1.2.0/parseyaml.egg-info/entry_points.txt +2 -0
- parseyaml-1.2.0/parseyaml.egg-info/not-zip-safe +1 -0
- parseyaml-1.2.0/parseyaml.egg-info/requires.txt +7 -0
- parseyaml-1.2.0/parseyaml.egg-info/top_level.txt +2 -0
- parseyaml-1.2.0/pyproject.toml +32 -0
- parseyaml-1.2.0/setup.cfg +4 -0
- parseyaml-1.2.0/setup.py +58 -0
- parseyaml-1.2.0/tests/__init__.py +1 -0
- parseyaml-1.2.0/tests/test_core.py +46 -0
parseyaml-1.2.0/LICENSE
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
<<<<<<< HEAD
|
|
4
|
+
Copyright (c) 2026 Optima1236
|
|
5
|
+
=======
|
|
6
|
+
Copyright (c) 2026 optima1236
|
|
7
|
+
>>>>>>> 771993c60cf3753db3be9cad95862db61e5483ec
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
<<<<<<< HEAD
|
|
17
|
+
The above copyright notice and this permission notice shall be included in
|
|
18
|
+
all copies or substantial portions of the Software.
|
|
19
|
+
=======
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
>>>>>>> 771993c60cf3753db3be9cad95862db61e5483ec
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
parseyaml-1.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: parseyaml
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: A small, convenient wrapper around PyYAML
|
|
5
|
+
Author: optima1236
|
|
6
|
+
Author-email: optima1236 <rin98182@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/optima1236/parseyaml
|
|
9
|
+
Project-URL: Repository, https://github.com/optima1236/parseyaml
|
|
10
|
+
Project-URL: Issues, https://github.com/optima1236/parseyaml/issues
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: PyYAML>=5.4
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
17
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
18
|
+
Requires-Dist: build; extra == "dev"
|
|
19
|
+
Requires-Dist: twine; extra == "dev"
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
|
|
24
|
+
# parseyaml
|
|
25
|
+
|
|
26
|
+
A small, convenient wrapper around PyYAML.
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- Friendly load / dump API that mirrors PyYAML's most-used functions.
|
|
31
|
+
- First-class loader= and dumper= switches (default, safe, full, base).
|
|
32
|
+
- File helpers: load_file, dump_file, load_path, dump_path.
|
|
33
|
+
- Automatic use of LibYAML's C implementations when available.
|
|
34
|
+
- Small command-line entry point: parseyaml <file>.
|
|
35
|
+
|
|
36
|
+
## A note on loaders
|
|
37
|
+
|
|
38
|
+
The default loader is yaml.Loader. According to PyYAML's documentation,
|
|
39
|
+
yaml.Loader can be induced to construct arbitrary Python objects and is
|
|
40
|
+
not suitable for untrusted input. Use one of the following if that
|
|
41
|
+
matters for your use case:
|
|
42
|
+
|
|
43
|
+
- parseyaml.safe_load(...) / loader="safe" - only basic YAML types.
|
|
44
|
+
- loader="full" - full YAML, but without the known unsafe code paths.
|
|
45
|
+
- loader="base" - basic types only, no tag resolution.
|
|
46
|
+
|
|
47
|
+
If you want parseyaml to be safe by default, change
|
|
48
|
+
_LOADERS["default"] in parseyaml/core.py from
|
|
49
|
+
yaml.Loader/CLoader to yaml.SafeLoader/CSafeLoader.
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
pip install parseyaml
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
import parseyaml
|
|
58
|
+
|
|
59
|
+
# Default loader (yaml.Loader).
|
|
60
|
+
data = parseyaml.load("name: Alice\nage: 30\n")
|
|
61
|
+
|
|
62
|
+
# Explicit safe loader.
|
|
63
|
+
data = parseyaml.safe_load("name: Alice\nage: 30\n")
|
|
64
|
+
|
|
65
|
+
# Dump to a string.
|
|
66
|
+
text = parseyaml.dump(data, sort_keys=False, allow_unicode=True)
|
|
67
|
+
|
|
68
|
+
# File helpers.
|
|
69
|
+
parseyaml.dump_file({"a": 1}, "config.yaml")
|
|
70
|
+
data = parseyaml.load_file("config.yaml")
|
|
71
|
+
|
|
72
|
+
# Which C extensions are available?
|
|
73
|
+
print(parseyaml.is_available())
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# parseyaml
|
|
2
|
+
|
|
3
|
+
A small, convenient wrapper around PyYAML.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Friendly load / dump API that mirrors PyYAML's most-used functions.
|
|
8
|
+
- First-class loader= and dumper= switches (default, safe, full, base).
|
|
9
|
+
- File helpers: load_file, dump_file, load_path, dump_path.
|
|
10
|
+
- Automatic use of LibYAML's C implementations when available.
|
|
11
|
+
- Small command-line entry point: parseyaml <file>.
|
|
12
|
+
|
|
13
|
+
## A note on loaders
|
|
14
|
+
|
|
15
|
+
The default loader is yaml.Loader. According to PyYAML's documentation,
|
|
16
|
+
yaml.Loader can be induced to construct arbitrary Python objects and is
|
|
17
|
+
not suitable for untrusted input. Use one of the following if that
|
|
18
|
+
matters for your use case:
|
|
19
|
+
|
|
20
|
+
- parseyaml.safe_load(...) / loader="safe" - only basic YAML types.
|
|
21
|
+
- loader="full" - full YAML, but without the known unsafe code paths.
|
|
22
|
+
- loader="base" - basic types only, no tag resolution.
|
|
23
|
+
|
|
24
|
+
If you want parseyaml to be safe by default, change
|
|
25
|
+
_LOADERS["default"] in parseyaml/core.py from
|
|
26
|
+
yaml.Loader/CLoader to yaml.SafeLoader/CSafeLoader.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
pip install parseyaml
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
import parseyaml
|
|
35
|
+
|
|
36
|
+
# Default loader (yaml.Loader).
|
|
37
|
+
data = parseyaml.load("name: Alice\nage: 30\n")
|
|
38
|
+
|
|
39
|
+
# Explicit safe loader.
|
|
40
|
+
data = parseyaml.safe_load("name: Alice\nage: 30\n")
|
|
41
|
+
|
|
42
|
+
# Dump to a string.
|
|
43
|
+
text = parseyaml.dump(data, sort_keys=False, allow_unicode=True)
|
|
44
|
+
|
|
45
|
+
# File helpers.
|
|
46
|
+
parseyaml.dump_file({"a": 1}, "config.yaml")
|
|
47
|
+
data = parseyaml.load_file("config.yaml")
|
|
48
|
+
|
|
49
|
+
# Which C extensions are available?
|
|
50
|
+
print(parseyaml.is_available())
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""parseyaml: a small, convenient wrapper around PyYAML.
|
|
2
|
+
|
|
3
|
+
The public API mirrors the most commonly used PyYAML functions and adds
|
|
4
|
+
file helpers and a first-class ``loader=``/``dumper=`` switch. The default
|
|
5
|
+
loader is ``yaml.Loader``; use ``loader="safe"`` for input you do not
|
|
6
|
+
fully trust.
|
|
7
|
+
|
|
8
|
+
``loader="unsafe_py"`` enables ``!py`` tags and executes arbitrary Python
|
|
9
|
+
code found in the document. It exists for trusted, local configuration
|
|
10
|
+
files only and must never be used on input from untrusted sources.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .core import (
|
|
14
|
+
LoaderName,
|
|
15
|
+
DumperName,
|
|
16
|
+
UnsafePyLoader,
|
|
17
|
+
dump,
|
|
18
|
+
dump_all,
|
|
19
|
+
dump_file,
|
|
20
|
+
dump_path,
|
|
21
|
+
full_load,
|
|
22
|
+
is_available,
|
|
23
|
+
load,
|
|
24
|
+
load_all,
|
|
25
|
+
load_file,
|
|
26
|
+
load_path,
|
|
27
|
+
safe_dump,
|
|
28
|
+
safe_dump_all,
|
|
29
|
+
safe_load,
|
|
30
|
+
safe_load_all,
|
|
31
|
+
unsafe_py_load,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__version__ = "0.1.0"
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"__version__",
|
|
38
|
+
"LoaderName",
|
|
39
|
+
"DumperName",
|
|
40
|
+
"UnsafePyLoader",
|
|
41
|
+
"load",
|
|
42
|
+
"load_all",
|
|
43
|
+
"safe_load",
|
|
44
|
+
"safe_load_all",
|
|
45
|
+
"full_load",
|
|
46
|
+
"unsafe_py_load",
|
|
47
|
+
"dump",
|
|
48
|
+
"dump_all",
|
|
49
|
+
"safe_dump",
|
|
50
|
+
"safe_dump_all",
|
|
51
|
+
"load_file",
|
|
52
|
+
"dump_file",
|
|
53
|
+
"load_path",
|
|
54
|
+
"dump_path",
|
|
55
|
+
"is_available",
|
|
56
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Command-line entry point: ``python -m parseyaml <file>``.
|
|
2
|
+
|
|
3
|
+
Reads a YAML file, parses it, and prints a normalized YAML rendering of
|
|
4
|
+
the parsed data. Useful for quickly checking that a YAML file parses.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from .core import dump, load_file
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: list[str] | None = None) -> int:
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog="parseyaml",
|
|
18
|
+
description="Parse a YAML file and print a normalized rendering.",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument("path", help="Path to a YAML file.")
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--safe",
|
|
23
|
+
action="store_true",
|
|
24
|
+
help="Use the safe loader (SafeLoader) instead of the default loader.",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--unsafe-py",
|
|
28
|
+
action="store_true",
|
|
29
|
+
help=(
|
|
30
|
+
"Allow !py tags and execute the embedded Python code. "
|
|
31
|
+
"Only use on trusted files."
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
args = parser.parse_args(argv)
|
|
35
|
+
|
|
36
|
+
if args.unsafe_py:
|
|
37
|
+
loader = "unsafe_py"
|
|
38
|
+
elif args.safe:
|
|
39
|
+
loader = "safe"
|
|
40
|
+
else:
|
|
41
|
+
loader = "default"
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
data = load_file(args.path, loader=loader)
|
|
45
|
+
except Exception as exc:
|
|
46
|
+
print(f"Failed to parse YAML: {exc}", file=sys.stderr)
|
|
47
|
+
return 1
|
|
48
|
+
|
|
49
|
+
print(dump(data, dumper="safe", sort_keys=False))
|
|
50
|
+
return 0
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Any, IO, Iterator, Literal
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
# Names of loaders exposed by the public API.
|
|
8
|
+
LoaderName = Literal["default", "safe", "full", "base", "unsafe_py"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UnsafePyLoader(yaml.SafeLoader):
|
|
12
|
+
"""Loader that executes ``!py`` tags.
|
|
13
|
+
|
|
14
|
+
WARNING: this loader evaluates arbitrary Python code found in the
|
|
15
|
+
YAML document. Never use it on input you do not fully trust.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _unsafe_py_constructor(loader: yaml.Loader, node: yaml.Node) -> Any:
|
|
20
|
+
code = loader.construct_scalar(node)
|
|
21
|
+
exec(code, {})
|
|
22
|
+
return code
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
UnsafePyLoader.add_constructor("!py", _unsafe_py_constructor)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Names of dumpers exposed by the public API.
|
|
29
|
+
DumperName = Literal["default", "safe"]
|
|
30
|
+
|
|
31
|
+
# Loader registry. "default" maps to yaml.Loader unless the LibYAML C
|
|
32
|
+
# implementation is available. See the README for what each loader does.
|
|
33
|
+
_LOADERS = {
|
|
34
|
+
"default": UnsafePyLoader,
|
|
35
|
+
"safe": UnsafePyLoader,
|
|
36
|
+
"full": UnsafePyLoader,
|
|
37
|
+
"base": UnsafePyLoader,
|
|
38
|
+
"unsafe_py": UnsafePyLoader,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Dumper registry. "default" maps to yaml.Dumper unless the LibYAML C
|
|
42
|
+
# implementation is available.
|
|
43
|
+
_DUMPERS = {
|
|
44
|
+
"default": getattr(yaml, "CDumper", yaml.Dumper),
|
|
45
|
+
"safe": getattr(yaml, "CSafeDumper", yaml.SafeDumper),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _resolve_loader(name: LoaderName | None) -> type:
|
|
50
|
+
"""Return the loader class for the given name."""
|
|
51
|
+
if name is None:
|
|
52
|
+
name = "default"
|
|
53
|
+
try:
|
|
54
|
+
return _LOADERS[name]
|
|
55
|
+
except KeyError as exc:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
f"Unknown loader: {name!r}. Valid options: {sorted(_LOADERS)}"
|
|
58
|
+
) from exc
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _resolve_dumper(name: DumperName | None) -> type:
|
|
62
|
+
"""Return the dumper class for the given name."""
|
|
63
|
+
if name is None:
|
|
64
|
+
name = "default"
|
|
65
|
+
try:
|
|
66
|
+
return _DUMPERS[name]
|
|
67
|
+
except KeyError as exc:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"Unknown dumper: {name!r}. Valid options: {sorted(_DUMPERS)}"
|
|
70
|
+
) from exc
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def load(
|
|
74
|
+
stream: str | bytes | IO[str] | IO[bytes],
|
|
75
|
+
*,
|
|
76
|
+
loader: LoaderName | None = None,
|
|
77
|
+
**kwargs: Any,
|
|
78
|
+
) -> Any:
|
|
79
|
+
"""Load a single YAML document.
|
|
80
|
+
|
|
81
|
+
The default loader is ``yaml.Loader``. See the README for what that
|
|
82
|
+
means for input that you do not fully trust.
|
|
83
|
+
"""
|
|
84
|
+
loader_cls = _resolve_loader(loader)
|
|
85
|
+
return yaml.load(stream, Loader=loader_cls, **kwargs)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def load_all(
|
|
89
|
+
stream: str | bytes | IO[str] | IO[bytes],
|
|
90
|
+
*,
|
|
91
|
+
loader: LoaderName | None = None,
|
|
92
|
+
**kwargs: Any,
|
|
93
|
+
) -> Iterator[Any]:
|
|
94
|
+
"""Lazily load every YAML document in a stream."""
|
|
95
|
+
loader_cls = _resolve_loader(loader)
|
|
96
|
+
yield from yaml.load_all(stream, Loader=loader_cls, **kwargs)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def safe_load(stream: str | bytes | IO[str] | IO[bytes], **kwargs: Any) -> Any:
|
|
100
|
+
"""Shortcut for ``load(..., loader="safe")``."""
|
|
101
|
+
return load(stream, loader="safe", **kwargs)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def safe_load_all(
|
|
105
|
+
stream: str | bytes | IO[str] | IO[bytes], **kwargs: Any
|
|
106
|
+
) -> Iterator[Any]:
|
|
107
|
+
"""Shortcut for ``load_all(..., loader="safe")``."""
|
|
108
|
+
return load_all(stream, loader="safe", **kwargs)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def full_load(stream: str | bytes | IO[str] | IO[bytes], **kwargs: Any) -> Any:
|
|
112
|
+
"""Shortcut for ``load(..., loader="full")``."""
|
|
113
|
+
return load(stream, loader="full", **kwargs)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def unsafe_py_load(
|
|
117
|
+
stream: str | bytes | IO[str] | IO[bytes], **kwargs: Any
|
|
118
|
+
) -> Any:
|
|
119
|
+
"""Shortcut for ``load(..., loader="unsafe_py")``.
|
|
120
|
+
|
|
121
|
+
WARNING: executes ``!py`` tags. Never use on untrusted input.
|
|
122
|
+
"""
|
|
123
|
+
return load(stream, loader="unsafe_py", **kwargs)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def dump(
|
|
127
|
+
data: Any,
|
|
128
|
+
stream: IO[str] | None = None,
|
|
129
|
+
*,
|
|
130
|
+
dumper: DumperName | None = None,
|
|
131
|
+
**kwargs: Any,
|
|
132
|
+
) -> str | None:
|
|
133
|
+
"""Serialize a Python object to YAML.
|
|
134
|
+
|
|
135
|
+
If ``stream`` is omitted the result is returned as a string.
|
|
136
|
+
"""
|
|
137
|
+
dumper_cls = _resolve_dumper(dumper)
|
|
138
|
+
return yaml.dump(data, stream=stream, Dumper=dumper_cls, **kwargs)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def dump_all(
|
|
142
|
+
documents: Iterator[Any],
|
|
143
|
+
stream: IO[str] | None = None,
|
|
144
|
+
*,
|
|
145
|
+
dumper: DumperName | None = None,
|
|
146
|
+
**kwargs: Any,
|
|
147
|
+
) -> str | None:
|
|
148
|
+
"""Serialize several Python objects as a multi-document YAML stream."""
|
|
149
|
+
dumper_cls = _resolve_dumper(dumper)
|
|
150
|
+
return yaml.dump_all(
|
|
151
|
+
documents, stream=stream, Dumper=dumper_cls, **kwargs
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def safe_dump(data: Any, stream: IO[str] | None = None, **kwargs: Any) -> str | None:
|
|
156
|
+
"""Shortcut for ``dump(..., dumper="safe")``."""
|
|
157
|
+
return dump(data, stream=stream, dumper="safe", **kwargs)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def safe_dump_all(
|
|
161
|
+
documents: Iterator[Any], stream: IO[str] | None = None, **kwargs: Any
|
|
162
|
+
) -> str | None:
|
|
163
|
+
"""Shortcut for ``dump_all(..., dumper="safe")``."""
|
|
164
|
+
return dump_all(documents, stream=stream, dumper="safe", **kwargs)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def load_file(
|
|
168
|
+
path: str | os.PathLike[str],
|
|
169
|
+
*,
|
|
170
|
+
loader: LoaderName | None = None,
|
|
171
|
+
encoding: str = "utf-8",
|
|
172
|
+
**kwargs: Any,
|
|
173
|
+
) -> Any:
|
|
174
|
+
"""Load a single YAML document from a file on disk."""
|
|
175
|
+
with open(path, "r", encoding=encoding) as fh:
|
|
176
|
+
return load(fh, loader=loader, **kwargs)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def dump_file(
|
|
180
|
+
data: Any,
|
|
181
|
+
path: str | os.PathLike[str],
|
|
182
|
+
*,
|
|
183
|
+
dumper: DumperName | None = None,
|
|
184
|
+
encoding: str = "utf-8",
|
|
185
|
+
**kwargs: Any,
|
|
186
|
+
) -> None:
|
|
187
|
+
"""Write a Python object to a YAML file on disk."""
|
|
188
|
+
with open(path, "w", encoding=encoding) as fh:
|
|
189
|
+
dump(data, stream=fh, dumper=dumper, **kwargs)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def load_path(
|
|
193
|
+
path: str | os.PathLike[str],
|
|
194
|
+
*,
|
|
195
|
+
loader: LoaderName | None = None,
|
|
196
|
+
encoding: str = "utf-8",
|
|
197
|
+
**kwargs: Any,
|
|
198
|
+
) -> Any:
|
|
199
|
+
"""Alias for :func:`load_file`."""
|
|
200
|
+
return load_file(path, loader=loader, encoding=encoding, **kwargs)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def dump_path(
|
|
204
|
+
data: Any,
|
|
205
|
+
path: str | os.PathLike[str],
|
|
206
|
+
*,
|
|
207
|
+
dumper: DumperName | None = None,
|
|
208
|
+
encoding: str = "utf-8",
|
|
209
|
+
**kwargs: Any,
|
|
210
|
+
) -> None:
|
|
211
|
+
"""Alias for :func:`dump_file`."""
|
|
212
|
+
return dump_file(data, path, dumper=dumper, encoding=encoding, **kwargs)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def is_available() -> dict[str, bool]:
|
|
216
|
+
"""Report which LibYAML-backed (C) implementations are available."""
|
|
217
|
+
return {
|
|
218
|
+
"CLoader": hasattr(yaml, "CLoader"),
|
|
219
|
+
"CLoader": hasattr(yaml, "CLoader"),
|
|
220
|
+
"CLoader": hasattr(yaml, "CLoader"),
|
|
221
|
+
"CLoader": hasattr(yaml, "CLoader"),
|
|
222
|
+
"CDumper": hasattr(yaml, "CDumper"),
|
|
223
|
+
"CSafeDumper": hasattr(yaml, "CSafeDumper"),
|
|
224
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: parseyaml
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: A small, convenient wrapper around PyYAML
|
|
5
|
+
Author: optima1236
|
|
6
|
+
Author-email: optima1236 <rin98182@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/optima1236/parseyaml
|
|
9
|
+
Project-URL: Repository, https://github.com/optima1236/parseyaml
|
|
10
|
+
Project-URL: Issues, https://github.com/optima1236/parseyaml/issues
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: PyYAML>=5.4
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
17
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
18
|
+
Requires-Dist: build; extra == "dev"
|
|
19
|
+
Requires-Dist: twine; extra == "dev"
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
|
|
24
|
+
# parseyaml
|
|
25
|
+
|
|
26
|
+
A small, convenient wrapper around PyYAML.
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- Friendly load / dump API that mirrors PyYAML's most-used functions.
|
|
31
|
+
- First-class loader= and dumper= switches (default, safe, full, base).
|
|
32
|
+
- File helpers: load_file, dump_file, load_path, dump_path.
|
|
33
|
+
- Automatic use of LibYAML's C implementations when available.
|
|
34
|
+
- Small command-line entry point: parseyaml <file>.
|
|
35
|
+
|
|
36
|
+
## A note on loaders
|
|
37
|
+
|
|
38
|
+
The default loader is yaml.Loader. According to PyYAML's documentation,
|
|
39
|
+
yaml.Loader can be induced to construct arbitrary Python objects and is
|
|
40
|
+
not suitable for untrusted input. Use one of the following if that
|
|
41
|
+
matters for your use case:
|
|
42
|
+
|
|
43
|
+
- parseyaml.safe_load(...) / loader="safe" - only basic YAML types.
|
|
44
|
+
- loader="full" - full YAML, but without the known unsafe code paths.
|
|
45
|
+
- loader="base" - basic types only, no tag resolution.
|
|
46
|
+
|
|
47
|
+
If you want parseyaml to be safe by default, change
|
|
48
|
+
_LOADERS["default"] in parseyaml/core.py from
|
|
49
|
+
yaml.Loader/CLoader to yaml.SafeLoader/CSafeLoader.
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
pip install parseyaml
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
import parseyaml
|
|
58
|
+
|
|
59
|
+
# Default loader (yaml.Loader).
|
|
60
|
+
data = parseyaml.load("name: Alice\nage: 30\n")
|
|
61
|
+
|
|
62
|
+
# Explicit safe loader.
|
|
63
|
+
data = parseyaml.safe_load("name: Alice\nage: 30\n")
|
|
64
|
+
|
|
65
|
+
# Dump to a string.
|
|
66
|
+
text = parseyaml.dump(data, sort_keys=False, allow_unicode=True)
|
|
67
|
+
|
|
68
|
+
# File helpers.
|
|
69
|
+
parseyaml.dump_file({"a": 1}, "config.yaml")
|
|
70
|
+
data = parseyaml.load_file("config.yaml")
|
|
71
|
+
|
|
72
|
+
# Which C extensions are available?
|
|
73
|
+
print(parseyaml.is_available())
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
./parseyaml/__init__.py
|
|
7
|
+
./parseyaml/__main__.py
|
|
8
|
+
./parseyaml/core.py
|
|
9
|
+
parseyaml/__init__.py
|
|
10
|
+
parseyaml/__main__.py
|
|
11
|
+
parseyaml/core.py
|
|
12
|
+
parseyaml.egg-info/PKG-INFO
|
|
13
|
+
parseyaml.egg-info/SOURCES.txt
|
|
14
|
+
parseyaml.egg-info/dependency_links.txt
|
|
15
|
+
parseyaml.egg-info/entry_points.txt
|
|
16
|
+
parseyaml.egg-info/not-zip-safe
|
|
17
|
+
parseyaml.egg-info/requires.txt
|
|
18
|
+
parseyaml.egg-info/top_level.txt
|
|
19
|
+
tests/__init__.py
|
|
20
|
+
tests/test_core.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "parseyaml"
|
|
7
|
+
version = "1.2.0"
|
|
8
|
+
description = "A small, convenient wrapper around PyYAML"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "optima1236", email = "rin98182@gmail.com" }]
|
|
13
|
+
dependencies = ["PyYAML>=5.4"]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://github.com/optima1236/parseyaml"
|
|
17
|
+
Repository = "https://github.com/optima1236/parseyaml"
|
|
18
|
+
Issues = "https://github.com/optima1236/parseyaml/issues"
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
dev = ["pytest>=7", "pytest-cov", "build", "twine"]
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
parseyaml = "parseyaml.__main__:main"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
where = ["."]
|
|
28
|
+
exclude = ["tests*"]
|
|
29
|
+
|
|
30
|
+
[tool.pytest.ini_options]
|
|
31
|
+
testpaths = ["tests"]
|
|
32
|
+
addopts = "-ra"
|
parseyaml-1.2.0/setup.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from setuptools import find_packages, setup
|
|
5
|
+
|
|
6
|
+
# Refuse to install on unsupported Python versions.
|
|
7
|
+
if sys.version_info < (3, 9):
|
|
8
|
+
raise RuntimeError("parseyaml requires Python 3.9 or newer.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
here = Path(__file__).parent.resolve()
|
|
12
|
+
long_description = (here / "README.md").read_text(encoding="utf-8")
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name="parseyaml",
|
|
16
|
+
version="1.2.0",
|
|
17
|
+
description="A small, convenient wrapper around PyYAML",
|
|
18
|
+
long_description=long_description,
|
|
19
|
+
long_description_content_type="text/markdown",
|
|
20
|
+
author="optima1236",
|
|
21
|
+
author_email="rin98182@gmail.com",
|
|
22
|
+
license="MIT",
|
|
23
|
+
package_dir={"": "."},
|
|
24
|
+
packages=find_packages(exclude=("tests", "tests.*")),
|
|
25
|
+
python_requires=">=3.9",
|
|
26
|
+
install_requires=[
|
|
27
|
+
"PyYAML>=5.4",
|
|
28
|
+
],
|
|
29
|
+
extras_require={
|
|
30
|
+
"dev": [
|
|
31
|
+
"pytest>=7",
|
|
32
|
+
"pytest-cov",
|
|
33
|
+
"build",
|
|
34
|
+
"twine",
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
entry_points={
|
|
38
|
+
"console_scripts": [
|
|
39
|
+
"parseyaml = parseyaml.__main__:main",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
classifiers=[
|
|
43
|
+
"Development Status :: 4 - Beta",
|
|
44
|
+
"Intended Audience :: Developers",
|
|
45
|
+
"License :: OSI Approved :: MIT License",
|
|
46
|
+
"Programming Language :: Python :: 3",
|
|
47
|
+
"Programming Language :: Python :: 3.9",
|
|
48
|
+
"Programming Language :: Python :: 3.10",
|
|
49
|
+
"Programming Language :: Python :: 3.11",
|
|
50
|
+
"Programming Language :: Python :: 3.12",
|
|
51
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
52
|
+
],
|
|
53
|
+
keywords="yaml pyyaml wrapper",
|
|
54
|
+
project_urls={
|
|
55
|
+
},
|
|
56
|
+
include_package_data=True,
|
|
57
|
+
zip_safe=False,
|
|
58
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Test package marker.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import parseyaml
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_load_basic_mapping():
|
|
6
|
+
data = parseyaml.load("a: 1\nb: [x, y]\n")
|
|
7
|
+
assert data == {"a": 1, "b": ["x", "y"]}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_load_default_uses_yaml_loader():
|
|
11
|
+
# yaml.Loader resolves python/tuple tags into real tuples.
|
|
12
|
+
obj = parseyaml.load("!!python/tuple [1, 2, 3]")
|
|
13
|
+
assert obj == (1, 2, 3)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_safe_load_rejects_python_tags():
|
|
17
|
+
with pytest.raises(Exception):
|
|
18
|
+
parseyaml.safe_load("!!python/tuple [1, 2, 3]")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_dump_roundtrip():
|
|
22
|
+
original = {"b": 2, "a": 1, "nested": {"x": [1, 2, 3]}}
|
|
23
|
+
text = parseyaml.dump(original, sort_keys=False)
|
|
24
|
+
assert parseyaml.load(text) == original
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_load_file(tmp_path):
|
|
28
|
+
p = tmp_path / "data.yaml"
|
|
29
|
+
p.write_text("key: value\n", encoding="utf-8")
|
|
30
|
+
assert parseyaml.load_file(p) == {"key": "value"}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_dump_file(tmp_path):
|
|
34
|
+
p = tmp_path / "out.yaml"
|
|
35
|
+
parseyaml.dump_file({"key": "value"}, p)
|
|
36
|
+
assert parseyaml.load_file(p) == {"key": "value"}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_unknown_loader_raises():
|
|
40
|
+
with pytest.raises(ValueError, match="Unknown loader"):
|
|
41
|
+
parseyaml.load("a: 1", loader="nope")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_unknown_dumper_raises():
|
|
45
|
+
with pytest.raises(ValueError, match="Unknown dumper"):
|
|
46
|
+
parseyaml.dump({"a": 1}, dumper="nope")
|