Beispiel #1
0
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
Beispiel #2
0
 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!')
Beispiel #3
0
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
Beispiel #4
0
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')
Beispiel #5
0
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
Beispiel #6
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)
Beispiel #7
0
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)
Beispiel #8
0
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'))
Beispiel #9
0
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')
Beispiel #10
0
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'))