Source code for chemistry_tools.pubchem.errors

#  !/usr/bin/env python
#
#  errors.py
"""
Error handling.
"""
#  Copyright (c) 2019-2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation; either version 3 of the
#  License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#  Based on PubChemPy https://github.com/mcs07/PubChemPy/blob/master/LICENSE
#  |  Copyright 2014 Matt Swain <m.swain@me.com>
#  |  Licensed under the MIT License
#  |
#  |  Permission is hereby granted, free of charge, to any person obtaining a copy
#  |  of this software and associated documentation files (the "Software"), to deal
#  |  in the Software without restriction, including without limitation the rights
#  |  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  |  copies of the Software, and to permit persons to whom the Software is
#  |  furnished to do so, subject to the following conditions:
#
#  |  The above copyright notice and this permission notice shall be included in
#  |  all copies or substantial portions of the Software.
#
#  |  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  |  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  |  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  |  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  |  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  |  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  |  THE SOFTWARE.
#

# stdlib
import json

# 3rd party
import requests

__all__ = [
		"ResponseParseError",
		"PubChemHTTPError",
		"BadRequestError",
		"NotFoundError",
		"MethodNotAllowedError",
		"TimeoutError",
		"HTTPTimeoutError",
		"UnimplementedError",
		"ServerError",
		"HTTP_ERROR_CODES",
		]

#: Numerical list of HTTP status codes considered to be errors.
HTTP_ERROR_CODES = [
		400,  # Bad Request
		401,  # Unauthorized
		402,  # Payment Required
		403,  # Forbidden
		404,  # Not Found
		405,  # Method Not Allowed
		406,  # Not Acceptable
		407,  # Proxy Authentication Required
		408,  # Request Timeout
		409,  # Conflict
		410,  # Gone
		411,  # Length Required
		412,  # Precondition Failed
		413,  # Payload Too Large
		414,  # URI Too Long
		415,  # Unsupported Media Type
		416,  # Range Not Satisfiable
		417,  # Expectation Failed
		421,  # Misdirected Request
		422,  # Unprocessable Entity
		423,  # Locked
		424,  # Failed Dependency
		425,  # Too Early
		426,  # Upgrade Required
		428,  # Precondition Required
		429,  # Too Many Requests
		431,  # Request Header Fields Too Large
		451,  # Unavailable For Legal Reasons
		500,  # Internal Server Error
		501,  # Not Implemented
		502,  # Bad Gateway
		503,  # Service Unavailable
		504,  # Gateway Timeout
		505,  # HTTP Version Not Supported
		506,  # Variant Also Negotiates
		507,  # Insufficient Storage
		508,  # Loop Detected
		509,  # Not Extended
		511,  # Network Authentication Required
		]


[docs]class ResponseParseError(Exception): """ PubChem response is uninterpretable. """
[docs]class PubChemHTTPError(Exception): """ Generic error class to handle all HTTP error codes. """ def __init__(self, e: requests.Response): self.code = e.status_code self.msg = e.reason try: self.msg += f': {json.loads(e.content.decode())["Fault"]["Details"][0]}' except (ValueError, IndexError, KeyError): pass if self.code == 400: raise BadRequestError(self.msg) elif self.code == 404: raise NotFoundError(self.msg) elif self.code == 405: raise MethodNotAllowedError(self.msg) elif self.code == 504: raise HTTPTimeoutError(self.msg) elif self.code == 501: raise UnimplementedError(self.msg) elif self.code == 500: raise ServerError(self.msg)
[docs] def __str__(self) -> str: return repr(self.msg)
[docs]class BadRequestError(PubChemHTTPError): """ Request is improperly formed (syntax error in the URL, POST body, etc.). """ def __init__(self, msg: str = "Request is improperly formed"): self.msg = msg
[docs]class NotFoundError(PubChemHTTPError): """ The input record was not found (e.g. invalid CID). """ def __init__(self, msg: str = "The input record was not found"): self.msg = msg
[docs]class MethodNotAllowedError(PubChemHTTPError): """ Request not allowed (such as invalid MIME type in the HTTP Accept header). """ def __init__(self, msg: str = "Request not allowed"): self.msg = msg
[docs]class HTTPTimeoutError(PubChemHTTPError): """ The request timed out, from server overload or too broad a request. .. versionchanged:: 0.4.0 Renamed from TimeoutErrpr """ def __init__(self, msg: str = "The request timed out"): self.msg = msg
TimeoutError = HTTPTimeoutError # noqa: A001 # pylint: disable=redefined-builtin
[docs]class UnimplementedError(PubChemHTTPError): """ The requested operation has not (yet) been implemented by the server. """ def __init__(self, msg: str = "The requested operation has not been implemented"): self.msg = msg
[docs]class ServerError(PubChemHTTPError): """ Some problem on the server side (such as a database server down, etc.). """ def __init__(self, msg: str = "Some problem on the server side"): self.msg = msg