def testFailEmpty(tmpdir): datasetRoot = Path(tmpdir, "bids-archive") emptyArchive = BidsArchive(datasetRoot) with pytest.raises(StateError): emptyArchive.dirExistsInArchive("will fail anyway") emptyArchive.getImages("will fail anyway") emptyArchive.addImage(None, "will fall anyway") emptyArchive.getSidecarMetadata("will fall anyway") emptyArchive.addMetadata({"will": "fail"}, "will fall anyway") emptyArchive.getIncremental(subject="will fall anyway", session="will fall anyway", task="will fall anyway", suffix="will fall anyway", datatype="will fall anyway")
def testDiskOutput(validBidsI, tmpdir): # Write the archive datasetRoot = os.path.join(tmpdir, "bids-pytest-dataset") validBidsI.writeToDisk(datasetRoot) # Validate the output can be opened by BidsArchive and verified against the # source BIDS-Incremental archive = BidsArchive(datasetRoot) archiveImage = archive.getImages()[0] # Remove pseudo entities to avoid conflict with the validBidsI metadata = archive.getSidecarMetadata(archiveImage, includeEntities=True) for entity in PYBIDS_PSEUDO_ENTITIES: metadata.pop(entity) incrementalFromArchive = BidsIncremental(archiveImage, metadata) assert incrementalFromArchive == validBidsI assert isValidBidsArchive(archive.rootPath) # Try only writing data datasetRoot = os.path.join(tmpdir, "bids-pytest-dataset-2") validBidsI.writeToDisk(datasetRoot, onlyData=True) assert not os.path.exists(os.path.join(datasetRoot, "README")) assert not os.path.exists( os.path.join(datasetRoot, "dataset_description.json"))
class BidsStream: """ A class that opens a BIDS archive and prepares to stream the data as BIDS incrementals. """ def __init__(self, archivePath, **entities): """ Args: archivePath: Absolute path of the BIDS archive. entities: BIDS entities (subject, session, task, run, suffix, datatype) that define the particular subject/run of the data to stream """ self.bidsArchive = BidsArchive(archivePath) # TODO - when we have BidsRun # self.bidsRun = self.bidsArchive.getBidsRun(**entities) images = self.bidsArchive.getImages(**entities) if len(images) == 0: raise ValidationError('No matching images found') if len(images) > 1: raise ValidationError('More than one match, please give more specific subject/session/task/run') self.bidsImage = images[0] self.niftiImage = self.bidsImage.get_image() self.filename = self.niftiImage.get_filename() self.imgVolumes = nib.four_to_three(self.niftiImage) self.metadata = self.bidsArchive.getSidecarMetadata(self.filename, includeEntities=True) self.metadata.pop('extension') self.numVolumes = len(self.imgVolumes) self.nextVol = 0 def getNumVolumes(self) -> int: """Return the number of brain volumes in the run""" # TODO - when we have BidsRun # return self.bidsRun.getNumVolumes() return self.numVolumes def getIncremental(self, volIdx=-1) -> BidsIncremental: """ Get a BIDS incremental for the indicated index in the current subject/run VolIdx acts similar to a file_seek pointer. If a volIdx >= 0 is supplied the volume pointer is advanced to that position. If no volIdx or a volIdx < 0 is supplied, then the next image volume after the previous position is returned and the pointer is incremented. Args: volIdx: The volume index (or TR) within the run to retrieve. Returns: BidsIncremental of that volume index within this subject/run """ # TODO - when we have BidsRun # return self.bidsRun.getIncremental(volIdx) if volIdx >= 0: # reset the next volume to the user specified volume self.nextVol = volIdx else: # use the default next volume pass if self.nextVol < self.numVolumes: incremental = BidsIncremental(self.imgVolumes[self.nextVol], self.metadata) self.nextVol += 1 return incremental else: return None