fromaind_behavior_vr_foraging.data_contractimportdatasetfromaind_behavior_vr_foraging_packaging.pipeline.sessionimportcreate_processorsfromaind_behavior_vr_foraging_packaging.nwb_fileimportNwbSessionraw="path/to/behavior_<subject>_<date>"ds=dataset(raw)processors=create_processors(ds)session=NwbSession(raw)# reads AIND metadata JSONs from raw/session.run(*processors)# calls nwbize() on each processorsession.write_nwb_zarr(# writes the NWBFile as NWB-Zarr"output/my_session.nwb.zarr")
classNwbSession:def__init__(self,root_path:Path,*,dataset:Optional[data_contract.Dataset]=None,base_nwb_file:Optional[NWBFile]=None,)->None:self._root_path=root_pathself._dataset=datasetifdatasetelseaind_behavior_vr_foraging.data_contract.dataset(root_path)self._base_nwb_file=base_nwb_fileself._nwb_file:Optional[NWBFile]=None@propertydefdataset(self)->data_contract.Dataset:returnself._dataset@propertydefroot_path(self)->Path:returnself._root_path@propertydefnwb_file(self)->NWBFile:ifself._nwb_fileisNone:raiseValueError("NWB file has not been created yet. Call process() to create it before accessing.")returnself._nwb_filedefprocess(self)->NWBFile:ifself._nwb_fileisNone:self._nwb_file=self._create_nwb_file()returnself._nwb_filedefrun(self,*processors:AbstractProcessor)->NWBFile:nwb=self.process()logger.info("Running %s processors on NWB file...",len(processors))forprocessorinprocessors:logger.info("Running nwbize: %s",processor.__class__.__name__)nwb=processor.nwbize(nwb)returnnwb@propertydefprovenance(self)->dict[str,str]:"""Versions describing how this file was produced, keyed as in ``df.attrs``."""returnPackagingProvenance.build(self._dataset).model_dump()def_create_nwb_file(self)->NWBFile:nwb_file=self._base_nwb_fileifself._base_nwb_fileisnotNoneelsecreate_base_nwb_file(self.root_path)# Provenance otherwise only reaches the parquet outputs (df.attrs). The same# versions land here, so the two outputs of a session can be checked against# each other. was_generated_by is write-once, and create_base_nwb_file has# already set it to aind-nwb-utils' own entry, so extend it in place.entries=[[key,value]forkey,valueinself.provenance.items()]ifnwb_file.was_generated_byisNone:nwb_file.was_generated_by=entrieselse:nwb_file.was_generated_by.extend(entries)returnnwb_filedefwrite_nwb_zarr(self,output:Path)->None:ifself._nwb_fileisNone:raiseValueError("NWB file has not been created yet. Call process() to create it before writing.")withNWBZarrIO(Path(output).as_posix(),"w")asio:io.write(self._nwb_file)logger.info(f"NWB zarr successfully written to path {output}")