diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7a71e00..f35a06cd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## HDMF 3.13.0 (March 20, 2024) ### Enhancements +- Unwrap `TermSetWrapper` within the builder to support different backends more efficiently. @mavaylon1 [#1070](https://github.com/hdmf-dev/hdmf/pull/1070) - Added docs page that lists limitations of support for the HDMF specification language. @rly [#1069](https://github.com/hdmf-dev/hdmf/pull/1069) - Added warning when using `add_row` or `add_column` to add a ragged array to `DynamicTable` without an index parameter. @stephprince [#1066](https://github.com/hdmf-dev/hdmf/pull/1066) diff --git a/src/hdmf/backends/hdf5/h5tools.py b/src/hdmf/backends/hdf5/h5tools.py index 7a644f0b7..05ce36e13 100644 --- a/src/hdmf/backends/hdf5/h5tools.py +++ b/src/hdmf/backends/hdf5/h5tools.py @@ -17,7 +17,6 @@ from ...build import (Builder, GroupBuilder, DatasetBuilder, LinkBuilder, BuildManager, RegionBuilder, ReferenceBuilder, TypeMap, ObjectMapper) from ...container import Container -from ...term_set import TermSetWrapper from ...data_utils import AbstractDataChunkIterator from ...spec import RefSpec, DtypeSpec, NamespaceCatalog from ...utils import docval, getargs, popargs, get_data_shape, get_docval, StrDataset @@ -1103,10 +1102,6 @@ def write_dataset(self, **kwargs): # noqa: C901 data = data.data else: options['io_settings'] = {} - if isinstance(data, TermSetWrapper): - # This is for when the wrapped item is a dataset - # (refer to objectmapper.py for wrapped attributes) - data = data.value attributes = builder.attributes options['dtype'] = builder.dtype dset = None diff --git a/src/hdmf/build/objectmapper.py b/src/hdmf/build/objectmapper.py index b8e50d104..fed678d41 100644 --- a/src/hdmf/build/objectmapper.py +++ b/src/hdmf/build/objectmapper.py @@ -752,7 +752,11 @@ def build(self, **kwargs): % (container.__class__.__name__, container.name, repr(source))) try: # use spec_dtype from self.spec when spec_ext does not specify dtype - bldr_data, dtype = self.convert_dtype(spec, container.data, spec_dtype=spec_dtype) + if isinstance(container.data, TermSetWrapper): + data = container.data.value + else: + data = container.data + bldr_data, dtype = self.convert_dtype(spec, data, spec_dtype=spec_dtype) except Exception as ex: msg = 'could not resolve dtype for %s \'%s\'' % (type(container).__name__, container.name) raise Exception(msg) from ex diff --git a/tests/unit/build_tests/mapper_tests/test_build.py b/tests/unit/build_tests/mapper_tests/test_build.py index 8590f29f2..b90ad6f1a 100644 --- a/tests/unit/build_tests/mapper_tests/test_build.py +++ b/tests/unit/build_tests/mapper_tests/test_build.py @@ -1,7 +1,8 @@ from abc import ABCMeta, abstractmethod import numpy as np -from hdmf import Container, Data +from hdmf import Container, Data, TermSet, TermSetWrapper +from hdmf.common import VectorData, get_type_map from hdmf.build import ObjectMapper, BuildManager, TypeMap, GroupBuilder, DatasetBuilder from hdmf.build.warnings import DtypeConversionWarning from hdmf.spec import GroupSpec, AttributeSpec, DatasetSpec, SpecCatalog, SpecNamespace, NamespaceCatalog, Spec @@ -10,6 +11,29 @@ from tests.unit.helpers.utils import CORE_NAMESPACE +try: + import linkml_runtime # noqa: F401 + LINKML_INSTALLED = True +except ImportError: + LINKML_INSTALLED = False + + +class TestUnwrapTermSetWrapperBuild(TestCase): + """ + Test the unwrapping of TermSetWrapper on regular datasets within build. + """ + def setUp(self): + if not LINKML_INSTALLED: + self.skipTest("optional LinkML module is not installed") + + def test_unwrap(self): + manager = BuildManager(get_type_map()) + terms = TermSet(term_schema_path='tests/unit/example_test_term_set.yaml') + build = manager.build(VectorData(name='test_data', + description='description', + data=TermSetWrapper(value=['Homo sapiens'], termset= terms))) + + self.assertEqual(build.data, ['Homo sapiens']) # TODO: test build of extended group/dataset that modifies an attribute dtype (commented out below), shape, value, etc. # by restriction. also check that attributes cannot be deleted or scope expanded.