Skip to content

Commit

Permalink
Add YAML 1.2 tags
Browse files Browse the repository at this point in the history
Example code:

    import yaml

    class MyCoreLoader(yaml.BaseLoader): pass
    class MyJSONLoader(yaml.BaseLoader): pass
    class MyCoreDumper(yaml.CommonDumper): pass
    class MyJSONDumper(yaml.CommonDumper): pass

    MyCoreLoader.init_tags('core')
    MyJSONLoader.init_tags('json')

    MyCoreDumper.init_tags('core')
    MyJSONDumper.init_tags('json')

    input = """
    - TRUE
    - yes
    - ~
    - true
    #- .inf
    #- 23
    #- #empty
    #- !!str #empty
    #- 010
    #- 0o10
    #- 0b100
    #- 0x20
    #- -0x20
    #- 1_000
    #- 3:14
    #- 0011
    #- +0
    #- 0001.23
    #- !!str +0.3e3
    #- +0.3e3
    #- &x foo
    #- *x
    #- 1e27
    #- 1x+27
    """

    print('--------------------------------------------- BaseLoader')
    data = yaml.load(input, Loader=yaml.BaseLoader)
    print(data)
    print('--------------------------------------------- SafeLoader')
    data = yaml.load(input, Loader=yaml.SafeLoader)
    print(data)
    print('--------------------------------------------- CoreLoader')
    data = yaml.load(input, Loader=MyCoreLoader)
    print(data)
    print('--------------------------------------------- JSONLoader')
    data = yaml.load(input, Loader=MyJSONLoader)
    print(data)

    print('--------------------------------------------- SafeDumper')
    out = yaml.dump(data, Dumper=yaml.SafeDumper)
    print(out)
    print('--------------------------------------------- MyCoreDumper')
    out = yaml.dump(data, Dumper=MyCoreDumper)
    print(out)
    print('--------------------------------------------- MyJSONDumper')
    out = yaml.dump(data, Dumper=MyJSONDumper)
    print(out)
  • Loading branch information
perlpunk committed Sep 22, 2021
1 parent 35f0417 commit 33cdeed
Show file tree
Hide file tree
Showing 10 changed files with 891 additions and 266 deletions.
352 changes: 206 additions & 146 deletions lib/yaml/constructor.py

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion lib/yaml/dumper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
__all__ = ['BaseDumper', 'SafeDumper', 'Dumper', 'CommonDumper']

from .emitter import *
from .serializer import *
Expand Down Expand Up @@ -42,6 +42,29 @@ def __init__(self, stream,
default_flow_style=default_flow_style, sort_keys=sort_keys)
Resolver.__init__(self)

class CommonDumper(Emitter, Serializer, CommonRepresenter, BaseResolver):

def __init__(self, stream,
default_style=None, default_flow_style=False,
canonical=None, indent=None, width=None,
allow_unicode=None, line_break=None,
encoding=None, explicit_start=None, explicit_end=None,
version=None, tags=None, sort_keys=True):
Emitter.__init__(self, stream, canonical=canonical,
indent=indent, width=width,
allow_unicode=allow_unicode, line_break=line_break)
Serializer.__init__(self, encoding=encoding,
explicit_start=explicit_start, explicit_end=explicit_end,
version=version, tags=tags)
CommonRepresenter.__init__(self, default_style=default_style,
default_flow_style=default_flow_style, sort_keys=sort_keys)
BaseResolver.__init__(self)

@classmethod
def init_tags(cls, tagset):
cls.init_representers(tagset)
cls.init_resolvers(tagset)

class Dumper(Emitter, Serializer, Representer, Resolver):

