Source code for pynwb.core

from warnings import warn

import numpy as np

from hdmf import Container, Data
from hdmf.container import AbstractContainer, MultiContainerInterface as hdmf_MultiContainerInterface, Table
from hdmf.common import DynamicTable, DynamicTableRegion  # noqa: F401
from hdmf.common import VectorData, VectorIndex, ElementIdentifiers  # noqa: F401
from hdmf.utils import docval, popargs, AllowPositional
from hdmf.utils import LabelledDict  # noqa: F401

from . import CORE_NAMESPACE, register_class
from pynwb import get_type_map


__all__ = [
    'NWBMixin',
    'NWBContainer',
    'NWBDataInterface',
    'NWBData',
    'ScratchData',
    'NWBTable',
    'MultiContainerInterface'
]


[docs] class NWBMixin(AbstractContainer): _data_type_attr = 'neurodata_type' _fieldsname = '__nwbfields__' __nwbfields__ = tuple()
[docs] @docval({'name': 'neurodata_type', 'type': str, 'doc': 'the data_type to search for', 'default': None}) def get_ancestor(self, **kwargs): """ Traverse parent hierarchy and return first instance of the specified data_type """ neurodata_type = kwargs['neurodata_type'] return super().get_ancestor(data_type=neurodata_type)
def _error_on_new_warn_on_construct(self, error_msg: str): """ Raise an error when a check is violated on instance creation. To ensure backwards compatibility, this method throws a warning instead of raising an error when reading from a file, ensuring that files with invalid data can be read. """ if not self._in_construct_mode: raise ValueError(error_msg) warn(error_msg) def _error_on_new_pass_on_construct(self, error_msg: str): """ Raise an error when a check is violated on instance creation. When reading from a file, do nothing, ensuring that files with invalid data or deprecated neurodata types can be read. """ if not self._in_construct_mode: raise ValueError(error_msg) def _warn_on_new_pass_on_construct(self, warn_msg: str): """ Issue a warning when a check is violated on instance creation. When reading from a file, do nothing, ensuring that files with deprecated neurodata types can be read without warnings. """ if not self._in_construct_mode: warn(warn_msg) def _get_type_map(self): return get_type_map(copy=False) @property def data_type(self): """ Return the spec data type associated with this container, i.e., the neurodata_type. """ # we need this function here to use the correct _data_type_attr. _type = getattr(self, self._data_type_attr) return _type
[docs] @register_class('NWBContainer', CORE_NAMESPACE) class NWBContainer(NWBMixin, Container): pass
[docs] @register_class('NWBDataInterface', CORE_NAMESPACE) class NWBDataInterface(NWBContainer): pass
[docs] @register_class('NWBData', CORE_NAMESPACE) class NWBData(NWBMixin, Data): @docval({'name': 'name', 'type': str, 'doc': 'the name of this container'}, {'name': 'data', 'type': ('scalar_data', 'array_data', 'data', Data), 'doc': 'the source of the data'}, allow_positional=AllowPositional.WARNING,) def __init__(self, **kwargs): super().__init__(**kwargs) self.__data = kwargs['data'] @property def data(self): """The data managed by this object""" return self.__data def __len__(self): """Size of the data. Same as len(self.data)""" return len(self.__data)
[docs] def __getitem__(self, args): if isinstance(self.data, (tuple, list)) and isinstance(args, (tuple, list)): return [self.data[i] for i in args] return self.data[args]
[docs] def append(self, arg): """ Append a single element to the data Note: The arg to append should be 1 dimension less than the data. For example, if the data is a 2D array, arg should be a 1D array. Appending to scalar data is not supported. To append multiple elements, use extend. """ if isinstance(self.data, list): self.data.append(arg) elif isinstance(self.data, np.ndarray): self.__data = np.concatenate((self.__data, [arg])) else: msg = "NWBData cannot append to object of type '%s'" % type(self.__data) raise ValueError(msg)
[docs] def extend(self, arg): """ Extend the data with multiple elements. """ if isinstance(self.data, list): self.data.extend(arg) elif isinstance(self.data, np.ndarray): self.__data = np.concatenate((self.__data, arg)) else: msg = "NWBData cannot extend object of type '%s'" % type(self.__data) raise ValueError(msg)
[docs] @register_class('ScratchData', CORE_NAMESPACE) class ScratchData(NWBData): __nwbfields__ = ('description', ) @docval({'name': 'name', 'type': str, 'doc': 'the name of this container'}, {'name': 'data', 'type': ('scalar_data', 'array_data', 'data', Data), 'doc': 'the source of the data'}, {'name': 'description', 'type': str, 'doc': 'notes about the data', 'default': None}, allow_positional=AllowPositional.WARNING,) def __init__(self, **kwargs): description = popargs('description', kwargs) super().__init__(**kwargs) if not description: self._error_on_new_pass_on_construct(error_msg='ScratchData.description is required.') self.description = description
[docs] class NWBTable(Table): """Defined in PyNWB for API backward compatibility. See HDMF Table for details.""" pass
[docs] class MultiContainerInterface(NWBDataInterface, hdmf_MultiContainerInterface): """Defined in PyNWB for API backward compatibility. See HDMF MultiContainterInterface for details.""" pass