def test_generate_xml(): # Generate an xml mapping of the BDIS folder structure. with tempfile.TemporaryDirectory() as tmp: # copy the dst to a temp folder. shutil.copytree(TESTPATH1, op.join(tmp, 'BIDSTEST1')) folder = BIDSTree(op.join(tmp, 'BIDSTEST1')) folder.generate_map(op.join(tmp, 'map.xml')) tree = ET.ElementTree() tree.parse(op.join(tmp, 'map.xml')) assert len(tree.findall('Project')) == 2 # find the `test1` project for _proj in tree.findall('Project'): if _proj.attrib['ID'] == 'test1': proj = _proj assert len(proj.findall('Subject')) == 2 # find subject 1 for _subj in proj.findall('Subject'): if _subj.attrib['ID'] == '1': subj = _subj assert subj.attrib['sex'] == 'F' assert len(subj.findall('Session')) == 2 for _sess in subj.findall('Session'): if _sess.attrib['ID'] == '1': sess = _sess assert len(sess.findall('Scan')) == 2 scan = None for _scan in sess.findall('Scan'): if (_scan.attrib['path'] == op.join( 'meg', 'sub-1_ses-1_task-resting_run-1_meg', 'sub-1_ses-1_task-resting_run-1_meg.con')): scan = _scan assert scan is not None
def _transfer(self): """Transfer all the files in each of the sources to the destination.""" copy_func = BIDSCopy(overwrite=self.force_override.get(), verify=self.verify.get(), file_name_tracker=self.curr_file, file_num_tracker=self.transferred_count, file_prog_tracker=self.curr_file_progress) self.curr_file.set('Mapping destination BIDS structure...') dst_folder = BIDSTree(self.dst) for src in self.srcs: dst_folder.add(src, copier=copy_func.copy_files) if self.set_copied: self._rename_complete(src) self.transferred_count.set(self.file_count) self.curr_file.set('Complete!')
def assign_bids_folder(fpath, treeview, data): """ Assign the filepath as a BIDS folder and associate all children as the required type. """ try: bids_folder = BIDSTree(fpath) except MappingError: return if bids_folder.projects == []: # Ie. no valid data messagebox.showerror( "Not valid", "The folder you selected is does not contain valid BIDS " "data.\nPlease select a folder containing BIDS-formatted " "data.") # Remove the bids folder just to be sure del bids_folder return None # now we need to assign all the data to the filetree... sid = treeview.sid_from_filepath(fpath) data[sid] = bids_folder for project in bids_folder: sid = treeview.sid_from_filepath(project.path) data[sid] = project for subject in project: sid = treeview.sid_from_filepath(subject.path) data[sid] = subject for session in subject: sid = treeview.sid_from_filepath(session.path) data[sid] = session return bids_folder
def test_rename(): with tempfile.TemporaryDirectory() as tmp: shutil.copytree(TESTPATH1, op.join(tmp, 'BIDSTEST1')) src_bt = BIDSTree(op.join(tmp, 'BIDSTEST1')) # renaming a subject subj = src_bt.project('test1').subject(2) subj.rename('4') assert subj.ID == 'sub-4' for _, _, files in os.walk(subj.path): for fname in files: assert 'sub-2' not in fname sess = subj.session(2) assert 'sub-4' in sess.scans[0].raw_file # renaming a session sess.rename('3') assert sess.ID == 'ses-3' for _, _, files in os.walk(subj.path): for fname in files: assert 'ses-2' not in fname df = pd.read_csv(sess.scans_tsv, sep='\t') for row in df['filename']: assert 'ses-3' in row assert 'sub-4' in row # test renaming a folder-less session to have a session label shutil.copytree(TESTPATH2, op.join(tmp, 'BIDSTEST2')) src_bt = BIDSTree(op.join(tmp, 'BIDSTEST2')) sess = src_bt.project('test1').subject(2).session('none') orig_path = sess.path sess.rename('1') assert sess.path == op.join(orig_path, 'ses-1')
def test_bidstree_to_bidstree(): # Test writing one BIDSTree object to a new empty BIDSTree location. with tempfile.TemporaryDirectory() as tmp: dest_bf = BIDSTree(tmp, False) src_bt = BIDSTree(TESTPATH2) dest_bf.add(src_bt) assert len(dest_bf.projects) == 1 assert dest_bf.project('test1').subject('1').subject_data['age'] == 2.0
def _import_bids_data(self): """Allow BIDS data to be imported into Biscuit.""" src_dir = filedialog.askdirectory( title="Select the BIDS folder to import") if src_dir != '': try: bt = BIDSTree(src_dir) except MappingError: messagebox.showerror( 'Invalid folder', 'Can only import entire BIDS folders ' 'currently.') return dst_dir = filedialog.askdirectory( title="Select the BIDS folder to import into") if dst_dir != '': SendFilesWindow(self, bt, dst_dir, opt_verify=True)
def test_copy_errors(): # Test trying to copy the wrong things into the wrong places. with tempfile.TemporaryDirectory() as tmp: # copy the dst to a temp folder shutil.copytree(TESTPATH2, op.join(tmp, 'BIDSTEST2')) src_bt = BIDSTree(TESTPATH1) dst_bt = BIDSTree(op.join(tmp, 'BIDSTEST2')) # try add one project to another with different ID's # try and add an object you shouldn't do: proj = src_bt.project('test1') with pytest.raises(TypeError): dst_bt.project('test1').subject('1').session('1').add(proj) with pytest.raises(TypeError): dst_bt.project('test1').subject('1').add(proj) with pytest.raises(TypeError): dst_bt.project('test1').add(src_bt) proj = src_bt.project('test2') sub = proj.subject('3') ses = sub.session('1') scan = ses.scan(task='resting', run='1') # try and add objects in the wrong project: with pytest.raises(ValueError): dst_bt.project('test1').add(proj) with pytest.raises(AssociationError): dst_bt.project('test1').add(sub) with pytest.raises(AssociationError): dst_bt.project('test1').add(ses) with pytest.raises(AssociationError): dst_bt.project('test1').add(scan) # try and add objects to the wrong subject: with pytest.raises(ValueError): dst_bt.project('test1').subject('1').add(sub) with pytest.raises(AssociationError): dst_bt.project('test1').subject('1').add(ses) with pytest.raises(AssociationError): dst_bt.project('test1').subject('1').add(scan) # try and add objects to the wrong session: with pytest.raises(ValueError): session = src_bt.project('test1').subject('1').session('2') dst_bt.project('test1').subject('1').session('1').add(session) with pytest.raises(AssociationError): dst_bt.project('test1').subject('1').session('1').add(scan)
def test_merge_bidstrees(): # Test completely merging one BIDS folder into another. with tempfile.TemporaryDirectory() as tmp: # copy the dst to a temp folder shutil.copytree(TESTPATH2, op.join(tmp, 'BIDSTEST2')) src_bt = BIDSTree(TESTPATH1) dst_bt = BIDSTree(op.join(tmp, 'BIDSTEST2')) with pytest.warns(UserWarning): dst_bt.add(src_bt) assert len(dst_bt.projects) == 2 # proj:test1, subj:2, sess: 1 will not have been merged assert (src_bt.project('test1').subject(2).session(2) not in dst_bt.project('test1').subject(2)) # To rectify this, rename the folder-less session then re-add dst_bt.project('test1').subject(2).session('none').rename('1') dst_bt.project('test1').subject(2).add( src_bt.project('test1').subject(2).session(2)) assert len(dst_bt.project('test1').subject(2).sessions) == 2 # check that extra files are brought along sess = dst_bt.project('test2').subject(3).session(1) assert 'code' in sess.extra_data assert 'extradata' in sess.extra_data assert op.exists(op.join(sess.path, 'code', 'analysis.py')) assert op.exists(op.join(sess.path, 'extradata', 'extra.txt'))
def test_add_new_project_recursively(): # Add a scan existing in a project that doesn't exist in the dst folder # This will recursively add the project, subject and session. with tempfile.TemporaryDirectory() as tmp: # copy the dst to a temp folder shutil.copytree(TESTPATH2, op.join(tmp, 'BIDSTEST2')) src_bt = BIDSTree(TESTPATH1) dst_bt = BIDSTree(op.join(tmp, 'BIDSTEST2')) scan = src_bt.project('test2').subject('3').session('1').scan( task='resting', run='1') assert scan.emptyroom is not None dst_bt.add(scan) # make sure the project was added assert len(dst_bt.projects) == 2 assert op.exists(dst_bt.project('test2').readme) assert op.exists(dst_bt.project('test2').description) # make sure the subject was added and the empty room data was too assert len(dst_bt.project('test2').subjects) == 2 # make sure the scan was added scans_tsv = dst_bt.project('test2').subject('3').session('1').scans_tsv assert op.exists(scans_tsv) dst_bt.project('test2').subject('emptyroom')
def test_query(): folder = BIDSTree(TESTPATH1) # query a BIDSTree object # query some subject information assert len(folder.query('subject', 'age', '=', 4)) == 1 assert len(folder.query('subject', 'age', '>', 2)) == 2 assert len(folder.query('subject', 'age', '>=', 2)) == 3 assert len(folder.query('subject', 'sex', '=', 'M')) == 1 assert len(folder.query('subject', 'sex', '!=', 'M')) == 3 assert len(folder.query('subject', 'group', '=', 'autistic')) == 2 # query some tasks assert len(folder.query('scan', 'task', '=', 'resting')) == 2 # ask if any of the subjects has *any* tasks that aren't 'resting' assert (folder.project('test1').subject('1') in folder.query('subject', 'task', '!=', 'resting')) # ask if any of the subjects have not got a task called 'resting' assert (folder.project('test1').subject('2') in folder.query('subject', 'task', '!!=', 'resting')) with pytest.raises(ValueError, match='Condition'): folder.query('subject', 'task', '>', 'resting') # query the recording date ref_datetime = '2018-10-26T11:32:33' ref_date = '2018-10-26' assert len(folder.query('scan', 'rec_date', '=', ref_datetime)) == 1 assert len(folder.query('scan', 'rec_date', '<=', ref_datetime)) == 5 assert len(folder.query('scan', 'rec_date', '>', ref_datetime)) == 1 assert len(folder.query('scan', 'rec_date', '=', ref_date)) == 6 assert len(folder.query('session', 'rec_date', '=', ref_date)) == 5 # query some data in the sidecar.json: assert len(folder.query('project', 'PowerLineFrequency', '=', 50)) == 2 assert len(folder.query('subject', 'MiscChannelCount', '=', 93)) == 4 assert len(folder.query('session', 'TaskName', '=', 'resting')) == 2 assert len(folder.query('scan', 'RecordingDuration', '>=', 5)) == 6 # query for number of subjects, sessions, or scans assert len(folder.query('project', 'subjects', '=', 2)) == 2 assert len(folder.query('project', 'sessions', '!=', 3)) == 1 assert len(folder.query('subject', 'sessions', '<', 2)) == 3 assert len(folder.query('project', 'scans', '>', 4)) == 0 assert len(folder.query('subject', 'scans', '<=', 2)) == 3 assert len(folder.query('session', 'scans', '<', 2)) == 4 with pytest.raises(ValueError): folder.query('subject', 'subjects', '=', 2) with pytest.raises(ValueError): folder.query('session', 'sessions', '=', 1) with pytest.raises(ValueError): folder.query('scan', 'scans', '=', 1) # query a Project object (test1): proj = folder.query('project', 'sessions', '=', 3) assert len(proj.query('subject', 'sessions', '=', 2)) == 1 assert len(proj.query('subject', 'group', '=', 'neurotypical')) == 1 assert len(proj.query('session', 'scans', '<=', 3)) == 3 # query a Subject object (sub-1): subj = proj.query('subject', 'sessions', '=', 2)[0] assert len(subj.query('session', 'scans', '>=', 1)) == 2 with pytest.raises(ValueError, match='Invalid query'): subj.query('project', 'subjects', '=', 1) # query a Session object (ses-1): sess = subj.query('session', 'scans', '>', 1)[0] assert len(sess.query('scan', 'task', '=', 'resting')) == 1 # query a scan object: scan = sess.query('scan', 'task', '=', 'resting')[0] assert len(scan.query('scan', 'MEGChannelCount', '=', 160)) == 1 # perform a compound query: subjs = folder.query('subject', 'age', '>', 2) assert len(subjs.query('scan', 'task', '=', 'resting')) == 1 projs = folder.query('project', 'subjects', '>', 1) assert (folder.project('test1') in projs.query('project', 'sessions', '=', 3)) subjs = folder.query('subject', 'sex', '=', 'F') assert (folder.project('test2').subject('3') in subjs.query('subject', 'sessions', '=', 1)) sesss = folder.query('session', 'scans', '=', 1) assert len(sesss) == 4 assert (folder.project('test2').subject('3').session('1') in sesss.query('session', 'TaskName', '=', 'resting'))