Source code for galaxy.exceptions

"""This module defines Galaxy's custom exceptions.

A Galaxy exception is an exception that extends :class:`MessageException` which
defines an HTTP status code (represented by the `status_code` attribute) and a
default error message.

New exceptions should be defined by adding an entry to `error_codes.json` in this
directory to define a default error message and a Galaxy "error code". A concrete
Python class should be added in this file defining an HTTP status code (as
`status_code`) and error code (`error_code`) object loaded dynamically from
`error_codes.json`.

Reflecting Galaxy's origins as a web application, these exceptions tend to be a
bit web-oriented. However this module is a dependency of modules and tools that
have nothing to do with the web - keep this in mind when defining exception names
and messages.
"""

from typing import Optional

from .error_codes import (
    error_codes_by_name,
    ErrorCode,
)


[docs]class MessageException(Exception): """Most generic Galaxy exception - indicates merely that some exceptional condition happened.""" # status code to be set when used with API. status_code: int = 400 # Error code information embedded into API json responses. err_code: ErrorCode = error_codes_by_name["UNKNOWN"]
[docs] def __init__(self, err_msg: Optional[str] = None, type="info", **extra_error_info): self.err_msg = err_msg or self.err_code.default_error_message self.type = type self.extra_error_info = extra_error_info
[docs] @staticmethod def from_code(status_code, message): exception_class = MessageException if status_code == 404: exception_class = ObjectNotFound elif status_code / 100 == 5: exception_class = InternalServerError return exception_class(message)
def __str__(self): return self.err_msg
[docs]class ItemDeletionException(MessageException): pass
[docs]class ObjectInvalid(Exception): """Accessed object store ID is invalid"""
# Please keep the exceptions ordered by status code
[docs]class AcceptedRetryLater(MessageException): status_code = 202 err_code = error_codes_by_name["ACCEPTED_RETRY_LATER"] retry_after: int
[docs] def __init__(self, msg: Optional[str] = None, retry_after=60): super().__init__(msg) self.retry_after = retry_after
[docs]class NoContentException(MessageException): status_code = 204 err_code = error_codes_by_name["NO_CONTENT_GENERIC"]
[docs]class ActionInputError(MessageException): status_code = 400 err_code = error_codes_by_name["USER_REQUEST_INVALID_PARAMETER"]
[docs] def __init__(self, err_msg, type="error"): super().__init__(err_msg, type)
[docs]class DuplicatedSlugException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_SLUG_DUPLICATE"]
[docs]class DuplicatedIdentifierException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_IDENTIFIER_DUPLICATE"]
[docs]class ObjectAttributeInvalidException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_OBJECT_ATTRIBUTE_INVALID"]
[docs]class ObjectAttributeMissingException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_OBJECT_ATTRIBUTE_MISSING"]
[docs]class MalformedId(MessageException): status_code = 400 err_code = error_codes_by_name["MALFORMED_ID"]
[docs]class UserInvalidRunAsException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_INVALID_RUN_AS"]
[docs]class MalformedContents(MessageException): status_code = 400 err_code = error_codes_by_name["MALFORMED_CONTENTS"]
[docs]class UnknownContentsType(MessageException): status_code = 400 err_code = error_codes_by_name["UNKNOWN_CONTENTS_TYPE"]
[docs]class RequestParameterMissingException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_REQUEST_MISSING_PARAMETER"]
[docs]class ToolMetaParameterException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_TOOL_META_PARAMETER_PROBLEM"]
[docs]class ToolMissingException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_TOOL_MISSING_PROBLEM"]
[docs] def __init__(self, err_msg: Optional[str] = None, type="info", tool_id=None, **extra_error_info): super().__init__(err_msg, type, **extra_error_info) self.tool_id = tool_id
[docs]class RequestParameterInvalidException(MessageException): status_code = 400 err_code = error_codes_by_name["USER_REQUEST_INVALID_PARAMETER"]
[docs]class ToolInputsNotReadyException(MessageException): status_code = 400 error_code = error_codes_by_name["TOOL_INPUTS_NOT_READY"]
[docs]class ToolInputsNotOKException(MessageException):
[docs] def __init__(self, err_msg: Optional[str] = None, type="info", *, src: str, id: int, **extra_error_info): super().__init__(err_msg, type, **extra_error_info) self.src = src self.id = id
status_code = 400 error_code = error_codes_by_name["TOOL_INPUTS_NOT_OK"]
[docs]class RealUserRequiredException(MessageException): status_code = 400 error_code = error_codes_by_name["REAL_USER_REQUIRED"]
[docs]class AuthenticationFailed(MessageException): status_code = 401 err_code = error_codes_by_name["USER_AUTHENTICATION_FAILED"]
[docs]class AuthenticationRequired(MessageException): status_code = 403 # TODO: as 401 and send WWW-Authenticate: ??? err_code = error_codes_by_name["USER_NO_API_KEY"]
[docs]class ItemAccessibilityException(MessageException): status_code = 403 err_code = error_codes_by_name["USER_CANNOT_ACCESS_ITEM"]
[docs]class ItemOwnershipException(MessageException): status_code = 403 err_code = error_codes_by_name["USER_DOES_NOT_OWN_ITEM"]
[docs]class ItemImmutableException(MessageException): status_code = 403 err_code = error_codes_by_name["ITEM_IS_IMMUTABLE"]
[docs]class ConfigDoesNotAllowException(MessageException): status_code = 403 err_code = error_codes_by_name["CONFIG_DOES_NOT_ALLOW"]
[docs]class InsufficientPermissionsException(MessageException): status_code = 403 err_code = error_codes_by_name["INSUFFICIENT_PERMISSIONS"]
[docs]class UserCannotRunAsException(MessageException): status_code = 403 err_code = error_codes_by_name["USER_CANNOT_RUN_AS"]
[docs]class UserRequiredException(MessageException): status_code = 403 err_code = error_codes_by_name["USER_REQUIRED"]
[docs]class AdminRequiredException(MessageException): status_code = 403 err_code = error_codes_by_name["ADMIN_REQUIRED"]
[docs]class UserActivationRequiredException(MessageException): status_code = 403 err_code = error_codes_by_name["USER_ACTIVATION_REQUIRED"]
[docs]class ObjectNotFound(MessageException): """Accessed object was not found""" status_code = 404 err_code = error_codes_by_name["USER_OBJECT_NOT_FOUND"]
[docs]class Conflict(MessageException): status_code = 409 err_code = error_codes_by_name["CONFLICT"]
[docs]class DeprecatedMethod(MessageException): """ Method (or a particular form/arg signature) has been removed and won't be available later """ status_code = 410 err_code = error_codes_by_name["DEPRECATED_API_CALL"]
[docs]class ConfigurationError(Exception): status_code = 500 err_code = error_codes_by_name["CONFIG_ERROR"]
[docs]class InconsistentDatabase(MessageException): status_code = 500 err_code = error_codes_by_name["INCONSISTENT_DATABASE"]
[docs]class InternalServerError(MessageException): status_code = 500 err_code = error_codes_by_name["INTERNAL_SERVER_ERROR"]
[docs]class ToolExecutionError(MessageException): status_code = 500 err_code = error_codes_by_name["TOOL_EXECUTION_ERROR"]
[docs] def __init__(self, err_msg, type="error", job=None): super().__init__(err_msg, type) self.job = job
[docs]class NotImplemented(MessageException): status_code = 501 err_code = error_codes_by_name["NOT_IMPLEMENTED"]
[docs]class InvalidFileFormatError(MessageException): status_code = 500 err_code = error_codes_by_name["INVALID_FILE_FORMAT"]
[docs]class ReferenceDataError(MessageException): status_code = 500 err_code = error_codes_by_name["REFERENCE_DATA_ERROR"]
[docs]class ServerNotConfiguredForRequest(MessageException): # A bit like ConfigDoesNotAllowException but it has nothing to do with the user of the # request being "forbidden". It just isn't configured. status_code = 501 err_code = error_codes_by_name["SERVER_NOT_CONFIGURED_FOR_REQUEST"]
[docs]class HandlerAssignmentError(Exception):
[docs] def __init__(self, msg=None, obj=None, **kwargs): super().__init__(msg) self.obj = obj