@@ -225,3 +225,107 @@ def __init__(self, **kwargs):
225225
226226io = NWBHDF5IO ('cache_spec_example.nwb' , mode = 'r' , load_namespaces = True )
227227nwbfile = io .read ()
228+
229+ ####################
230+ # .. _MultiContainerInterface:
231+ # Creating and using a custom MultiContainerInterface
232+ # -----------------------------------------------------
233+ # It is sometimes the case that we need a group to hold zero-or-more or one-or-more of the same object.
234+ # Here we show how to create an extension that defines a group (`PotatoSack`) that holds multiple objects (`Pototo`es)
235+ # and then how to use the new data types. First, we use `pynwb` to define the new data types.
236+
237+ from pynwb .spec import NWBNamespaceBuilder , NWBGroupSpec , NWBAttributeSpec
238+
239+ name = 'test_multicontainerinterface'
240+ ns_path = name + ".namespace.yaml"
241+ ext_source = name + ".extensions.yaml"
242+
243+ potato = NWBGroupSpec (neurodata_type_def = 'Potato' ,
244+ neurodata_type_inc = 'NWBDataInterface' ,
245+ doc = 'time of multicontainer' , quantity = '*' ,
246+ attributes = [
247+ NWBAttributeSpec (name = 'weight' ,
248+ doc = 'weight of potato' ,
249+ dtype = 'float' ,
250+ required = True ),
251+ NWBAttributeSpec (name = 'age' ,
252+ doc = 'age of potato' ,
253+ dtype = 'float' ,
254+ required = False ),
255+ NWBAttributeSpec (name = 'help' ,
256+ doc = 'help' ,
257+ dtype = 'text' ,
258+ value = "It's a potato" )
259+ ])
260+
261+ potato_sack = NWBGroupSpec (neurodata_type_def = 'PotatoSack' ,
262+ neurodata_type_inc = 'NWBDataInterface' ,
263+ name = 'potato_sack' ,
264+ doc = 'test of multicontainer' , quantity = '?' ,
265+ groups = [potato ],
266+ attributes = [
267+ NWBAttributeSpec (name = 'help' ,
268+ doc = 'help' ,
269+ dtype = 'text' ,
270+ value = "It's a sack of potatoes" )
271+ ])
272+
273+ ns_builder = NWBNamespaceBuilder (name + ' extensions' , name )
274+ ns_builder .add_spec (ext_source , potato_sack )
275+ ns_builder .export (ns_path )
276+
277+ ####################
278+ # Then create Container classes registered to the new data types (this is generally done in a different file)
279+
280+ from pynwb import register_class , load_namespaces
281+ from pynwb .file import MultiContainerInterface , NWBContainer
282+
283+ load_namespaces (ns_path )
284+
285+
286+ @register_class ('Potato' , name )
287+ class Potato (NWBContainer ):
288+ __nwbfields__ = ('name' , 'weight' , 'age' , 'source' )
289+
290+ @docval ({'name' : 'name' , 'type' : str , 'doc' : 'who names a potato?' },
291+ {'name' : 'weight' , 'type' : float , 'doc' : 'weight of potato in grams' },
292+ {'name' : 'age' , 'type' : float , 'doc' : 'age of potato in days' },
293+ {'name' : 'source' , 'type' : str , 'doc' : 'source of potato' ,
294+ 'default' : 'the ground' })
295+ def __init__ (self , ** kwargs ):
296+ super (Potato , self ).__init__ (kwargs ['source' ], name = kwargs ['name' ])
297+ self .weight = kwargs ['weight' ]
298+ self .age = kwargs ['age' ]
299+
300+
301+ @register_class ('PotatoSack' , name )
302+ class PotatoSack (MultiContainerInterface ):
303+
304+ __clsconf__ = {
305+ 'attr' : 'potatos' ,
306+ 'type' : Potato ,
307+ 'add' : 'add_potato' ,
308+ 'get' : 'get_potato' ,
309+ 'create' : 'create_potato' ,
310+ }
311+
312+ __help = 'info about potatoes'
313+
314+
315+ ####################
316+ # Then use the objects (again, this would often be done in a different file).
317+
318+ from pynwb import NWBHDF5IO , NWBFile
319+
320+ potato_sack = PotatoSack (source = 'pantry' ,
321+ potatos = Potato (name = 'potato1' , age = 2.3 , weight = 3.0 ,
322+ source = 'the ground' ))
323+
324+ nwbfile = NWBFile ("source" , "a file with metadata" , "NB123A" , '2018-06-01T00:00:00' )
325+
326+ pmod = nwbfile .create_processing_module ('module_name' , 'source' , 'desc' )
327+ pmod .add_container (potato_sack )
328+
329+
330+ with NWBHDF5IO ('test_multicontainerinterface.nwb' , 'w' ) as io :
331+ io .write (nwbfile )
0 commit comments