xcookie.util_yaml module

Wrappers around pyyaml or ruamel.yaml.

The important functions to know are:

Loads and Dumps are strightforward. Loads takes a block of text and passes it through the ruamel.yaml or pyyaml to parse the string. Dumps takes a data structure and turns it into a YAML string. Roundtripping is supported with the ruamel.yaml backend.

Coerce will accept input as a non-string data structure, and simply return it, a path to a file, or a string which it assumes is YAML text (note: there is a small ambiguity introduced here). If coerce encounters a string that looks like an existing path it reads it. This does not happen by default in longer YAML text inputs, but the parser does respect a !include constructor, which does let you make nested configs by pointing to other configs.

class xcookie.util_yaml._YamlRepresenter[source]

Bases: object

static str_presenter(dumper, data)[source]
xcookie.util_yaml._custom_ruaml_loader()[source]

old method

References

https://stackoverflow.com/questions/59635900/ruamel-yaml-custom-commentedmapping-for-custom-tags https://stackoverflow.com/questions/528281/how-can-i-include-a-yaml-file-inside-another https://stackoverflow.com/questions/76870413/using-a-custom-loader-with-ruamel-yaml-0-15-0

xcookie.util_yaml._custom_ruaml_dumper()[source]

References

https://stackoverflow.com/questions/59635900/ruamel-yaml-custom-commentedmapping-for-custom-tags

xcookie.util_yaml._custom_pyaml_dumper()[source]
xcookie.util_yaml._custom_new_ruaml_yaml_obj(version=None)[source]

new method

References

https://stackoverflow.com/questions/59635900/ruamel-yaml-custom-commentedmapping-for-custom-tags https://stackoverflow.com/questions/528281/how-can-i-include-a-yaml-file-inside-another https://stackoverflow.com/questions/76870413/using-a-custom-loader-with-ruamel-yaml-0-15-0

Example

>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> # Test new load
>>> import io
>>> file = io.StringIO('[a, b, c]')
>>> yaml_obj = _custom_new_ruaml_yaml_obj()
>>> data = yaml_obj.load(file)
>>> print(data)
>>> # Test round trip tump
>>> file = io.StringIO()
>>> yaml_obj.dump(data, file)
>>> print(file.getvalue())
>>> #
>>> # Test new dump
>>> data2 = ub.udict(a=1, b=2)
>>> file = io.StringIO()
>>> yaml_obj.dump(data2, file)
>>> print(file.getvalue())
class xcookie.util_yaml.Yaml[source]

Bases: object

Namespace for yaml functions

Example

>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> import ubelt as ub
>>> data = {
>>>     'a': 'hello world',
>>>     'b': ub.udict({'a': 3})
>>> }
>>> text1 = Yaml.dumps(data, backend='ruamel')
>>> # Coerce is idempotent and resolves the input to nested Python
>>> # structures.
>>> resolved1 = Yaml.coerce(data)
>>> resolved2 = Yaml.coerce(text1)
>>> resolved3 = Yaml.coerce(resolved2)
>>> assert resolved1 == resolved2 == resolved3 == data
>>> # with ruamel
>>> data2 = Yaml.loads(text1)
>>> assert data2 == data
>>> # with pyyaml
>>> data2 = Yaml.loads(text1, backend='pyyaml')
>>> assert data2 == data
static dumps(data, backend='ruamel', version=None)[source]

Dump yaml to a string representation (and account for some of our use-cases)

Parameters:
  • data (Any) – yaml representable data

  • backend (str) – either ruamel or pyyaml

Returns:

yaml text

Return type:

str

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> import ubelt as ub
>>> data = {
>>>     'a': 'hello world',
>>>     'b': ub.udict({'a': 3})
>>> }
>>> text2 = Yaml.dumps(data, backend='pyyaml')
>>> print(text2)
>>> text1 = Yaml.dumps(data, backend='ruamel')
>>> print(text1)
>>> assert text1 == text2
static load(file, backend='ruamel', version=None)[source]

Load yaml from a file

Parameters:
  • file (io.TextIOBase | PathLike | str) – yaml file path or file object

  • backend (str) – either ruamel or pyyaml

Returns:

object

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> import ubelt as ub
>>> data = {
>>>     'a': 'hello world',
>>>     'b': ub.udict({'a': 3})
>>> }
>>> text1 = Yaml.dumps(data, backend='ruamel')
>>> import io
>>> # with ruamel
>>> file = io.StringIO(text1)
>>> data2 = Yaml.load(file)
>>> assert data2 == data
>>> # with pyyaml
>>> file = io.StringIO(text1)
>>> data2 = Yaml.load(file, backend='pyyaml')
>>> assert data2 == data
static loads(text, backend='ruamel', version=None)[source]

