diff --git a/.github/PULL_REQUEST_TEMPLATE/release.md b/.github/PULL_REQUEST_TEMPLATE/release.md index 11bd20bfa..7c5ff5ece 100644 --- a/.github/PULL_REQUEST_TEMPLATE/release.md +++ b/.github/PULL_REQUEST_TEMPLATE/release.md @@ -10,7 +10,7 @@ Prepare for release of HDMF [version] and any other locations as needed - [ ] Update `pyproject.toml` as needed - [ ] Update `README.rst` as needed -- [ ] Update `src/hdmf/common/hdmf-common-schema` submodule as needed. Check the version number and commit SHA manually +- [ ] Update `src/hdmf/common/hdmf-common-schema` submodule as needed. Check the version number and commit SHA manually. Make sure we are using the latest release and not the latest commit on the `main` branch. - [ ] Update changelog (set release date) in `CHANGELOG.md` and any other docs as needed - [ ] Run tests locally including gallery tests, and inspect all warnings and outputs (`pytest && python test_gallery.py`) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c421b14..38ec80c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # HDMF Changelog -## HDMF 3.13.0 (Upcoming) +## HDMF 3.13.0 (March 20, 2024) ### Enhancements - Updated `TermSetWrapper` to support validating a single field within a compound array. @mavaylon1 [#1061](https://github.com/hdmf-dev/hdmf/pull/1061) +- 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/pyproject.toml b/pyproject.toml index ee8037be5..b60ae6943 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "License :: OSI Approved :: BSD License", "Development Status :: 5 - Production/Stable", "Operating System :: OS Independent", diff --git a/requirements-dev.txt b/requirements-dev.txt index f61962728..1d856e4e7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,7 @@ # compute coverage, and create test environments. note that depending on the version of python installed, different # versions of requirements may be installed due to package incompatibilities. # -black==23.10.1 +black==24.3.0 codespell==2.2.6 coverage==7.3.2 pre-commit==3.5.0 diff --git a/requirements-opt.txt b/requirements-opt.txt index 644fc80be..6b4e102f1 100644 --- a/requirements-opt.txt +++ b/requirements-opt.txt @@ -1,8 +1,8 @@ # pinned dependencies that are optional. used to reproduce an entire development environment to use HDMF -tqdm==4.66.1 -zarr==2.16.1 -linkml-runtime==1.6.0; python_version >= "3.9" -schemasheets==0.1.24; python_version >= "3.9" -oaklib==0.5.20; python_version >= "3.9" -pydantic==1.10.13 # linkml-runtime 1.6.0 and related packages require pydantic<2 +tqdm==4.66.2 +zarr==2.17.1 +linkml-runtime==1.7.3; python_version >= "3.9" +schemasheets==0.2.1; python_version >= "3.9" +oaklib==0.5.31; python_version >= "3.9" +pydantic==2.6.4 pyyaml==6.0.1; python_version >= "3.9" 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.