nestedtext.dumps

nestedtext.dumps(obj, *, width=0, sort_keys=False, indent=4, converters=None, default=None, _level=0)[source]

Recursively convert object to NestedText string.

Parameters
  • obj – The object to convert to NestedText.

  • width (int) – Enables compact lists and dictionaries if greater than zero and if resulting line would be less than or equal to given width.

  • sort_keys (bool or func) – Dictionary items are sorted by their key if sort_keys is true. If a function is passed in, it is used as the key function.

  • indent (int) – The number of spaces to use to represent a single level of indentation. Must be one or greater.

  • converters (dict) –

    A dictionary where the keys are types and the values are converter functions (functions that take an object and return it in a form that can be processed by NestedText). If a value is False, an unsupported type error is raised.

    An object may provide its own converter by defining the __nestedtext_converter__ attribute. It may be False, or it may be a method that converts the object to a supported data type for NestedText. A matching converter specified in the converters argument dominates over this attribute.

  • default (func or 'strict') – The default converter. Use to convert otherwise unrecognized objects to a form that can be processed. If not provided an error will be raised for unsupported data types. Typical values are repr or str. If ‘strict’ is specified then only dictionaries, lists, strings, and those types that have converters are allowed. If default is not specified then a broader collection of value types are supported, including None, bool, int, float, and list- and dict-like objects. In this case Booleans are rendered as ‘True’ and ‘False’ and None is rendered as an empty string. If default is a function, it acts as the default converter. If it raises a TypeError, the value is reported as an unsupported type.

  • _level (int) – The number of indentation levels. When dumps is invoked recursively this is used to increment the level and so the indent. Should not be specified by the user.

Returns

The NestedText content.

Raises

NestedTextError – if there is a problem in the input data.

Examples

>>> import nestedtext as nt

>>> data = {
...     'name': 'Kristel Templeton',
...     'sex': 'female',
...     'age': '74',
... }

>>> try:
...     print(nt.dumps(data))
... except nt.NestedTextError as e:
...     print(str(e))
name: Kristel Templeton
sex: female
age: 74

The NestedText format only supports dictionaries, lists, and strings. By default, dumps is configured to be rather forgiving, so it will render many of the base Python data types, such as None, bool, int, float and list-like types such as tuple and set by converting them to the types supported by the format. This implies that a round trip through dumps and loads could result in the types of values being transformed. You can restrict dumps to only supporting the native types of NestedText by passing default=’strict’ to dumps. Doing so means that values that are not dictionaries, lists, or strings generate exceptions.

>>> data = {'key': 42, 'value': 3.1415926, 'valid': True}

>>> try:
...     print(nt.dumps(data))
... except nt.NestedTextError as e:
...     print(str(e))
key: 42
value: 3.1415926
valid: True

>>> try:
...     print(nt.dumps(data, default='strict'))
... except nt.NestedTextError as e:
...     print(str(e))
42: unsupported type.

Alternatively, you can specify a function to default, which is used to convert values to strings. It is used if no other converter is available. Typical values are str and repr.

>>> class Color:
...     def __init__(self, color):
...         self.color = color
...     def __repr__(self):
...         return f'Color({self.color!r})'
...     def __str__(self):
...         return self.color

>>> data['house'] = Color('red')
>>> print(nt.dumps(data, default=repr))
key: 42
value: 3.1415926
valid: True
house: Color('red')

>>> print(nt.dumps(data, default=str))
key: 42
value: 3.1415926
valid: True
house: red

If Color is consistently used with NestedText, you can include the converter in Color itself.

>>> class Color:
...     def __init__(self, color):
...         self.color = color
...     def __nestedtext_converter__(self):
...         return self.color.title()

>>> data['house'] = Color('red')
>>> print(nt.dumps(data))
key: 42
value: 3.1415926
valid: True
house: Red

You can also specify a dictionary of converters. The dictionary maps the object type to a converter function.

>>> class Info:
...     def __init__(self, **kwargs):
...         self.__dict__ = kwargs

>>> converters = {
...     bool: lambda b: 'yes' if b else 'no',
...     int: hex,
...     float: lambda f: f'{f:0.3}',
...     Color: lambda c: c.color,
...     Info: lambda i: i.__dict__,
... }

>>> data['attributes'] = Info(readable=True, writable=False)

>>> try:
...    print(nt.dumps(data, converters=converters))
... except nt.NestedTextError as e:
...     print(str(e))
key: 0x2a
value: 3.14
valid: yes
house: red
attributes:
    readable: yes
    writable: no

The above example shows that Color in the converters argument dominates over the __nestedtest__converter__ class.

If the dictionary maps a type to None, then the default behavior is used for that type. If it maps to False, then an exception is raised.

>>> converters = {
...     bool: lambda b: 'yes' if b else 'no',
...     int: hex,
...     float: False,
...     Color: lambda c: c.color,
...     Info: lambda i: i.__dict__,
... }

>>> try:
...    print(nt.dumps(data, converters=converters))
... except nt.NestedTextError as e:
...     print(str(e))
3.1415926: unsupported type.

converters need not actually change the type of a value, it may simply transform the value. In the following example, converters is used to transform strings and dictionaries by adding quotes to strings and removing empty dictionary fields. It is also converts dates and physical quantities to strings.

>>> import arrow
>>> from inform import cull
>>> import quantiphy

>>> class Dollars(quantiphy.Quantity):
...     units = '$'
...     form = 'fixed'
...     prec = 2
...     strip_zeros = False
...     show_commas = True

>>> converters = {
...     str: repr,
...     dict: cull,
...     arrow.Arrow: lambda d: d.format('D MMMM YYYY'),
...     quantiphy.Quantity: lambda q: str(q)
... }

>>> transaction = dict(
...     date = arrow.get('2013-05-07T22:19:11.363410-07:00'),
...     description = "Incoming wire from Publisher's Clearing House",
...     debit = 0,
...     credit = Dollars(12345.67)
... )

>>> print(nt.dumps(transaction, converters=converters))
date: 7 May 2013
description: "Incoming wire from Publisher's Clearing House"
credit: $12,345.67

Both default and converters may be used together. converters has priority over the built-in types and default. When a function is specified as default, it is always applied as a last resort.