This is an automated email from the ASF dual-hosted git repository.
akitouni pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/buildstream.git
The following commit(s) were added to refs/heads/master by this push:
new 5ef9e1f _yaml.pyx: port roundtripping code to the new ruamel.yaml API
new 2164ac3 Merge pull request #1546 from abderrahim/yaml-deprecation
5ef9e1f is described below
commit 5ef9e1fdcf46e85695592ce0d83db962c00e5a7c
Author: Abderrahim Kitouni <[email protected]>
AuthorDate: Mon Dec 13 14:37:53 2021 +0100
_yaml.pyx: port roundtripping code to the new ruamel.yaml API
Also drop roundtrip_load_data that was unused
Fixes #1495
---
src/buildstream/_yaml.pyx | 85 +++++++++++++++++------------------------------
tests/internals/yaml.py | 14 ++------
2 files changed, 34 insertions(+), 65 deletions(-)
diff --git a/src/buildstream/_yaml.pyx b/src/buildstream/_yaml.pyx
index 64b76c5..a07353d 100644
--- a/src/buildstream/_yaml.pyx
+++ b/src/buildstream/_yaml.pyx
@@ -378,25 +378,25 @@
yaml.RoundTripConstructor.add_constructor(u'tag:yaml.org,2002:null',
yaml.RoundTripConstructor.add_constructor(u'tag:yaml.org,2002:timestamp',
yaml.RoundTripConstructor.construct_yaml_str)
-
-# HardlineDumper
-#
# This is a dumper used during roundtrip_dump which forces every scalar to be
# a plain string, in order to match the output format to the input format.
#
# If you discover something is broken, please add a test case to the roundtrip
# test in tests/internals/yaml/roundtrip-test.yaml
-#
-class HardlineDumper(yaml.RoundTripDumper):
- def __init__(self, *args, **kwargs):
- yaml.RoundTripDumper.__init__(self, *args, **kwargs)
- # For each of YAML 1.1 and 1.2, force everything to be a plain string
- for version in [(1, 1), (1, 2), None]:
- self.add_version_implicit_resolver(
- version,
- u'tag:yaml.org,2002:str',
- yaml.util.RegExp(r'.*'),
- None)
+def prepare_roundtrip_yaml():
+ yml = yaml.YAML()
+ yml.preserve_quotes=True
+
+ # For each of YAML 1.1 and 1.2, force everything to be a plain string
+
+ for version in [(1, 1), (1, 2), None]:
+ yml.resolver.add_version_implicit_resolver(
+ version,
+ u'tag:yaml.org,2002:str',
+ yaml.util.RegExp(r'.*'),
+ None)
+
+ return yml
# roundtrip_load()
@@ -420,10 +420,23 @@ class HardlineDumper(yaml.RoundTripDumper):
# Also if the YAML is malformed.
#
def roundtrip_load(filename, *, allow_missing=False):
+ yml = prepare_roundtrip_yaml()
try:
with open(filename, "r") as fh:
- data = fh.read()
- contents = roundtrip_load_data(data, filename=filename)
+ try:
+ contents = yml.load(fh)
+ except (yaml.scanner.ScannerError, yaml.composer.ComposerError,
yaml.parser.ParserError) as e:
+ raise LoadError("Malformed
YAML:\n\n{}\n\n{}\n".format(e.problem, e.problem_mark),
+ LoadErrorReason.INVALID_YAML) from e
+
+ # Special case empty files at this point
+ if contents is None:
+ # We'll make them empty mappings like the main Node loader
+ contents = {}
+
+ if not isinstance(contents, Mapping):
+ raise LoadError("YAML file has content of type '{}' instead of
expected type 'dict': {}"
+ .format(type(contents).__name__, filename),
LoadErrorReason.INVALID_YAML)
except FileNotFoundError as e:
if allow_missing:
# Missing files are always empty dictionaries
@@ -437,43 +450,6 @@ def roundtrip_load(filename, *, allow_missing=False):
return contents
-# roundtrip_load_data()
-#
-# Parse the given contents as YAML, returning them as a roundtrippable data
-# structure.
-#
-# A lack of content will be returned as an empty mapping.
-#
-# Args:
-# contents (str): The contents to be parsed as YAML
-# filename (str): Optional filename to be used in error reports
-#
-# Returns:
-# (Mapping): The loaded YAML mapping
-#
-# Raises:
-# (LoadError): Raised on invalid YAML, or YAML which parses to something
other
-# than a Mapping
-#
-def roundtrip_load_data(contents, *, filename=None):
- try:
- contents = yaml.load(contents, yaml.RoundTripLoader,
preserve_quotes=True)
- except (yaml.scanner.ScannerError, yaml.composer.ComposerError,
yaml.parser.ParserError) as e:
- raise LoadError("Malformed YAML:\n\n{}\n\n{}\n".format(e.problem,
e.problem_mark),
- LoadErrorReason.INVALID_YAML) from e
-
- # Special case empty files at this point
- if contents is None:
- # We'll make them empty mappings like the main Node loader
- contents = {}
-
- if not isinstance(contents, Mapping):
- raise LoadError("YAML file has content of type '{}' instead of
expected type 'dict': {}"
- .format(type(contents).__name__, filename),
LoadErrorReason.INVALID_YAML)
-
- return contents
-
-
# roundtrip_dump()
#
# Dumps the given contents as a YAML file. Ideally the contents came from
@@ -488,6 +464,7 @@ def roundtrip_load_data(contents, *, filename=None):
# file (any): The file to write to
#
def roundtrip_dump(contents, file=None):
+ yml = prepare_roundtrip_yaml()
with ExitStack() as stack:
if type(file) is str:
from . import utils
@@ -496,4 +473,4 @@ def roundtrip_dump(contents, file=None):
f = file
else:
f = sys.stdout
- yaml.round_trip_dump(contents, f, Dumper=HardlineDumper)
+ yml.dump(contents, f)
diff --git a/tests/internals/yaml.py b/tests/internals/yaml.py
index 452906f..ee5ad94 100644
--- a/tests/internals/yaml.py
+++ b/tests/internals/yaml.py
@@ -400,21 +400,13 @@ def test_value_doesnt_match_expected(datafiles):
assert exc.value.reason == LoadErrorReason.INVALID_DATA
-# This test has been broken by upstream ruamel.yaml, filed an issue here:
-#
-# https://sourceforge.net/p/ruamel-yaml/tickets/390/
-#
[email protected](reason="recent versions of ruamel.yaml have broken
roundtripping perfection")
@pytest.mark.datafiles(os.path.join(DATA_DIR))
[email protected]("fromdisk", [(True), (False)])
-def test_roundtrip_dump(datafiles, fromdisk):
+def test_roundtrip_dump(datafiles):
filename = os.path.join(datafiles.dirname, datafiles.basename,
"roundtrip-test.yaml")
with open(filename, "r", encoding="utf-8") as fh:
rt_raw = fh.read()
- if fromdisk:
- rt_loaded = _yaml.roundtrip_load(filename)
- else:
- rt_loaded = _yaml.roundtrip_load_data(rt_raw, filename=filename)
+
+ rt_loaded = _yaml.roundtrip_load(filename)
# Now walk the loaded data structure, checking for ints etc.
def walk_node(node):