Skip to content

Commit

Permalink
Add preserve_bools
Browse files Browse the repository at this point in the history
  • Loading branch information
guibog committed Feb 29, 2024
1 parent a4806d4 commit 05d641b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 11 deletions.
77 changes: 77 additions & 0 deletions _test/test_bools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

import pytest
import io
import ruyaml # NOQA
from .roundtrip import round_trip, dedent

from ruyaml import YAML
from ruyaml.util import load_yaml_guess_indent
from ruyaml.scalarbool import ScalarBoolean
from ruyaml.comments import CommentedSeq
from ruyaml.representer import RoundTripRepresenter, ScalarNode
from ruyaml.constructor import RoundTripConstructor
from typing import Text, Any, Dict, List # NOQA


def round_trip_stabler(
inp,
outp=None,
):
if outp is None:
outp = inp
doutp = dedent(outp)
yaml = ruyaml.YAML()
yaml.preserve_quotes = True
yaml.preserve_bools = True
data = yaml.load(doutp)
buf = io.StringIO()
yaml.dump(data, stream=buf)
res = buf.getvalue()
assert res == doutp


class TestStability:

def test_lowercase_boolean(self):
round_trip(
"""
- true
"""
)

@pytest.mark.xfail(strict=True)
def test_uppercase_boolean(self):
round_trip(
"""
- True
"""
)

# @pytest.mark.xfail(strict=True) # Why not failing??
def test_yes_boolean(self):
round_trip(
"""
- yes
"""
)

def test_lowercase_boolean2(self):
round_trip_stabler(
"""
- true
"""
)

def test_uppercase_boolean2(self):
round_trip_stabler(
"""
- True
"""
)

def test_yes_boolean2(self):
round_trip_stabler(
"""
- yes
"""
)
7 changes: 4 additions & 3 deletions lib/ruyaml/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class BaseConstructor:
yaml_constructors = {} # type: Dict[Any, Any]
yaml_multi_constructors = {} # type: Dict[Any, Any]

def __init__(self, preserve_quotes=None, loader=None):
def __init__(self, preserve_quotes=None, loader=None, preserve_bools=None):
# type: (Optional[bool], Any) -> None
self.loader = loader
if (
Expand All @@ -91,6 +91,7 @@ def __init__(self, preserve_quotes=None, loader=None):
self.state_generators = [] # type: List[Any]
self.deep_construct = False
self._preserve_quotes = preserve_quotes
self._preserve_bools = preserve_bools
self.allow_duplicate_keys = False

@property
Expand Down Expand Up @@ -1862,8 +1863,8 @@ def construct_yaml_timestamp(self, node, values=None):
def construct_yaml_bool(self, node):
# type: (Any) -> Any
b = SafeConstructor.construct_yaml_bool(self, node)
if node.anchor:
return ScalarBoolean(b, anchor=node.anchor)
if node.anchor or self._preserve_bools:
return ScalarBoolean(b, anchor=node.anchor, orig_repr=node.value)
return b


Expand Down
5 changes: 4 additions & 1 deletion lib/ruyaml/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def __init__(
self.prefix_colon = None
self.version = None
self.preserve_quotes = None
self.preserve_bools = None
self.allow_duplicate_keys = False # duplicate keys in map, set
self.encoding = 'utf-8'
self.explicit_start = None
Expand Down Expand Up @@ -242,7 +243,9 @@ def constructor(self):
# type: () -> Any
attr = '_' + sys._getframe().f_code.co_name
if not hasattr(self, attr):
cnst = self.Constructor(preserve_quotes=self.preserve_quotes, loader=self)
cnst = self.Constructor(preserve_quotes=self.preserve_quotes,
preserve_bools=self.preserve_bools,
loader=self)
cnst.allow_duplicate_keys = self.allow_duplicate_keys
setattr(self, attr, cnst)
return getattr(self, attr)
Expand Down
17 changes: 10 additions & 7 deletions lib/ruyaml/representer.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,16 @@ def represent_binary(self, data):

def represent_bool(self, data, anchor=None):
# type: (Any, Optional[Any]) -> Any
try:
value = self.dumper.boolean_representation[bool(data)] # type: ignore
except AttributeError:
if data:
value = 'true'
else:
value = 'false'
if getattr(data, 'yaml_orig_repr', None) is not None:
value = data.yaml_orig_repr
else:
try:
value = self.dumper.boolean_representation[bool(data)] # type: ignore
except AttributeError:
if data:
value = 'true'
else:
value = 'false'
return self.represent_scalar('tag:yaml.org,2002:bool', value, anchor=anchor)

def represent_int(self, data):
Expand Down
5 changes: 5 additions & 0 deletions lib/ruyaml/scalarbool.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@


class ScalarBoolean(int):
yaml_orig_repr = None

def __new__(cls, *args, **kw):
# type: (Any, Any, Any) -> Any
anchor = kw.pop('anchor', None)
orig_repr = kw.pop('orig_repr', None)
b = int.__new__(cls, *args, **kw)
if orig_repr is not None:
b.yaml_orig_repr = orig_repr
if anchor is not None:
b.yaml_set_anchor(anchor, always_dump=True)
return b
Expand Down

0 comments on commit 05d641b

Please sign in to comment.