def __init__(self, stream,
Expand Down
8 changes: 7 additions & 1 deletion lib/yaml/loader.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

__all__ = ['BaseLoader', 'FullLoader', 'SafeLoader', 'Loader', 'UnsafeLoader']
__all__ = ['BaseLoader', 'FullLoader', 'SafeLoader', 'Loader', 'UnsafeLoader',
]

from .reader import *
from .scanner import *
Expand All @@ -18,6 +19,11 @@ def __init__(self, stream):
BaseConstructor.__init__(self)
BaseResolver.__init__(self)

@classmethod
def init_tags(cls, tagset):
cls.init_constructors(tagset)
cls.init_resolvers(tagset)

class FullLoader(Reader, Scanner, Parser, Composer, FullConstructor, Resolver):

def __init__(self, stream):
Expand Down
176 changes: 102 additions & 74 deletions lib/yaml/representer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
'RepresenterError']
'RepresenterError', 'CommonRepresenter']

from .error import *
from .nodes import *
Expand Down Expand Up @@ -131,29 +131,30 @@ def represent_mapping(self, tag, mapping, flow_style=None):
def ignore_aliases(self, data):
return False

class SafeRepresenter(BaseRepresenter):
def represent_str(self, data):
return self.represent_scalar('tag:yaml.org,2002:str', data)

def ignore_aliases(self, data):
if data is None:
return True
if isinstance(data, tuple) and data == ():
return True
if isinstance(data, (str, bytes, bool, int, float)):
return True
def represent_list(self, data):
#pairs = (len(data) > 0 and isinstance(data, list))
#if pairs:
# for item in data:
# if not isinstance(item, tuple) or len(item) != 2:
# pairs = False
# break
#if not pairs:
return self.represent_sequence('tag:yaml.org,2002:seq', data)
#value = []
#for item_key, item_value in data:
# value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
# [(item_key, item_value)]))
#return SequenceNode(u'tag:yaml.org,2002:pairs', value)

def represent_dict(self, data):
return self.represent_mapping('tag:yaml.org,2002:map', data)

def represent_none(self, data):
return self.represent_scalar('tag:yaml.org,2002:null', 'null')

def represent_str(self, data):
return self.represent_scalar('tag:yaml.org,2002:str', data)

def represent_binary(self, data):
if hasattr(base64, 'encodebytes'):
data = base64.encodebytes(data).decode('ascii')
else:
data = base64.encodestring(data).decode('ascii')
return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|')

def represent_bool(self, data):
if data:
value = 'true'
Expand Down Expand Up @@ -184,27 +185,17 @@ def represent_float(self, data):
# Unfortunately, this is not a valid float representation according
# to the definition of the `!!float` tag. We fix this by adding
# '.0' before the 'e' symbol.
# TODO (In YAML 1.2 Core, 1e17 would be a valid float though)
if '.' not in value and 'e' in value:
value = value.replace('e', '.0e', 1)
return self.represent_scalar('tag:yaml.org,2002:float', value)

def represent_list(self, data):
#pairs = (len(data) > 0 and isinstance(data, list))
#if pairs:
# for item in data:
# if not isinstance(item, tuple) or len(item) != 2:
# pairs = False
# break
#if not pairs:
return self.represent_sequence('tag:yaml.org,2002:seq', data)
#value = []
#for item_key, item_value in data:
# value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
# [(item_key, item_value)]))
#return SequenceNode(u'tag:yaml.org,2002:pairs', value)

def represent_dict(self, data):
return self.represent_mapping('tag:yaml.org,2002:map', data)
def represent_binary(self, data):
if hasattr(base64, 'encodebytes'):
data = base64.encodebytes(data).decode('ascii')
else:
data = base64.encodestring(data).decode('ascii')
return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|')

def represent_set(self, data):
value = {}
Expand All @@ -220,54 +211,91 @@ def represent_datetime(self, data):
value = data.isoformat(' ')
return self.represent_scalar('tag:yaml.org,2002:timestamp', value)

def represent_yaml_object(self, tag, data, cls, flow_style=None):
if hasattr(data, '__getstate__'):
state = data.__getstate__()
else:
state = data.__dict__.copy()
return self.represent_mapping(tag, state, flow_style=flow_style)

