biopragmatics/bioontologies

Gracefully handle `robot` exceptions

Opened this issue · 0 comments

Overview

I made a mistake with what I was trying to do. I accidentally named my OWL file that I wanted to convert mondo.json instead of mondo.owl. I think that is what caused robot to throw an error. However, I don't see the actual error message that robot raised.

Error

Short err: subprocess.CalledProcessError:

Long err:

in convert_to_obograph
    ret = convert(
  File "/Users/joeflack4/virtualenvs/tims-ts/lib/python3.10/site-packages/bioontologies/[robot.py](http://robot.py/)", line 295, in convert
    ret = check_output(  # noqa:S603
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/[subprocess.py](http://subprocess.py/)", line 421, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/[subprocess.py](http://subprocess.py/)", line 526, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['robot', 'convert', '-i', '/Users/joeflack4/projects/tims-ts/bin/../cache/mondo.json', '-o', '/var/folders/_0/hsvm3gjx1q7br2grg3gx901c0000gn/T/tmpwfpxhug7/output.json', '--format', 'json']' returned non-zero exit status 1.
python-BaseException

Possible solutions

Currently, robot is being called like so: https://github.com/biopragmatics/bioontologies/blob/main/src/bioontologies/robot.py#L355

    ret = check_output(  # noqa:S603
        args,
        cwd=os.path.dirname(__file__),
    )
    return ret.decode()

It looks like subprocess check_output() calls run(), which returns CompletedProcess(process.args, retcode, stdout, stderr). We should be able to parse out stdout and stderr from this. Edit: I tried and I'm not sure why, but the result I got back from check_output() was b'', not a CompletedProcess instance.

I recently did this for mondo-ingest (looks like it was on run() directly:

        result = subprocess.run(command_str.split(), capture_output=True, text=True)
        stderr, stdout = result.stderr, result.stdout
        if stderr:
            raise RuntimeError(stderr)
        elif stdout and 'error' in stdout or 'ERROR' in stdout:
            raise RuntimeError(stdout)

The parsing of stdout in this way is not very graceful, but at least it worked for this particular exception. Perhaps there is a more stable / better way.

Either way what do you think? If you want, I could do a PR for this one.