Load yaml from a text

Parameters:
  • text (str) – yaml text

  • backend (str) – either ruamel or pyyaml

Returns:

object

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> import ubelt as ub
>>> data = {
>>>     'a': 'hello world',
>>>     'b': ub.udict({'a': 3})
>>> }
>>> print('data = {}'.format(ub.urepr(data, nl=1)))
>>> print('---')
>>> text = Yaml.dumps(data)
>>> print(ub.highlight_code(text, 'yaml'))
>>> print('---')
>>> data2 = Yaml.loads(text)
>>> assert data == data2
>>> data3 = Yaml.loads(text, backend='pyyaml')
>>> print('data2 = {}'.format(ub.urepr(data2, nl=1)))
>>> print('data3 = {}'.format(ub.urepr(data3, nl=1)))
>>> assert data == data3
static coerce(data, backend='ruamel', path_policy='existing_file_with_extension')[source]

Attempt to convert input into a parsed yaml / json data structure. If the data looks like a path, it tries to load and parse file contents. If the data looks like a yaml/json string it tries to parse it. If the data looks like parsed data, then it returns it as-is.

Parameters:
  • data (str | PathLike | dict | list)

  • backend (str) – either ruamel or pyyaml

  • path_policy (str) – Determines how we determine if something looks like a path. Pre 0.3.2 behavior is from path_policy=’existing_file’. Default is ‘existing_file_with_extension’. Can also be ‘never’ to disable the path feature and decrease ambiguity.

Returns:

parsed yaml data

Return type:

object

Note

The input to the function cannot distinguish a string that should be loaded and a string that should be parsed. If it looks like a file that exists it will read it. To avoid this coerner case use this only for data where you expect the output is a List or Dict.

References

https://stackoverflow.com/questions/528281/how-can-i-include-a-yaml-file-inside-another

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> text = ub.codeblock(
    '''
    - !!float nan
    - !!float inf
    - nan
    - inf
    # Seems to break older ruamel.yaml 0.17.21
    # - .nan
    # - .inf
    - null
    ''')
>>> Yaml.coerce(text, backend='pyyaml')
>>> Yaml.coerce(text, backend='ruamel')

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> Yaml.coerce('"[1, 2, 3]"')
[1, 2, 3]
>>> fpath = ub.Path.appdir('cmd_queue/tests/util_yaml').ensuredir() / 'file.yaml'
>>> fpath.write_text(Yaml.dumps([4, 5, 6]))
>>> Yaml.coerce(fpath)
[4, 5, 6]
>>> Yaml.coerce(str(fpath))
[4, 5, 6]
>>> dict(Yaml.coerce('{a: b, c: d}'))
{'a': 'b', 'c': 'd'}
>>> Yaml.coerce(None)
None

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> assert Yaml.coerce('') is None

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> dpath = ub.Path.appdir('cmd_queue/tests/util_yaml').ensuredir()
>>> fpath = dpath / 'external.yaml'
>>> fpath.write_text(Yaml.dumps({'foo': 'bar'}))
>>> text = ub.codeblock(
>>>    f'''
>>>    items:
>>>        - !include {dpath}/external.yaml
>>>    ''')
>>> data = Yaml.coerce(text, backend='ruamel')
>>> print(Yaml.dumps(data, backend='ruamel'))
items:
- foo: bar
>>> text = ub.codeblock(
>>>    f'''
>>>    items:
>>>        !include [{dpath}/external.yaml, blah, 1, 2, 3]
>>>    ''')
>>> data = Yaml.coerce(text, backend='ruamel')
>>> print('data = {}'.format(ub.urepr(data, nl=1)))
>>> print(Yaml.dumps(data, backend='ruamel'))
static InlineList(items)[source]

References

static Dict(data)[source]

Get a ruamel-enhanced dictionary

Example

>>> # xdoctest: +REQUIRES(module:pyyaml)
>>> # xdoctest: +REQUIRES(module:ruamel.yaml)
>>> data = {'a': 'avalue', 'b': 'bvalue'}
>>> data = Yaml.Dict(data)
>>> data.yaml_set_start_comment('hello')
>>> # Note: not working https://sourceforge.net/p/ruamel-yaml/tickets/400/
>>> data.yaml_set_comment_before_after_key('a', before='a comment', indent=2)
>>> data.yaml_set_comment_before_after_key('b', 'b comment')
>>> print(Yaml.dumps(data))
static CodeBlock(text)[source]
xcookie.util_yaml._dev()[source]