Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuration File for TermSet validations #1016

Merged
merged 85 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
8204c48
config
mavaylon1 Dec 11, 2023
748d305
Merge branch 'dev' into config
mavaylon1 Jan 9, 2024
bb40b5a
rough draft
mavaylon1 Jan 10, 2024
b9b52f2
move
mavaylon1 Jan 10, 2024
5fa60cd
testing
mavaylon1 Jan 11, 2024
988a442
check
mavaylon1 Jan 13, 2024
0b83e58
new way of thinking draft
mavaylon1 Jan 18, 2024
fa9e0f0
support multiple config files
mavaylon1 Jan 18, 2024
66d0752
testing
mavaylon1 Jan 18, 2024
c77e06d
placeholder'
mavaylon1 Jan 22, 2024
8353092
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 22, 2024
ed140c9
update
mavaylon1 Jan 25, 2024
0478c39
Delete docs/gallery/example_config.yaml
mavaylon1 Jan 25, 2024
e432e6d
clean up
mavaylon1 Jan 25, 2024
9e6c2e3
clean up
mavaylon1 Jan 25, 2024
fd73ae0
clean up
mavaylon1 Jan 25, 2024
6a9c956
checkpoint
mavaylon1 Jan 29, 2024
9aa468d
Merge branch 'dev' into config
mavaylon1 Jan 31, 2024
ec36ee3
need to clean
mavaylon1 Jan 31, 2024
fd8995a
partial clean up
mavaylon1 Jan 31, 2024
041099e
warn
mavaylon1 Jan 31, 2024
cec4050
Merge branch 'dev' into config
mavaylon1 Feb 28, 2024
f4e4a16
Merge branch 'dev' into config
mavaylon1 Mar 12, 2024
145513a
yaml changes
mavaylon1 Mar 12, 2024
bb4b422
revert
mavaylon1 Mar 12, 2024
55479e3
except
mavaylon1 Mar 12, 2024
3d67fbc
clean up
mavaylon1 Mar 13, 2024
5b7787a
warning tests
mavaylon1 Mar 13, 2024
e979bf8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 13, 2024
b806404
tests
mavaylon1 Mar 14, 2024
901cb56
tests
mavaylon1 Mar 14, 2024
809d511
tests
mavaylon1 Mar 14, 2024
6b99a8a
ruff
mavaylon1 Mar 14, 2024
f38ca1d
update
mavaylon1 Mar 14, 2024
57e7bf0
update
mavaylon1 Mar 14, 2024
3228671
Merge branch 'dev' into config
mavaylon1 Mar 14, 2024
2d32acf
cov
mavaylon1 Mar 14, 2024
4fd0116
tests
mavaylon1 Mar 14, 2024
39ea8c2
tests/clean
mavaylon1 Mar 15, 2024
0602a53
coverage'
mavaylon1 Mar 15, 2024
d66145d
coverage'
mavaylon1 Mar 15, 2024
eb3970b
final clean ups
mavaylon1 Mar 15, 2024
e9e26f6
final clean ups
mavaylon1 Mar 15, 2024
f6d5a55
Update CHANGELOG.md
mavaylon1 Mar 15, 2024
626a316
Update CHANGELOG.md
mavaylon1 Mar 15, 2024
9728c66
Update CHANGELOG.md
rly Mar 19, 2024
e654e3d
Update src/hdmf/container.py
rly Mar 19, 2024
ddd66ab
Update src/hdmf/container.py
rly Mar 19, 2024
5518adc
Update src/hdmf/term_set.py
rly Mar 19, 2024
790df9b
Update src/hdmf/term_set.py
rly Mar 19, 2024
6131fdb
Merge branch 'dev' into config
rly Mar 19, 2024
4f617cb
in progress
mavaylon1 Mar 19, 2024
08766d3
Update src/hdmf/container.py
mavaylon1 Mar 19, 2024
465b2a5
Update tests/unit/test_term_set.py
mavaylon1 Mar 19, 2024
9c6a451
Update tests/unit/test_term_set.py
mavaylon1 Mar 19, 2024
bdb0410
in progress
mavaylon1 Mar 19, 2024
be1752d
in progress
mavaylon1 Mar 19, 2024
46c8f9b
in progress
mavaylon1 Mar 19, 2024
3574bd0
in progress
mavaylon1 Mar 19, 2024
207683b
clean tests
mavaylon1 Mar 19, 2024
8d44588
checkpoint of updates
mavaylon1 Mar 25, 2024
c179791
checkpoint of updates
mavaylon1 Mar 25, 2024
f108c07
checkpoint of updates
mavaylon1 Mar 25, 2024
4dd5202
Merge branch 'dev' into config
mavaylon1 Mar 25, 2024
9d27717
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 25, 2024
6b19e6d
copy
mavaylon1 Mar 25, 2024
7b25393
clean up
mavaylon1 Mar 25, 2024
b2c902a
clean
mavaylon1 Mar 25, 2024
6d7369e
Update CHANGELOG.md
mavaylon1 Mar 26, 2024
14c0e1b
clean up
mavaylon1 Mar 26, 2024
e133b7f
clean up
mavaylon1 Mar 26, 2024
67d1c4f
test copy
mavaylon1 Mar 27, 2024
6ef126c
name
mavaylon1 Mar 27, 2024
2a7a048
Update CHANGELOG.md
rly Mar 28, 2024
6c28042
Update requirements-opt.txt
rly Mar 28, 2024
c7b0d5f
Update requirements-opt.txt
rly Mar 28, 2024
54b68ae
Update container.py
mavaylon1 Mar 28, 2024
2f3a51b
Update container.py
mavaylon1 Mar 28, 2024
89ab7fa
Update __init__.py
mavaylon1 Mar 28, 2024
e5eff48
Update manager.py
mavaylon1 Mar 28, 2024
5efb5e0
clean
mavaylon1 Mar 28, 2024
13ee1f4
namespace
mavaylon1 Mar 28, 2024
bcd7f21
Update src/hdmf/common/__init__.py
rly Mar 28, 2024
87c1827
Update src/hdmf/common/__init__.py
mavaylon1 Mar 28, 2024
0efd22b
Update __init__.py
rly Mar 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# HDMF Changelog

