S3/Exceptions.py
21f36f55
 # -*- coding: utf-8 -*-
 
 ## Amazon S3 manager - Exceptions library
 ## Author: Michal Ludvig <michal@logix.cz>
 ##         http://www.logix.cz/michal
 ## License: GPL Version 2
 ## Copyright: TGRMN Software and contributors
 
 from __future__ import absolute_import
 
 from logging import debug, error
 import sys
 import S3.Utils
 from . import ExitCodes
 
f830c10c
 if sys.version_info >= (3, 0):
21f36f55
     PY3 = True
     # In python 3, unicode -> str, and str -> bytes
     unicode = str
 else:
     PY3 = False
 
e4b18b1e
 ## External exceptions
 
 from ssl import SSLError as S3SSLError
 
 try:
     from ssl import CertificateError as S3SSLCertificateError
 except ImportError:
     class S3SSLCertificateError(Exception):
         pass
 
21f36f55
 
 try:
     from xml.etree.ElementTree import ParseError as XmlParseError
 except ImportError:
     # ParseError was only added in python2.7, before ET was raising ExpatError
     from xml.parsers.expat import ExpatError as XmlParseError
 
e4b18b1e
 
 ## s3cmd exceptions
 
21f36f55
 class S3Exception(Exception):
fce333f6
     def __init__(self, message=""):
21f36f55
         self.message = S3.Utils.unicodise(message)
 
     def __str__(self):
         ## Don't return self.message directly because
         ## __unicode__() method could be overridden in subclasses!
         if PY3:
             return self.__unicode__()
         else:
             return S3.Utils.deunicodise(self.__unicode__())
 
     def __unicode__(self):
         return self.message
 
     ## (Base)Exception.message has been deprecated in Python 2.6
     def _get_message(self):
         return self._message
fce333f6
 
21f36f55
     def _set_message(self, message):
         self._message = message
     message = property(_get_message, _set_message)
 
 
 class S3Error (S3Exception):
     def __init__(self, response):
         self.status = response["status"]
         self.reason = response["reason"]
         self.info = {
fce333f6
             "Code": "",
             "Message": "",
             "Resource": ""
21f36f55
         }
         debug("S3Error: %s (%s)" % (self.status, self.reason))
         if "headers" in response:
             for header in response["headers"]:
                 debug("HttpHeader: %s: %s" % (header, response["headers"][header]))
         if "data" in response and response["data"]:
             try:
                 tree = S3.Utils.getTreeFromXml(response["data"])
             except XmlParseError:
                 debug("Not an XML response")
             else:
                 try:
                     self.info.update(self.parse_error_xml(tree))
                 except Exception as e:
                     error("Error parsing xml: %s.  ErrorXML: %s" % (e, response["data"]))
 
         self.code = self.info["Code"]
         self.message = self.info["Message"]
         self.resource = self.info["Resource"]
 
     def __unicode__(self):
         retval = u"%d " % (self.status)
         retval += (u"(%s)" % ("Code" in self.info and self.info["Code"] or self.reason))
         error_msg = self.info.get("Message")
         if error_msg:
             retval += (u": %s" % error_msg)
         return retval
 
     def get_error_code(self):
         if self.status in [301, 307]:
             return ExitCodes.EX_SERVERMOVED
         elif self.status in [400, 405, 411, 416, 417, 501, 504]:
             return ExitCodes.EX_SERVERERROR
         elif self.status == 403:
             return ExitCodes.EX_ACCESSDENIED
         elif self.status == 404:
             return ExitCodes.EX_NOTFOUND
         elif self.status == 409:
             return ExitCodes.EX_CONFLICT
         elif self.status == 412:
             return ExitCodes.EX_PRECONDITION
         elif self.status == 500:
             return ExitCodes.EX_SOFTWARE
fce333f6
         elif self.status in [429, 503]:
21f36f55
             return ExitCodes.EX_SERVICE
         else:
             return ExitCodes.EX_SOFTWARE
 
     @staticmethod
     def parse_error_xml(tree):
         info = {}
         error_node = tree
         if not error_node.tag == "Error":
             error_node = tree.find(".//Error")
         if error_node is not None:
             for child in error_node.getchildren():
                 if child.text != "":
                     debug("ErrorXML: " + child.tag + ": " + repr(child.text))
                     info[child.tag] = child.text
         else:
             raise S3ResponseError("Malformed error XML returned from remote server.")
         return info
 
 
 class CloudFrontError(S3Error):
     pass
 
 class S3UploadError(S3Exception):
     pass
 
 class S3DownloadError(S3Exception):
     pass
 
 class S3RequestError(S3Exception):
     pass
 
 class S3ResponseError(S3Exception):
     pass
 
 class InvalidFileError(S3Exception):
     pass
 
 class ParameterError(S3Exception):
     pass
 
 # vim:et:ts=4:sts=4:ai