NeurodataWithoutBorders / nwb-schema

Data format specification schema for the NWB neurophysiology data format
http://nwb-schema.readthedocs.io
Other
53 stars 16 forks source link

extensions cannot inherit from MultiContainerInterface #257

Closed bendichter closed 5 years ago

bendichter commented 5 years ago
from pynwb import load_namespaces
from pynwb.spec import NWBNamespaceBuilder, NWBGroupSpec, NWBAttributeSpec

name = 'test_multicontainerinterface'
ns_path = name + ".namespace.yaml"
ext_source = name + ".extensions.yaml"

ns_builder = NWBNamespaceBuilder(name + ' extensions', name)
ns_builder.include_type('NWBDataInterface', namespace='core')
ns_builder.include_type('MultiContainerInterface', namespace='core')

potato = NWBGroupSpec(neurodata_type_def='Potato',
                      neurodata_type_inc='NWBDataInterface',
                      doc='object to put in a multi-container', quantity='*',
                      attributes=[
                          NWBAttributeSpec(name='weight',
                                           doc='weight of potato',
                                           dtype='float',
                                           required=True),
                          NWBAttributeSpec(name='age',
                                           doc='age of potato',
                                           dtype='float',
                                           required=False),
                          NWBAttributeSpec(name='help',
                                           doc='help',
                                           dtype='text',
                                           value="It's a potato")
                      ])

potato_sack = NWBGroupSpec(neurodata_type_def='PotatoSack',
                           neurodata_type_inc='MultiContainerInterface',
                           name='potato_sack',
                           doc='test of multi-container', quantity='?',
                           groups=[potato],
                           attributes=[
                               NWBAttributeSpec(name='help',
                                                doc='help',
                                                dtype='text',
                                                value="It's a sack of potatoes")
                           ])

ns_builder.add_spec(ext_source, potato_sack)
ns_builder.export(ns_path)

load_namespaces(ns_path)

error:

Traceback (most recent call last):
  File "/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3296, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-8-eb3f6cba267f>", line 45, in <module>
    load_namespaces(ns_path)
  File "/Users/bendichter/dev/hdmf/src/hdmf/utils.py", line 396, in func_call
    return func(**parsed['args'])
  File "/Users/bendichter/dev/pynwb/src/pynwb/__init__.py", line 106, in load_namespaces
    return __TYPE_MAP.load_namespaces(namespace_path)
  File "/Users/bendichter/dev/hdmf/src/hdmf/utils.py", line 381, in func_call
    return func(self, **parsed['args'])
  File "/Users/bendichter/dev/hdmf/src/hdmf/build/map.py", line 1264, in load_namespaces
    deps = call_docval_func(self.__ns_catalog.load_namespaces, kwargs)
  File "/Users/bendichter/dev/hdmf/src/hdmf/utils.py", line 274, in call_docval_func
    return func(*fargs, **fkwargs)
  File "/Users/bendichter/dev/hdmf/src/hdmf/utils.py", line 381, in func_call
    return func(self, **parsed['args'])
  File "/Users/bendichter/dev/hdmf/src/hdmf/spec/namespace.py", line 457, in load_namespaces
    ret[ns['name']] = self.__load_namespace(ns, reader, types_key, resolve=resolve)
  File "/Users/bendichter/dev/hdmf/src/hdmf/spec/namespace.py", line 416, in __load_namespace
    spec = inc_ns.get_spec(ndt)
  File "/Users/bendichter/dev/hdmf/src/hdmf/utils.py", line 381, in func_call
    return func(self, **parsed['args'])
  File "/Users/bendichter/dev/hdmf/src/hdmf/spec/namespace.py", line 140, in get_spec
    raise ValueError("No specification for '%s' in namespace '%s'" % (data_type, self.name))
ValueError: No specification for 'MultiContainerInterface' in namespace 'core'

Do we want types to be able to inherit from MultiContainerInterface? To fix this, we'd have to define it in nwb.base.yaml and register it in core.py

oruebel commented 5 years ago

As far as I understand MultiContainerInterface is a class in PyNWB to help implement interface classes for NWBDataInterface types that contain a collection of specific set of neurodata_types, e.g., the LFP type containing a set of ElectricalSeries. From the perspective of the format specification, I don't think there is really anything particular about MultiContainerInterface that is different from NWBDataInterface. The difference lies really in functionality on the API side, rather than the structure in the spec. As such, I think the current structure makes sense, i.e.., in the format specification you have to inherit from NWBDataInterface and then on the API side you can implement it via MultiContainerInterface.

bendichter commented 5 years ago

I was trying to get this working for auto-generation of classes with get_class but now that I think about it I don't think it's necessary. Besides, matnwb manages to auto-generate these with the current schema, and I'd rather be similar to them where possible.