asdf-format/asdf

asdf odd handling of `namedtuple` that prevents implementing a `Converter`

Opened this issue · 0 comments

Attempts to store a namedtuple instance in the tree result in behavior that doesn't match with other custom objects.

import collections
import asdf

NT = collections.namedtuple("NT", ("a", "b"))
nt = NT(1, 2)
af = asdf.AsdfFile({"nt": nt})
print(type(af['nt']))

produces

/Users/bgraham/projects/240103_named_tuple/asdf/asdf/treeutil.py:360: AsdfWarning: Failed to serialize instance of <class '__main__.NT'>, converting to list instead
  warnings.warn(f"Failed to serialize instance of {type(node)}, converting to list instead", AsdfWarning)
<class 'list'>

The warning can be silenced by passing ignore_implicit_conversion=True when creating the AsdfFile instance.

The conversion to a list loses the by-name item access possible with namedtuple.

This prevents creation of any Converter to support a specific namedtuple.

If the following line is changed to use type(node) == tuple:

elif isinstance(node, tuple):

it becomes possible to put namedtuple instances in the tree and to implement Converter instances for specific namedtuple classes. See the following:

import collections
import asdf


NT = collections.namedtuple("NT", ("a", "b"))
nt = NT(1, 2)

nt_tag = "asdf://example.com/tags/nt-1.0.0"


class NTConverter:
    types = [NT]
    tags = [nt_tag]

    def to_yaml_tree(self, obj, tag, ctx):
        return obj._asdict()

    def from_yaml_tree(self, obj, tag, ctx):
        return NT(**obj)


class NTExtension:
    converters=[NTConverter()]
    tags=[nt_tag]
    extension_uri = "asdf://example.com/extensions/nt-1.0.0"


with asdf.config_context() as cfg:
    cfg.add_extension(NTExtension())

    af = asdf.AsdfFile({"nt": nt})
    assert type(af["nt"]) == NT
    af.write_to("test.asdf")

    with asdf.open("test.asdf") as af:
        assert type(af["nt"]) == NT

In summary, the current way that namedtuple is supported seems incomplete and hinders customization by users.

I propose that we deprecate ignore_implicit_conversion drop our current "support" for namedtuple and allow users to implement Converter instances for any namedtuples they would like to serialize/deserialize.