Skip to content

Commit

Permalink
Always use parent names in autogenerated child spec names (#130)
Browse files Browse the repository at this point in the history
* Always use parent names in autogenerated child spec names, use __

* Add custom object mapper in tests
  • Loading branch information
rly authored Aug 5, 2019
1 parent 38e572d commit 68003ce
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 9 deletions.
8 changes: 2 additions & 6 deletions src/hdmf/build/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,12 @@ def __get_fields(cls, name_stack, all_names, spec):
if spec.name is None:
name = cls.convert_dt_name(spec)
name_stack.append(name)
if name in all_names:
name = "_".join(name_stack)
name = '__'.join(name_stack)
all_names[name] = spec
if isinstance(spec, BaseStorageSpec):
if not (spec.data_type_def is None and spec.data_type_inc is None):
# don't get names for components in data_types
name_stack.pop()
return
for subspec in spec.attributes:
cls.__get_fields(name_stack, all_names, subspec)
Expand Down Expand Up @@ -643,10 +643,6 @@ def __map_spec(self, spec):
def map_attr(self, **kwargs):
""" Map an attribute to spec. Use this to override default behavior """
attr_name, spec = getargs('attr_name', 'spec', kwargs)
if hasattr(spec, 'name') and spec.name is not None:
n = spec.name
elif hasattr(spec, 'data_type_def') and spec.data_type_def is not None:
n = spec.data_type_def # noqa: F841
self.__spec2attr[spec] = attr_name
self.__attr2spec[attr_name] = spec

Expand Down
36 changes: 34 additions & 2 deletions tests/unit/build_tests/test_io_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
from tests.unit.test_utils import Foo, FooBucket, CORE_NAMESPACE


class FooMapper(ObjectMapper):
"""Maps nested 'attr2' attribute on dataset 'my_data' to Foo.attr2 in constructor and attribute map
"""

def __init__(self, spec):
super(FooMapper, self).__init__(spec)
my_data_spec = spec.get_dataset('my_data')
self.map_spec('attr2', my_data_spec.get_attribute('attr2'))


class TestBase(unittest.TestCase):

def setUp(self):
Expand All @@ -37,7 +47,7 @@ def setUp(self):
self.namespace_catalog.add_namespace(CORE_NAMESPACE, self.namespace)
self.type_map = TypeMap(self.namespace_catalog)
self.type_map.register_container_type(CORE_NAMESPACE, 'Foo', Foo)
self.type_map.register_map(Foo, ObjectMapper)
self.type_map.register_map(Foo, FooMapper)
self.manager = BuildManager(self.type_map)


Expand Down Expand Up @@ -130,7 +140,7 @@ def setUp(self):

self.spec_catalog.register_spec(self.bucket_spec, 'test.yaml')
self.type_map.register_container_type(CORE_NAMESPACE, 'FooBucket', FooBucket)
self.type_map.register_map(FooBucket, ObjectMapper)
self.type_map.register_map(FooBucket, self.setUpBucketMapper())
self.manager = BuildManager(self.type_map)

def setUpBucketBuilder(self):
Expand All @@ -139,6 +149,9 @@ def setUpBucketBuilder(self):
def setUpBucketSpec(self):
raise unittest.SkipTest('Abstract Base Class')

def setUpBucketMapper(self):
raise unittest.SkipTest('Abstract Base Class')

def test_build(self):
''' Test default mapping for an Container that has an Container as an attribute value '''
builder = self.manager.build(self.foo_bucket)
Expand Down Expand Up @@ -171,6 +184,9 @@ def setUpBucketSpec(self):
data_type_inc='Foo',
quantity=ZERO_OR_MANY)])

def setUpBucketMapper(self):
return ObjectMapper


class TestNestedContainersSubgroup(TestNestedBase):
'''
Expand All @@ -197,6 +213,14 @@ def setUpBucketSpec(self):
data_type_def='FooBucket',
groups=[tmp_spec])

def setUpBucketMapper(self):
class BucketMapper(ObjectMapper):
def __init__(self, spec):
super(BucketMapper, self).__init__(spec)
self.map_spec('foos', spec.get_group('foo_holder').get_data_type('Foo'))

return BucketMapper


class TestNestedContainersSubgroupSubgroup(TestNestedBase):
'''
Expand Down Expand Up @@ -225,6 +249,14 @@ def setUpBucketSpec(self):
data_type_def='FooBucket',
groups=[tmp_spec])

def setUpBucketMapper(self):
class BucketMapper(ObjectMapper):
def __init__(self, spec):
super(BucketMapper, self).__init__(spec)
self.map_spec('foos', spec.get_group('foo_holder_holder').get_group('foo_holder').get_data_type('Foo'))

return BucketMapper


class TestTypeMap(TestBase):

Expand Down
15 changes: 14 additions & 1 deletion tests/unit/build_tests/test_io_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ def test_build(self):
expected = GroupBuilder('my_bar', datasets={'data': DatasetBuilder(
'data', list(range(10)), attributes={'attr2': 10})},
attributes={'attr1': 'value1'})
self._remap_nested_attr()
builder = self.mapper.build(container_inst, self.manager)
self.assertDictEqual(builder, expected)

Expand All @@ -359,15 +360,27 @@ def test_construct(self):
'data', list(range(10)), attributes={'attr2': 10})},
attributes={'attr1': 'value1', 'data_type': 'Bar', 'namespace': CORE_NAMESPACE,
'object_id': expected.object_id})
self._remap_nested_attr()
container = self.mapper.construct(builder, self.manager)
self.assertEqual(container, expected)

def test_default_mapping_keys(self):
attr_map = self.mapper.get_attr_names(self.bar_spec)
keys = set(attr_map.keys())
expected = {'attr1', 'data', 'attr2'}
expected = {'attr1', 'data', 'data__attr2'}
self.assertSetEqual(keys, expected)

def test_remap_keys(self):
self._remap_nested_attr()
self.assertEqual(self.mapper.get_attr_spec('attr2'),
self.mapper.spec.get_dataset('data').get_attribute('attr2'))
self.assertEqual(self.mapper.get_attr_spec('attr1'), self.mapper.spec.get_attribute('attr1'))
self.assertEqual(self.mapper.get_attr_spec('data'), self.mapper.spec.get_dataset('data'))

def _remap_nested_attr(self):
data_spec = self.mapper.spec.get_dataset('data')
self.mapper.map_spec('attr2', data_spec.get_attribute('attr2'))


class TestObjectMapperNoNesting(TestObjectMapper):

Expand Down
7 changes: 7 additions & 0 deletions tests/unit/test_io_hdf5_h5tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ def _get_manager():
data_type_def='FooBucket',
groups=[tmp_spec])

class FooMapper(ObjectMapper):
def __init__(self, spec):
super(FooMapper, self).__init__(spec)
my_data_spec = spec.get_dataset('my_data')
self.map_spec('attr2', my_data_spec.get_attribute('attr2'))

class BucketMapper(ObjectMapper):
def __init__(self, spec):
super(BucketMapper, self).__init__(spec)
Expand Down Expand Up @@ -461,6 +467,7 @@ def __init__(self, spec):
type_map.register_container_type(CORE_NAMESPACE, 'FooBucket', FooBucket)
type_map.register_container_type(CORE_NAMESPACE, 'FooFile', FooFile)

type_map.register_map(Foo, FooMapper)
type_map.register_map(FooBucket, BucketMapper)
type_map.register_map(FooFile, FileMapper)

Expand Down

0 comments on commit 68003ce

Please sign in to comment.