Skip to content

Commit 5a61048

Browse files
committed
fix(yaml): emit null, not empty scalars
This is the null value the users expect. It was how Remarshal worked with PyYAML. The choice of how to implement it is per the suggestion of the developer of ruamel.yaml on https://stackoverflow.com/questions/44313992/.
1 parent 05b2804 commit 5a61048

File tree

5 files changed

+27
-2
lines changed

5 files changed

+27
-2
lines changed

src/remarshal/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,10 @@ def stringify_null(x: Any) -> Any:
646646
raise ValueError(msg)
647647

648648

649+
def _yaml_represent_none(self, data):
650+
return self.represent_scalar("tag:yaml.org,2002:null", "null")
651+
652+
649653
def _encode_yaml(data: Document, *, yaml_options: YAMLOptions) -> str:
650654
yaml = ruamel.yaml.YAML()
651655
yaml.default_flow_style = False
@@ -654,6 +658,8 @@ def _encode_yaml(data: Document, *, yaml_options: YAMLOptions) -> str:
654658
yaml.indent = yaml_options.indent
655659
yaml.width = yaml_options.width
656660

661+
yaml.representer.add_representer(type(None), _yaml_represent_none)
662+
657663
try:
658664
out = StringIO()
659665
yaml.dump(

tests/bool-null-key.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
True: foo
22
false: oof
33
another: bar
4-
NULL: "nothin'"
4+
NULL: nothin'

tests/null.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"foo": null
3+
}

tests/null.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo: null

tests/test_remarshal.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#! /usr/bin/env python
22
# Remarshal, a utility to convert between serialization formats.
3-
# Copyright (c) 2014-2020, 2023 D. Bohdan
3+
# Copyright (c) 2014-2020, 2023-2024 D. Bohdan
44
# License: MIT
55

66
from __future__ import annotations
@@ -364,6 +364,11 @@ def test_binary_to_yaml(self, convert_and_read) -> None:
364364
def test_binary_to_cbor(self, convert_and_read) -> None:
365365
convert_and_read("bin.msgpack", "msgpack", "cbor")
366366

367+
def test_yaml_null(self, convert_and_read) -> None:
368+
output = convert_and_read("null.json", "json", "yaml")
369+
reference = read_file("null.yaml")
370+
assert output == reference
371+
367372
def test_yaml_style_default(self, convert_and_read) -> None:
368373
output = convert_and_read("long-line.json", "json", "yaml")
369374
reference = read_file("long-line-default.yaml")
@@ -544,6 +549,16 @@ def test_yaml2toml_bool_null_key(self, convert_and_read) -> None:
544549
reference = read_file("bool-null-key.toml")
545550
assert output == reference
546551

552+
def test_yaml2yaml_bool_null_key(self, convert_and_read) -> None:
553+
output = convert_and_read(
554+
"bool-null-key.yaml",
555+
"yaml",
556+
"yaml",
557+
)
558+
reference = read_file("bool-null-key.yaml")
559+
560+
assert output == reference.lower()
561+
547562
def test_yaml2toml_timestamp_key(self, convert_and_read) -> None:
548563
output = convert_and_read(
549564
"timestamp-key.yaml",

0 commit comments

Comments
 (0)