def represent_undefined(self, data):
raise RepresenterError("cannot represent an object", data)

SafeRepresenter.add_representer(type(None),
SafeRepresenter.represent_none)

SafeRepresenter.add_representer(str,
SafeRepresenter.represent_str)

SafeRepresenter.add_representer(bytes,
SafeRepresenter.represent_binary)

SafeRepresenter.add_representer(bool,
SafeRepresenter.represent_bool)

SafeRepresenter.add_representer(int,
SafeRepresenter.represent_int)

SafeRepresenter.add_representer(float,
SafeRepresenter.represent_float)
@classmethod
def init_representers(cls, name):
for key in _representers[name]:
callback = _representers[name][key]
cls.add_representer(key, callback)

SafeRepresenter.add_representer(list,
SafeRepresenter.represent_list)
class CommonRepresenter(BaseRepresenter):

SafeRepresenter.add_representer(tuple,
SafeRepresenter.represent_list)
def ignore_aliases(self, data):
if data is None:
return True
if isinstance(data, tuple) and data == ():
return True
if isinstance(data, (str, bytes, bool, int, float)):
return True

SafeRepresenter.add_representer(dict,
SafeRepresenter.represent_dict)
def represent_yaml_object(self, tag, data, cls, flow_style=None):
if hasattr(data, '__getstate__'):
state = data.__getstate__()
else:
state = data.__dict__.copy()
return self.represent_mapping(tag, state, flow_style=flow_style)

SafeRepresenter.add_representer(set,
SafeRepresenter.represent_set)
class SafeRepresenter(BaseRepresenter):

SafeRepresenter.add_representer(datetime.date,
SafeRepresenter.represent_date)
def ignore_aliases(self, data):
if data is None:
return True
if isinstance(data, tuple) and data == ():
return True
if isinstance(data, (str, bytes, bool, int, float)):
return True

SafeRepresenter.add_representer(datetime.datetime,
SafeRepresenter.represent_datetime)
def represent_yaml_object(self, tag, data, cls, flow_style=None):
if hasattr(data, '__getstate__'):
state = data.__getstate__()
else:
state = data.__dict__.copy()
return self.represent_mapping(tag, state, flow_style=flow_style)

SafeRepresenter.add_representer(None,
SafeRepresenter.represent_undefined)
_representers = {
'yaml11': {
bool: BaseRepresenter.represent_bool,
dict: BaseRepresenter.represent_dict,
list: BaseRepresenter.represent_list,
tuple: BaseRepresenter.represent_list,
str: BaseRepresenter.represent_str,
float: BaseRepresenter.represent_float,
int: BaseRepresenter.represent_int,
type(None): BaseRepresenter.represent_none,
bytes: BaseRepresenter.represent_binary,
set: BaseRepresenter.represent_set,
datetime.date: BaseRepresenter.represent_date,
datetime.datetime: BaseRepresenter.represent_datetime,
None: BaseRepresenter.represent_undefined,
},
'core': {
bool: BaseRepresenter.represent_bool,
dict: BaseRepresenter.represent_dict,
list: BaseRepresenter.represent_list,
tuple: BaseRepresenter.represent_list,
str: BaseRepresenter.represent_str,
float: BaseRepresenter.represent_float,
int: BaseRepresenter.represent_int,
type(None): BaseRepresenter.represent_none,
None: BaseRepresenter.represent_undefined,
},
'json': {
bool: BaseRepresenter.represent_bool,
dict: BaseRepresenter.represent_dict,
list: BaseRepresenter.represent_list,
tuple: BaseRepresenter.represent_list,
str: BaseRepresenter.represent_str,
float: BaseRepresenter.represent_float,
int: BaseRepresenter.represent_int,
type(None): BaseRepresenter.represent_none,
None: BaseRepresenter.represent_undefined,
},
}


SafeRepresenter.init_representers('yaml11')

class Representer(SafeRepresenter):

Expand Down
Loading

0 comments on commit 33cdeed

Please sign in to comment.