Skip to content

Commit

Permalink
improve error when an object fails to serialize
Browse files Browse the repository at this point in the history
  • Loading branch information
braingram committed Jul 22, 2024
1 parent b8ba0ad commit c6acfae
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 18 deletions.
5 changes: 2 additions & 3 deletions asdf/_tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@

import pytest
from packaging.specifiers import SpecifierSet
from yaml.representer import RepresenterError

import asdf
from asdf import AsdfFile, config_context
from asdf.exceptions import AsdfManifestURIMismatchWarning, AsdfWarning, ValidationError
from asdf.exceptions import AsdfManifestURIMismatchWarning, AsdfSerializationError, AsdfWarning, ValidationError
from asdf.extension import (
Compressor,
Converter,
Expand Down Expand Up @@ -578,7 +577,7 @@ class FooExtension(Extension):
tree = {"obj": Foo()}
with config_context() as cfg:
cfg.add_extension(FooExtension())
with pytest.raises(RepresenterError, match=r"cannot represent an object"):
with pytest.raises(AsdfSerializationError, match=r"is not serializable by asdf"):
roundtrip_object(tree)


Expand Down
6 changes: 3 additions & 3 deletions asdf/_tests/test_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import asdf
from asdf import tagged, treeutil, yamlutil
from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfWarning
from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfSerializationError, AsdfWarning
from asdf.testing.helpers import yaml_to_asdf


Expand Down Expand Up @@ -104,7 +104,7 @@ class Foo:

buff = io.BytesIO()
ff = asdf.AsdfFile(tree)
with pytest.raises(yaml.YAMLError, match=r"\('cannot represent an object', .*\)"):
with pytest.raises(AsdfSerializationError, match=r".*is not serializable by asdf.*"):
ff.write_to(buff)


Expand Down Expand Up @@ -350,7 +350,7 @@ class MyNDArray(np.ndarray):

with asdf.config.config_context() as cfg:
cfg.convert_unknown_ndarray_subclasses = False
with pytest.raises(yaml.representer.RepresenterError, match=r".*cannot represent.*"):
with pytest.raises(AsdfSerializationError, match=r".*is not serializable by asdf.*"):
af.write_to(fn)


Expand Down
10 changes: 10 additions & 0 deletions asdf/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from yaml.representer import RepresenterError

from asdf._jsonschema import ValidationError

__all__ = [
Expand Down Expand Up @@ -73,3 +75,11 @@ class AsdfLazyReferenceError(ReferenceError):
collected and you may need to update your code to keep the AsdfFile
in memory (by keeping a reference).
"""


class AsdfSerializationError(RepresenterError):
"""
An object failed serialization by asdf and by yaml. This likely indicates
that the object does not have a supporting asdf Converter and needs to
be manually converted to a supported type.
"""
36 changes: 24 additions & 12 deletions asdf/yamlutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from . import config, schema, tagged, treeutil, util
from .constants import STSCI_SCHEMA_TAG_BASE, YAML_TAG_PREFIX
from .exceptions import AsdfConversionWarning
from .exceptions import AsdfConversionWarning, AsdfSerializationError
from .extension._serialization_context import BlockAccess
from .tags.core import AsdfObject
from .versioning import _YAML_VERSION, _yaml_base_loader
Expand Down Expand Up @@ -403,14 +403,26 @@ def dump_tree(tree, fd, ctx, tree_finalizer=None, _serialization_context=None):
if key not in tags:
tags[key] = val

yaml.dump_all(
[tree],
stream=fd,
Dumper=AsdfDumper,
explicit_start=True,
explicit_end=True,
version=_YAML_VERSION,
allow_unicode=True,
encoding="utf-8",
tags=tags,
)
try:
yaml.dump_all(
[tree],
stream=fd,
Dumper=AsdfDumper,
explicit_start=True,
explicit_end=True,
version=_YAML_VERSION,
allow_unicode=True,
encoding="utf-8",
tags=tags,
)
except yaml.representer.RepresenterError as err:
if len(err.args) < 2:
raise err
# inspect the exception arguments to determine what object failed
obj = err.args[1]
msg = (
f"Object of type[{type(obj)}] is not serializable by asdf. "
"Please convert the object to a supported type or implement "
"a Converter for this type to allow the tree to be serialized."
)
raise AsdfSerializationError(msg, obj) from err

0 comments on commit c6acfae

Please sign in to comment.