## HDMF 3.14.0 (Upcoming)

### Enhancements
- Added `TermSetConfigurator` to automatically wrap fields with `TermSetWrapper` according to a configuration file. @mavaylon1 [#1016](https://github.com/hdmf-dev/hdmf/pull/1016)

## HDMF 3.13.0 (March 20, 2024)

### Enhancements
Expand Down
6 changes: 2 additions & 4 deletions requirements-opt.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# pinned dependencies that are optional. used to reproduce an entire development environment to use HDMF
tqdm==4.66.2
zarr==2.17.1
linkml-runtime==1.7.3; python_version >= "3.9"
linkml-runtime==1.7.4; 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"
oaklib==0.5.32; python_version >= "3.9"
2 changes: 1 addition & 1 deletion src/hdmf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .container import Container, Data, DataRegion, HERDManager
from .region import ListSlicer
from .utils import docval, getargs
from .term_set import TermSet, TermSetWrapper
from .term_set import TermSet, TermSetWrapper, TypeConfigurator


@docval(
Expand Down
18 changes: 13 additions & 5 deletions src/hdmf/build/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .builders import DatasetBuilder, GroupBuilder, LinkBuilder, Builder, BaseBuilder
from .classgenerator import ClassGenerator, CustomClassGenerator, MCIClassGenerator
from ..container import AbstractContainer, Container, Data
from ..term_set import TypeConfigurator
from ..spec import DatasetSpec, GroupSpec, NamespaceCatalog
from ..spec.spec import BaseStorageSpec
from ..utils import docval, getargs, ExtenderMeta, get_docval
Expand Down Expand Up @@ -391,25 +392,32 @@ def data_type(self):


class TypeMap:
''' A class to maintain the map between ObjectMappers and AbstractContainer classes
'''
"""
A class to maintain the map between ObjectMappers and AbstractContainer classes
"""

@docval({'name': 'namespaces', 'type': NamespaceCatalog, 'doc': 'the NamespaceCatalog to use', 'default': None},
{'name': 'mapper_cls', 'type': type, 'doc': 'the ObjectMapper class to use', 'default': None})
{'name': 'mapper_cls', 'type': type, 'doc': 'the ObjectMapper class to use', 'default': None},
{'name': 'type_config', 'type': TypeConfigurator, 'doc': 'The TypeConfigurator to use.',
'default': None})
def __init__(self, **kwargs):
namespaces, mapper_cls = getargs('namespaces', 'mapper_cls', kwargs)
namespaces, mapper_cls, type_config = getargs('namespaces', 'mapper_cls', 'type_config', kwargs)
if namespaces is None:
namespaces = NamespaceCatalog()
if mapper_cls is None:
from .objectmapper import ObjectMapper # avoid circular import
mapper_cls = ObjectMapper
if type_config is None:
type_config = TypeConfigurator()
self.__ns_catalog = namespaces
self.__mappers = dict() # already constructed ObjectMapper classes
self.__mapper_cls = dict() # the ObjectMapper class to use for each container type
self.__container_types = OrderedDict()
self.__data_types = dict()
self.__default_mapper_cls = mapper_cls
self.__class_generator = ClassGenerator()
self.type_config = type_config

self.register_generator(CustomClassGenerator)
self.register_generator(MCIClassGenerator)

Expand All @@ -422,7 +430,7 @@ def container_types(self):
return self.__container_types

def __copy__(self):
ret = TypeMap(copy(self.__ns_catalog), self.__default_mapper_cls)
ret = TypeMap(copy(self.__ns_catalog), self.__default_mapper_cls, self.type_config)
ret.merge(self)
return ret

Expand Down
25 changes: 25 additions & 0 deletions src/hdmf/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@
# a global type map
global __TYPE_MAP

@docval({'name': 'config_path', 'type': str, 'doc': 'Path to the configuration file.'},
is_method=False)
def load_type_config(**kwargs):
"""
This method will either load the default config or the config provided by the path.
NOTE: This config is global and shared across all type maps.
"""
mavaylon1 marked this conversation as resolved.
Show resolved Hide resolved
config_path = kwargs['config_path']
__TYPE_MAP.type_config.load_type_config(config_path)

def get_loaded_type_config():
"""
This method returns the entire config file.
"""
if __TYPE_MAP.type_config.config is None:
msg = "No configuration is loaded."
raise ValueError(msg)

Check warning on line 39 in src/hdmf/common/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/common/__init__.py#L38-L39

Added lines #L38 - L39 were not covered by tests
else:
return __TYPE_MAP.type_config.config

Check warning on line 41 in src/hdmf/common/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/common/__init__.py#L41

Added line #L41 was not covered by tests

def unload_type_config():
"""
Unload the configuration file.
"""
return __TYPE_MAP.type_config.unload_type_config()

# a function to register a container classes with the global map
@docval({'name': 'data_type', 'type': str, 'doc': 'the data_type to get the spec for'},
Expand Down
82 changes: 77 additions & 5 deletions src/hdmf/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Type
from uuid import uuid4
from warnings import warn
import os

import h5py
import numpy as np
Expand All @@ -13,6 +14,7 @@
from .data_utils import DataIO, append_data, extend_data
from .utils import docval, get_docval, getargs, ExtenderMeta, get_data_shape, popargs, LabelledDict

from .term_set import TermSet, TermSetWrapper

def _set_exp(cls):
"""Set a class as being experimental"""
Expand All @@ -34,7 +36,7 @@
This class manages whether to set/attach an instance of HERD to the subclass.
"""

@docval({'name': 'herd', 'type': 'hdmf.common.resources.HERD',
@docval({'name': 'herd', 'type': 'HERD',
'doc': 'The external resources to be used for the container.'},)
def link_resources(self, **kwargs):
"""
Expand Down Expand Up @@ -75,7 +77,6 @@
Make a setter function for creating a :py:func:`property`
"""
name = field['name']

if not field.get('settable', True):
return None

Expand All @@ -85,10 +86,82 @@
if name in self.fields:
msg = "can't set attribute '%s' -- already set" % name
raise AttributeError(msg)
self.fields[name] = val
self.fields[name] = self._field_config(arg_name=name, val=val)

return setter

@property
def data_type(self):
"""
Return the spec data type associated with this container.
"""
return getattr(self, self._data_type_attr)

Check warning on line 98 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L98

Added line #L98 was not covered by tests


def _field_config(self, arg_name, val):
"""
This method will be called in the setter. The termset configuration will be used (if loaded)
to check for a defined TermSet associated with the field. If found, the value of the field
will be wrapped with a TermSetWrapper.

Even though the path field in the configurator can be a list of paths, the config
itself is only one file. When a user loads custom configs, the config is appended/modified.
The modifications are not written to file, avoiding permanent modifications.
"""
# load termset configuration file from global Config
from hdmf.common import get_type_map # circular import
type_map = get_type_map()
configurator = type_map.type_config

if len(configurator.path)>0:
# The type_map has a config always set; however, when toggled off, the config path is empty.
CUR_DIR = os.path.dirname(os.path.realpath(configurator.path[0]))
termset_config = configurator.config

Check warning on line 119 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L118-L119

Added lines #L118 - L119 were not covered by tests
else:
return val
# check to see that the namespace for the container is in the config
if self.namespace not in type_map.container_types:
msg = "%s not found within loaded configuration." % self.namespace
warn(msg)
return val

Check warning on line 126 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L124-L126

Added lines #L124 - L126 were not covered by tests
else:
# check to see that the container type is in the config under the namespace
config_namespace = termset_config['namespaces'][self.namespace]
data_type = self.data_type

Check warning on line 130 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L129-L130

Added lines #L129 - L130 were not covered by tests

if data_type not in config_namespace['data_types']:
msg = '%s not found within the configuration for %s' % (data_type, self.namespace)
warn(msg)
return val

Check warning on line 135 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L133-L135

Added lines #L133 - L135 were not covered by tests
else:
for attr in config_namespace['data_types'][data_type]:
obj_mapper = type_map.get_map(self)

Check warning on line 138 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L138

Added line #L138 was not covered by tests

# get the spec according to attr name in schema
# Note: this is the name for the field in the config
spec = obj_mapper.get_attr_spec(attr)

Check warning on line 142 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L142

Added line #L142 was not covered by tests

# In the case of dealing with datasets directly or not defined in the spec.
# (Data/VectorData/DynamicTable/etc)
if spec is None:
msg = "Spec not found for %s." % attr
warn(msg)
return val

Check warning on line 149 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L147-L149

Added lines #L147 - L149 were not covered by tests
else:
# If the val has been manually wrapped then skip checking the config for the attr
if isinstance(val, TermSetWrapper):
msg = "Field value already wrapped with TermSetWrapper."
warn(msg)
return val

Check warning on line 155 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L153-L155

Added lines #L153 - L155 were not covered by tests
else:
# From the spec, get the mapped attribute name
mapped_attr_name = obj_mapper.get_attribute(spec)
termset_path = os.path.join(CUR_DIR,

Check warning on line 159 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L158-L159

Added lines #L158 - L159 were not covered by tests
config_namespace['data_types'][data_type][mapped_attr_name]['termset'])
termset = TermSet(term_schema_path=termset_path)
val = TermSetWrapper(value=val, termset=termset)
return val

Check warning on line 163 in src/hdmf/container.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/container.py#L161-L163

Added lines #L161 - L163 were not covered by tests

@classmethod
def _getter(cls, field):
"""
Expand Down Expand Up @@ -389,7 +462,7 @@
def children(self):
return tuple(self.__children)

@docval({'name': 'child', 'type': 'hdmf.container.Container',
@docval({'name': 'child', 'type': 'Container',
'doc': 'the child Container for this Container', 'default': None})
def add_child(self, **kwargs):
warn(DeprecationWarning('add_child is deprecated. Set the parent attribute instead.'))
Expand Down Expand Up @@ -787,7 +860,6 @@
"""
A class for representing dataset containers
"""

@docval({'name': 'name', 'type': str, 'doc': 'the name of this container'},
{'name': 'data', 'type': ('scalar_data', 'array_data', 'data'), 'doc': 'the source of the data'})
def __init__(self, **kwargs):
Expand Down
87 changes: 79 additions & 8 deletions src/hdmf/term_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import warnings
import numpy as np
from .data_utils import append_data, extend_data
from ruamel.yaml import YAML


class TermSet:
Expand Down Expand Up @@ -162,19 +163,20 @@
This method returns a path to the new schema to be viewed via SchemaView.
"""
try:
import yaml
from linkml_runtime.utils.schema_as_dict import schema_as_dict
from schemasheets.schemamaker import SchemaMaker
except ImportError: # pragma: no cover
msg = "Install schemasheets."
raise ValueError(msg)

schema_maker = SchemaMaker()
tsv_file_paths = glob.glob(self.schemasheets_folder + "/*.tsv")
schema = schema_maker.create_schema(tsv_file_paths)
schema_dict = schema_as_dict(schema)
schemasheet_schema_path = os.path.join(self.schemasheets_folder, f"{schema_dict['name']}.yaml")

with open(schemasheet_schema_path, "w") as f:
yaml=YAML(typ='safe')

Check warning on line 179 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L179

Added line #L179 was not covered by tests
yaml.dump(schema_dict, f)

return schemasheet_schema_path
Expand Down Expand Up @@ -262,13 +264,6 @@
"""
return self.__value[val]

# uncomment when DataChunkIterator objects can be wrapped by TermSet
# def __next__(self):
# """
# Return the next item of a wrapped iterator.
# """
# return self.__value.__next__()
#
def __len__(self):
return len(self.__value)

Expand Down Expand Up @@ -304,3 +299,79 @@
else:
msg = ('"%s" is not in the term set.' % ', '.join([str(item) for item in bad_data]))
raise ValueError(msg)

class TypeConfigurator:
"""
This class allows users to toggle on/off a global configuration for defined data types.
When toggled on, every instance of a configuration file supported data type will be validated
according to the corresponding TermSet.
"""
@docval({'name': 'path', 'type': str, 'doc': 'Path to the configuration file.', 'default': None})
def __init__(self, **kwargs):
self.config = None
if kwargs['path'] is None:
self.path = []
else:
self.path = [kwargs['path']]
self.load_type_config(config_path=self.path[0])

Check warning on line 316 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L315-L316

Added lines #L315 - L316 were not covered by tests

@docval({'name': 'data_type', 'type': str,
'doc': 'The desired data type within the configuration file.'},
{'name': 'namespace', 'type': str,
'doc': 'The namespace for the data type.'})
def get_config(self, data_type, namespace):
"""
Return the config for that data type in the given namespace.
"""
try:
namespace_config = self.config['namespaces'][namespace]
except KeyError:
msg = 'The namespace %s was not found within the configuration.' % namespace
raise ValueError(msg)

Check warning on line 330 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L326-L330

Added lines #L326 - L330 were not covered by tests

try:
type_config = namespace_config['data_types'][data_type]
return type_config
except KeyError:
msg = '%s was not found within the configuration for that namespace.' % data_type
raise ValueError(msg)

Check warning on line 337 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L332-L337

Added lines #L332 - L337 were not covered by tests

@docval({'name': 'config_path', 'type': str, 'doc': 'Path to the configuration file.'})
def load_type_config(self,config_path):
"""
Load the configuration file for validation on the fields defined for the objects within the file.
"""
with open(config_path, 'r') as config:
yaml=YAML(typ='safe')
termset_config = yaml.load(config)
if self.config is None: # set the initial config/load after config has been unloaded
self.config = termset_config
if len(self.path)==0: # for loading after an unloaded config
self.path.append(config_path)
else: # append/replace to the existing config
if config_path in self.path:
msg = 'This configuration file path already exists within the configurator.'
raise ValueError(msg)

Check warning on line 354 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L353-L354

Added lines #L353 - L354 were not covered by tests
else:
for namespace in termset_config['namespaces']:
if namespace not in self.config['namespaces']: # append namespace config if not present
self.config['namespaces'][namespace] = termset_config['namespaces'][namespace]

Check warning on line 358 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L358

Added line #L358 was not covered by tests
else: # check for any needed overrides within existing namespace configs
for data_type in termset_config['namespaces'][namespace]['data_types']:
# NOTE: these two branches effectively do the same thing, but are split for clarity.
if data_type in self.config['namespaces'][namespace]['data_types']:
replace_config = termset_config['namespaces'][namespace]['data_types'][data_type]
self.config['namespaces'][namespace]['data_types'][data_type] = replace_config

Check warning on line 364 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L363-L364

Added lines #L363 - L364 were not covered by tests
else: # append to config
new_config = termset_config['namespaces'][namespace]['data_types'][data_type]
self.config['namespaces'][namespace]['data_types'][data_type] = new_config

Check warning on line 367 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L366-L367

Added lines #L366 - L367 were not covered by tests
mavaylon1 marked this conversation as resolved.
Show resolved Hide resolved

# append path to self.path
self.path.append(config_path)

Check warning on line 370 in src/hdmf/term_set.py

View check run for this annotation

Codecov / codecov/patch

src/hdmf/term_set.py#L370

Added line #L370 was not covered by tests

def unload_type_config(self):
"""
Remove validation according to termset configuration file.
"""
self.path = []
self.config = None
14 changes: 13 additions & 1 deletion tests/unit/common/test_common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from hdmf import Data, Container
from hdmf.common import get_type_map
from hdmf.common import get_type_map, load_type_config, unload_type_config
from hdmf.testing import TestCase


Expand All @@ -11,3 +11,15 @@ def test_base_types(self):
self.assertIs(cls, Container)
cls = tm.get_dt_container_cls('Data', 'hdmf-common')
self.assertIs(cls, Data)

def test_copy_ts_config(self):
path = 'tests/unit/hdmf_config.yaml'
load_type_config(config_path=path)
tm = get_type_map()
config = {'namespaces': {'hdmf-common': {'version': '3.12.2',
'data_types': {'VectorData': {'description': {'termset': 'example_test_term_set.yaml'}},
'VectorIndex': {'data': '...'}}}}}

self.assertEqual(tm.type_config.config, config)
self.assertEqual(tm.type_config.path, [path])
unload_type_config()
Loading
Loading