diff --git a/hpcpy/client/base.py b/hpcpy/client/base.py index ceda7cf..e585a3c 100644 --- a/hpcpy/client/base.py +++ b/hpcpy/client/base.py @@ -115,7 +115,6 @@ def status(self, job_id): job_id : str Job ID. """ - # raise NotImplementedError() cmd = self._tmp_status.format(job_id=job_id) result = self._shell(cmd) return result @@ -171,11 +170,15 @@ def _shell(self, cmd, decode=True): Command to run. decode : bool Automatically decode response with utf-8, defaults to True + Raises + ------ + hpcypy.excetions.ShellException : + When the underlying shell call fails. Returns ------- - _type_ - _description_ + str + Result from the underlying called command. """ result = shell(cmd) diff --git a/hpcpy/exceptions.py b/hpcpy/exceptions.py index 483d2f8..f2b075a 100644 --- a/hpcpy/exceptions.py +++ b/hpcpy/exceptions.py @@ -1,5 +1,36 @@ +import subprocess as sp + + class NoClientException(Exception): def __init__(self): super().__init__( "Unable to detect scheduler type, cannot determine client type." ) + + +class ShellException(Exception): + """Exception class to improve readability of the subprocess.CalledProcessError""" + + def __init__(self, called_process_error: sp.CalledProcessError): + """Constructor + + Parameters + ---------- + called_process_error : sp.CalledProcessError + Source subprocess.CalledError + """ + self.returncode = called_process_error.returncode + self.cmd = called_process_error.cmd[0] + self.stdout = called_process_error.stdout.decode() + self.stderr = called_process_error.stderr.decode() + self.output = called_process_error.output + + def __str__(self): + """Improved string representation of the error message. + + Returns + ------- + str + Improved error messaging + """ + return f"Error {self.returncode}: {self.stderr}" diff --git a/hpcpy/utilities.py b/hpcpy/utilities.py index 497f7c3..18f1dff 100644 --- a/hpcpy/utilities.py +++ b/hpcpy/utilities.py @@ -5,6 +5,7 @@ import jinja2.meta as j2m from pathlib import Path from importlib import resources +from hpcpy.exceptions import ShellException import shlex @@ -27,11 +28,19 @@ def shell(cmd, check=True, capture_output=True, **kwargs) -> sp.CompletedProcess Raises ------ - subprocess.CalledProcessError + hpcypy.excetions.ShellException : + When the shell call fails. """ - return sp.run( - shlex.split(cmd), check=check, capture_output=capture_output, **kwargs - ) + try: + return sp.run( + shlex.split(cmd), + shell=True, + check=check, + capture_output=capture_output, + **kwargs, + ) + except sp.CalledProcessError as ex: + raise ShellException(ex) def interpolate_string_template(template, **kwargs) -> str: diff --git a/tests/test_utilities.py b/tests/test_utilities.py index ac837dd..3521f32 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -1,8 +1,17 @@ """Tests for utilities.py""" import hpcpy.utilities as hu +import hpcpy.exceptions as hx def test_interpolate_string_template(): """Test interpolating a string template.""" assert hu.interpolate_string_template("hello {{arg}}", arg="world") == "hello world" + + +def test_shell_exception(): + """Test that error messaging is being raised to the user.""" + try: + hu.shell("blah") + except hx.ShellException as ex: + assert ex.__str__() == "Error 127: /bin/sh: blah: command not found\n"