Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #29 from flywheel-apps/return-value
Browse files Browse the repository at this point in the history
Fix Retry on Failure, log to file
  • Loading branch information
AndysWorth authored May 11, 2022
2 parents b60b4d5 + cb533ce commit 25449a1
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 22 deletions.
13 changes: 9 additions & 4 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@
],
"type": "string"
},
"gear-log-to-file": {
"default": false,
"description": "Instead of logging in real time, save log output of fMRIPrep to the file output/log#.txt (where # is 1 or 2 depending on how many times fMRIPrep was run.",
"type": "boolean"
},
"gear-run-bids-validation": {
"default": false,
"description": "Gear will run BIDS validation before running fMRIPrep and print out all warnings and errors. fMRIPrep runs a version of the bids validator so having the gear run it is not necessary, but might be informative. If validation fails and gear-abort-on-bids-error is true, fMRIPrep will NOT be run.",
Expand Down Expand Up @@ -292,7 +297,7 @@
},
"verbose": {
"default": "",
"description": "increases log verbosity for each occurence, debug level is -vvv",
"description": "increases log verbosity for each occurrence, debug level is -vvv",
"enum": [
"",
"v",
Expand All @@ -308,13 +313,13 @@
}
},
"custom": {
"docker-image": "flywheel/bids-fmriprep:1.2.8_20.2.6",
"docker-image": "flywheel/bids-fmriprep:1.2.14_20.2.6",
"flywheel": {
"suite": "BIDS Apps"
},
"gear-builder": {
"category": "analysis",
"image": "flywheel/bids-fmriprep:1.2.8_20.2.6"
"image": "flywheel/bids-fmriprep:1.2.14_20.2.6"
},
"license": {
"dependencies": [
Expand Down Expand Up @@ -388,5 +393,5 @@
"name": "bids-fmriprep",
"source": "https://github.com/nipreps/fmriprep",
"url": "https://github.com/flywheel-apps/bids-fmriprep/blob/master/README.md",
"version": "1.2.8_20.2.6"
"version": "1.2.14_20.2.6"
}
45 changes: 27 additions & 18 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def generate_command(config, work_dir, output_analysis_id_dir, errors, warnings)
skip_pattern = re.compile("gear-|lsf-|singularity-")

command_parameters = {}
log_to_file = False
for key, val in config.items():

# these arguments are passed directly to the command as is
Expand Down Expand Up @@ -303,6 +304,12 @@ def main(gtk_context):
# show what's in the current working directory just before running
os.system("tree -alh .")

if config.get("gear-log-to-file"):
if command[-1] == "output/log1.txt":
command[-1] = "output/log2.txt"
else:
command = command + [">", "output/log1.txt"]

# This is what it is all about
exec_command(
command,
Expand All @@ -311,13 +318,19 @@ def main(gtk_context):
shell=True,
cont_output=True,
)
break

except RuntimeError as exc:
return_code = 1
if num_tries == 2:
return_code = 1
errors.append(exc)
log.critical(exc)
log.exception("Unable to execute command.")

os.system("echo ")
os.system("echo Disk Information on Failure")
os.system("df -h")

# Save time, etc. resources used in metadata on analysis
if Path("time_output.txt").exists(): # some tests won't have this file
metadata = {
Expand All @@ -342,11 +355,6 @@ def main(gtk_context):

# Cleanup, move all results to the output directory

if return_code != 0:
os.system("echo ")
os.system("echo Disk Information on Failure")
os.system("df -h")

# Remove all fsaverage* directories
if not config.get("gear-keep-fsaverage"):
path = output_analysis_id_dir / "freesurfer"
Expand Down Expand Up @@ -418,7 +426,6 @@ def main(gtk_context):
err_type = str(type(err)).split("'")[1]
msg += f" {err_type}: {str(err)}\n"
log.info(msg)
return_code = 1

if num_tries == 1:
log.info("Happily, fMRIPrep worked on the first try.")
Expand All @@ -437,21 +444,23 @@ def main(gtk_context):

if __name__ == "__main__":

# make sure /flywheel/v0 is writable, use a scratch directory if not
with flywheel_gear_toolkit.GearToolkitContext() as gtk_context:

# make sure /flywheel/v0 is writable, use a scratch directory if not
scratch_dir = run_in_tmp_dir(gtk_context.config["gear-writable-dir"])

# Has to be instantiated twice here, since parent directories might have
# changed
with flywheel_gear_toolkit.GearToolkitContext() as gtk_context:
return_code = main(gtk_context)

# clean up (might be necessary when running in a shared computing environment)
if scratch_dir:
log.debug("Removing scratch directory")
for thing in scratch_dir.glob("*"):
if thing.is_symlink():
thing.unlink() # don't remove anything links point to
log.debug("unlinked %s", thing.name)
shutil.rmtree(scratch_dir)
log.debug("Removed %s", scratch_dir)
# clean up (might be necessary when running in a shared computing environment)
if scratch_dir:
log.debug("Removing scratch directory")
for thing in scratch_dir.glob("*"):
if thing.is_symlink():
thing.unlink() # don't remove anything links point to
log.debug("unlinked %s", thing.name)
shutil.rmtree(scratch_dir)
log.debug("Removed %s", scratch_dir)

sys.exit(return_code)
Binary file added tests/data/gear_tests/log_to_file.zip
Binary file not shown.
46 changes: 46 additions & 0 deletions tests/integration_tests/test_log_to_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import json
import logging
import os
from pathlib import Path
from unittest import TestCase

import flywheel_gear_toolkit
from flywheel_gear_toolkit.utils.zip_tools import unzip_archive

import run

log = logging.getLogger(__name__)


def test_log_to_file_works(
tmp_path, caplog, install_gear, search_caplog_contains, search_caplog
):

caplog.set_level(logging.DEBUG)

user_json = Path(Path.home() / ".config/flywheel/user.json")
if not user_json.exists():
TestCase.skipTest("", f"No API key available in {str(user_json)}")
with open(user_json) as json_file:
data = json.load(json_file)
if "ga" not in data["key"]:
TestCase.skipTest("", "Not logged in to ga.")

FWV0 = Path.cwd()

install_gear("log_to_file.zip")

with flywheel_gear_toolkit.GearToolkitContext(input_args=[]) as gtk_context:

status = run.main(gtk_context)

assert status == 1
log_path = Path("/flywheel/v0/output/log2.txt")
assert log_path.exists()
found_it = False
with open(log_path, "r") as ff:
for line in ff:
if "Running fMRIPREP" in line:
found_it = True
break
assert found_it

0 comments on commit 25449a1

Please sign in to comment.