Skip to content

Commit

Permalink
First (non-working) version of the new BidsMap, Format and Datatype c…
Browse files Browse the repository at this point in the history
…lasses
  • Loading branch information
marcelzwiers committed Sep 16, 2024
1 parent 30e43d0 commit ccd5d1b
Show file tree
Hide file tree
Showing 16 changed files with 1,812 additions and 1,632 deletions.
12 changes: 6 additions & 6 deletions bidscoin/bcoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ def test_plugin(plugin: Union[Path,str], options: dict) -> int:
Performs runtime tests of the plug-in
:param plugin: The name of the plugin that is being tested
:param options: A dictionary with the plugin options, e.g. taken from the bidsmap['Options']['plugins'][plugin.stem]
:param options: A dictionary with the plugin options, e.g. taken from the bidsmap.plugins[plugin.stem]
:return: The result of the plugin test routine (e.g. 0 if it passed or 1 if there was a general plug-in error)
"""

Expand Down Expand Up @@ -493,12 +493,12 @@ def test_bidsmap(bidsmapfile: str):
bidsmapfile = Path(bidsmapfile)
if bidsmapfile.is_dir():
bidsmapfile = bidsmapfile/'code'/'bidscoin'/'bidsmap.yaml'
bidsmap, _ = bids.load_bidsmap(bidsmapfile, checks=(True, True, True))
bidsmap = bids.BidsMap(bidsmapfile, checks=(True, True, True))

return bids.validate_bidsmap(bidsmap, 1)
return bidsmap.validate(1)


def test_bidscoin(bidsmapfile: Union[Path,dict], options: dict=None, testplugins: bool=True, testgui: bool=True, testtemplate: bool=True) -> int:
def test_bidscoin(bidsmapfile: Path, options: dict=None, testplugins: bool=True, testgui: bool=True, testtemplate: bool=True) -> int:
"""
Performs a bidscoin installation test
Expand All @@ -521,7 +521,7 @@ def test_bidscoin(bidsmapfile: Union[Path,dict], options: dict=None, testplugins
LOGGER.info(f"Running bidsmap checks:")
try: # Moving the import to the top of this module will cause circular import issues
from bidscoin import bids
bidsmap, _ = bids.load_bidsmap(bidsmapfile, checks=(True, True, False))
bidsmap = bids.BidsMap(bidsmapfile, checks=(True, True, False))
except Exception as bidsmaperror:
LOGGER.error(f"An error occurred when loading {bidsmapfile}:\n{bidsmaperror}\nThis may be due to invalid YAML syntax. You can check this using a YAML validator (e.g. https://www.yamllint.com)")
bidsmap = {'Options': {}}
Expand All @@ -533,7 +533,7 @@ def test_bidscoin(bidsmapfile: Union[Path,dict], options: dict=None, testplugins
if testtemplate:
try: # Moving the import to the top of this module will cause circular import issues
from bidscoin import bids
success = bids.check_template(bidsmap) and success
success = bidsmap.check_template() and success
except ImportError:
LOGGER.info(f"Could not fully test: {bidsmap}")

Expand Down
2,410 changes: 1,244 additions & 1,166 deletions bidscoin/bids.py

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions bidscoin/bidsapps/fixmeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def fixmeta(bidsfolder: str, pattern: str, metadata: dict, participant: list, bi
LOGGER.info(f"Command: fixmeta {' '.join(sys.argv[1:])}")

# Load the bidsmap data (-> plugins)
bidsmap, _ = bids.load_bidsmap(Path(bidsmap or 'bidsmap.yaml'), bidsdir/'code'/'bidscoin', checks=(False, False, False))
bidsmap, _ = bids.BidsMap(Path(bidsmap or 'bidsmap.yaml'), bidsdir/'code'/'bidscoin', checks=(False, False, False))
if not bidsmap:
bidsmap, _ = bids.load_bidsmap(bidsmap_template, checks=(False, False, False))
plugins = bidsmap['Options']['plugins']
bidsmap, _ = bids.BidsMap(bidsmap_template, checks=(False, False, False))
plugins = bidsmap.plugins
provdata = bids.bidsprov(bidsdir)

# Loop over the subject/session-directories
Expand All @@ -83,7 +83,7 @@ def fixmeta(bidsfolder: str, pattern: str, metadata: dict, participant: list, bi
if isinstance(row['targets'], str) and target.name in row['targets']:
sourcedir = source
datasource = bids.get_datasource(Path(sourcedir), plugins)
LOGGER.bcdebug(f"Datasource provenance: '{target.name}' -> '{datasource.path}'")
LOGGER.bcdebug(f"Datasource provenance: '{target.name}' -> '{datasource}'")

# Load/copy over the source meta-data
jsonfile = target.with_suffix('').with_suffix('.json')
Expand Down
32 changes: 15 additions & 17 deletions bidscoin/bidscoiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,25 @@ def bidscoiner(sourcefolder: str, bidsfolder: str, participant: list=(), force:

# Create a README file if it does not exist
readme_file = bidsfolder/'README'
if not readme_file.is_file():
if not (readme_file.is_file() or next(bidsfolder.glob('README.*'))):
LOGGER.info(f"Creating a template README file (adjust it to your needs): {readme_file}")
try:
urllib.request.urlretrieve('https://raw.githubusercontent.com/bids-standard/bids-starter-kit/main/templates/README.MD', readme_file)
except urllib.error.URLError:
readme_file.write_text(
f"A free form text ( README ) describing the dataset in more details that SHOULD be provided. For an example, see e.g.:\n"
f"https://github.com/bids-standard/bids-starter-kit/blob/main/templates/README.MD\n\n"
f"The raw BIDS data was created using BIDScoin {__version__}\n"
f"All provenance information and settings can be found in ./code/bidscoin\n"
f"For more information see: https://github.com/Donders-Institute/bidscoin\n")
readme_file.write_text(f"A free form text ( README ) describing the dataset in more details that SHOULD be provided. For an example, see e.g.:\n"
f"https://github.com/bids-standard/bids-starter-kit/blob/main/templates/README.MD\n\n"
f"The raw BIDS data was created using BIDScoin {__version__}\n"
f"All provenance information and settings can be found in ./code/bidscoin\n"
f"For more information see: https://github.com/Donders-Institute/bidscoin\n")

# Get the bidsmap heuristics from the bidsmap YAML-file
bidsmap, bidsmapfile = bids.load_bidsmap(bidsmapfile, bidscoinfolder)
dataformats = [dataformat for dataformat in bidsmap if dataformat and dataformat not in ('$schema','Options')]
if not bidsmap:
bidsmap = bids.BidsMap(bidsmapfile, bidscoinfolder)
if not bidsmap.filepath.is_file():
LOGGER.error(f"No bidsmap file found in {bidsfolder}. Please run the bidsmapper first and/or use the correct bidsfolder")
return

# Load the data conversion plugins
plugins = [bcoin.import_plugin(plugin, ('bidscoiner_plugin',)) for plugin,options in bidsmap['Options']['plugins'].items()]
plugins = [bcoin.import_plugin(plugin, ('bidscoiner_plugin',)) for plugin,options in bidsmap.plugins.items()]
plugins = [plugin for plugin in plugins if plugin] # Filter the empty items from the list
if not plugins:
LOGGER.warning(f"The plugins listed in your bidsmap['Options'] did not have a usable `bidscoiner_plugin` function, nothing to do")
Expand All @@ -110,7 +108,7 @@ def bidscoiner(sourcefolder: str, bidsfolder: str, participant: list=(), force:
return

# Append options to the .bidsignore file
bidsignore_items = bidsmap['Options']['bidscoin']['bidsignore']
bidsignore_items = bidsmap.options['bidsignore']
bidsignore_file = bidsfolder/'.bidsignore'
if bidsignore_items:
LOGGER.verbose(f"Writing {bidsignore_items} entries to {bidsignore_file}")
Expand All @@ -121,8 +119,8 @@ def bidscoiner(sourcefolder: str, bidsfolder: str, participant: list=(), force:
bidsignore.write(item + '\n')

# Get the list of subjects
subprefix = bidsmap['Options']['bidscoin']['subprefix'].replace('*','')
sesprefix = bidsmap['Options']['bidscoin']['sesprefix'].replace('*','')
subprefix = bidsmap.options['subprefix'].replace('*','')
sesprefix = bidsmap.options['sesprefix'].replace('*','')
if not participant:
subjects = lsdirs(rawfolder, (subprefix if subprefix!='*' else '') + '*')
if not subjects:
Expand Down Expand Up @@ -151,7 +149,7 @@ def bidscoiner(sourcefolder: str, bidsfolder: str, participant: list=(), force:
for subject in subjects:

# Check if we should skip the session-folder
datasource = bids.get_datasource(subject, bidsmap['Options']['plugins'])
datasource = bids.get_datasource(subject, bidsmap.plugins)
subid,_ = datasource.subid_sesid(bidsmap[datasource.dataformat]['subject'], bidsmap[datasource.dataformat]['session'])
if (bidsfolder/subid).is_dir() and not force:
LOGGER.info(f">>> Skipping already processed subject: {bidsfolder/subid} (you can use the -f option to overrule)")
Expand Down Expand Up @@ -257,11 +255,11 @@ def bidscoiner(sourcefolder: str, bidsfolder: str, participant: list=(), force:
for session in sessions:

# Unpack the data in a temporary folder if it is tarballed/zipped and/or contains a DICOMDIR file
sesfolders, unpacked = bids.unpack(session, bidsmap['Options']['bidscoin'].get('unzip',''))
sesfolders, unpacked = bids.unpack(session, bidsmap.options.get('unzip',''))
for sesfolder in sesfolders:

# Check if we should skip the session-folder
datasource = bids.get_datasource(sesfolder, bidsmap['Options']['plugins'])
datasource = bids.get_datasource(sesfolder, bidsmap.plugins)
if not datasource.dataformat:
LOGGER.info(f">>> No datasources found in '{sesfolder}'")
continue
Expand Down
Loading

0 comments on commit ccd5d1b

Please sign in to comment.