Source code for ymp.exceptions

"""Exceptions raised by YMP"""

import textwrap
from inspect import stack
from typing import Optional

from click import ClickException, echo


[docs]class YmpException(Exception): """Base class of all YMP Exceptions"""
[docs]class YmpNoStackException(YmpException, ClickException): """Exception that does not lead to stack trace on CLI Inheriting from ClickException makes ``click`` print only the ``self.msg`` value of the exception, rather than allowing Python to print a full stack trace. This is useful for exceptions indicating usage or configuration errors. We use this, instead of `click.UsageError` and friends so that the exceptions can be caught and handled explicitly where needed. Note that click will call the ``show`` method on this object to print the exception. The default implementation from click will just prefix the ``msg`` with ``Error:``. FIXME: This does not work if the exception is raised from within the snakemake workflow as snakemake.snakemake catches and reformats exceptions. """
[docs]class YmpUsageError(YmpNoStackException): pass
[docs]class YmpSystemError(YmpNoStackException): """Indicates problem running YMP with available system software"""
[docs]class YmpRuleError(YmpNoStackException): """Indicates an error in the rules files This could e.g. be a Stage or Environment defined twice. Args: obj: The object causing the exception. Must have ``lineno`` and ``filename`` as these will be shown as part of the error message on the command line. msg: The message to display """ def __init__(self, obj: object, msg: str) -> None: self.obj = obj self.stack = stack() super().__init__(msg)
[docs] def show(self) -> None: echo('Error in line %i of %s:\n%s' % ( getattr(self.obj, "lineno", -1), getattr(self.obj, "filename", "<NOT FOUND>"), self.format_message() ), err=True) for fi in self.stack: if not fi.filename.endswith(".py"): echo(f" included from {fi.filename}:{fi.lineno}")
[docs]class YmpConfigError(YmpNoStackException): """Indicates an error in the ymp.yml config files Args: obj: Subtree of config causing error msg: The message to display key: Key indicating part of ``obj`` causing error exc: Upstream exception causing error """ def __init__(self, obj: object, msg: str, key: Optional[object]=None, exc: Optional[Exception]=None) -> None: self.obj = obj self.stack = stack() self.exc = exc super().__init__(msg)
[docs]class YmpStageError(YmpNoStackException): """Indicates an error in the requested stage stack """ def __init__(self, msg: str) -> None: super().__init__(textwrap.dedent(msg))
[docs] def show(self) -> None: echo(self.format_message(), err=True)
[docs]class YmpWorkflowError(YmpNoStackException): """Indicates an error during workflow execution E.g. failures to expand dynamic variables """