Skip to content

Commit 779fa25

Browse files
authored
Add lab meta data (#751)
You can now write zero or more lab extensions and put them in /general/ by making them inherit from LabMetaData and calling nwbfile.add_lab_meta_data tests were also added
1 parent 7e2365c commit 779fa25

File tree

5 files changed

+55
-4
lines changed

5 files changed

+55
-4
lines changed

src/pynwb/data/nwb.file.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ groups:
223223
date made, injection location, volume, etc.
224224
quantity: '?'
225225
groups:
226+
- neurodata_type_def: LabMetaData
227+
neurodata_type_inc: NWBContainer
228+
doc: 'place-holder than can be extended so that lab-specific meta-data can be placed in /general'
229+
quantity: '*'
226230
- name: devices
227231
doc: 'Description of hardware devices used during experiment. COMMENT: Eg, monitors,
228232
ADC boards, microscopes, etc'

src/pynwb/file.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class SpecFile(Container):
2828
pass
2929

3030

31+
@register_class('LabMetaData', CORE_NAMESPACE)
32+
class LabMetaData(NWBContainer):
33+
def __init__(self, **kwargs):
34+
super(LabMetaData, self).__init__(kwargs['name'])
35+
36+
3137
@register_class('Subject', CORE_NAMESPACE)
3238
class Subject(NWBContainer):
3339

@@ -141,6 +147,13 @@ class NWBFile(MultiContainerInterface):
141147
'create': 'create_time_intervals',
142148
'get': 'get_time_intervals'
143149
},
150+
{
151+
'attr': 'lab_meta_data',
152+
'add': 'add_lab_meta_data',
153+
'type': LabMetaData,
154+
'create': 'create_lab_meta_data',
155+
'get': 'get_lab_meta_data'
156+
}
144157
]
145158

146159
__nwbfields__ = ('timestamps_reference_time',

src/pynwb/io/file.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self, spec):
4747

4848
self.map_spec('subject', general_spec.get_group('subject'))
4949
self.map_spec('devices', general_spec.get_group('devices').get_neurodata_type('Device'))
50+
self.map_spec('lab_meta_data', general_spec.get_neurodata_type('LabMetaData'))
5051

5152
@ObjectMapper.constructor_arg('session_start_time')
5253
def dateconversion(self, builder, manager):

tests/unit/pynwb_tests/test_core.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ def test_print_file(self):
309309
epoch_tags: """ + empty_set_str + """
310310
ic_electrodes: { }
311311
imaging_planes: { }
312+
lab_meta_data: { }
312313
modules: { }
313314
ogen_sites: { }
314315
stimulus: { }

tests/unit/pynwb_tests/test_extension.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import unittest2 as unittest
21
import os
3-
from tempfile import gettempdir
42
import random
53
import string
4+
from datetime import datetime
5+
from dateutil.tz import tzlocal
6+
from tempfile import gettempdir
67

7-
from pynwb.spec import NWBNamespaceBuilder, NWBGroupSpec, NWBAttributeSpec, NWBDatasetSpec
8+
import unittest2 as unittest
9+
from pynwb import get_type_map, TimeSeries, NWBFile, register_class, docval, load_namespaces, popargs
810
from pynwb.form.spec.spec import RefSpec
9-
from pynwb import get_type_map, TimeSeries
1011
from pynwb.form.utils import get_docval
12+
from pynwb.spec import NWBNamespaceBuilder, NWBGroupSpec, NWBAttributeSpec, NWBDatasetSpec
13+
from pynwb.file import LabMetaData
1114

1215

1316
def id_generator(N=10):
@@ -80,6 +83,35 @@ def test_load_namespace_with_reftype_attribute_check_autoclass_const(self):
8083
self.assertIsNotNone(docval)
8184
self.assertEqual(docval['type'], TimeSeries)
8285

86+
def test_lab_meta(self):
87+
ns_builder = NWBNamespaceBuilder('Extension for use in my Lab', self.prefix)
88+
test_meta_ext = NWBGroupSpec(
89+
neurodata_type_def='MyTestMetaData',
90+
neurodata_type_inc='LabMetaData',
91+
doc='my test meta data',
92+
attributes=[
93+
NWBAttributeSpec(name='test_attr', dtype='float', doc='test_dtype')])
94+
ns_builder.add_spec(self.ext_source, test_meta_ext)
95+
ns_builder.export(self.ns_path, outdir=self.tempdir)
96+
ns_abs_path = os.path.join(self.tempdir, self.ns_path)
97+
98+
load_namespaces(ns_abs_path)
99+
100+
@register_class('MyTestMetaData', self.prefix)
101+
class MyTestMetaData(LabMetaData):
102+
__nwbfields__ = ('test_attr',)
103+
104+
@docval({'name': 'name', 'type': str, 'doc': 'name'},
105+
{'name': 'test_attr', 'type': float, 'doc': 'test attribute'})
106+
def __init__(self, **kwargs):
107+
test_attr = popargs('test_attr', kwargs)
108+
super(MyTestMetaData, self).__init__(**kwargs)
109+
self.test_attr = test_attr
110+
111+
nwbfile = NWBFile("a file with header data", "NB123A", datetime(2017, 5, 1, 12, 0, 0, tzinfo=tzlocal()))
112+
113+
nwbfile.add_lab_meta_data(MyTestMetaData(name='test_name', test_attr=5.))
114+
83115

84116
class TestCatchDupNS(unittest.TestCase):
85117

0 commit comments

Comments
 (0)