Home | History | Annotate | Download | only in googleapiclient
      1 # Copyright 2014 Google Inc. All Rights Reserved.
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 """Errors for the library.
     16 
     17 All exceptions defined by the library
     18 should be defined in this file.
     19 """
     20 from __future__ import absolute_import
     21 
     22 __author__ = 'jcgregorio (at] google.com (Joe Gregorio)'
     23 
     24 import json
     25 
     26 from googleapiclient import _helpers as util
     27 
     28 
     29 class Error(Exception):
     30   """Base error for this module."""
     31   pass
     32 
     33 
     34 class HttpError(Error):
     35   """HTTP data was invalid or unexpected."""
     36 
     37   @util.positional(3)
     38   def __init__(self, resp, content, uri=None):
     39     self.resp = resp
     40     if not isinstance(content, bytes):
     41         raise TypeError("HTTP content should be bytes")
     42     self.content = content
     43     self.uri = uri
     44     self.error_details = ''
     45 
     46   def _get_reason(self):
     47     """Calculate the reason for the error from the response content."""
     48     reason = self.resp.reason
     49     try:
     50       data = json.loads(self.content.decode('utf-8'))
     51       if isinstance(data, dict):
     52         reason = data['error']['message']
     53         if 'details' in data['error']:
     54             self.error_details = data['error']['details']
     55       elif isinstance(data, list) and len(data) > 0:
     56         first_error = data[0]
     57         reason = first_error['error']['message']
     58         if 'details' in first_error['error']:
     59             self.error_details = first_error['error']['details']
     60     except (ValueError, KeyError, TypeError):
     61       pass
     62     if reason is None:
     63       reason = ''
     64     return reason
     65 
     66   def __repr__(self):
     67     reason = self._get_reason()
     68     if self.error_details:
     69       return '<HttpError %s when requesting %s returned "%s". Details: "%s">' % \
     70              (self.resp.status, self.uri, reason.strip(), self.error_details)
     71     elif self.uri:
     72       return '<HttpError %s when requesting %s returned "%s">' % (
     73           self.resp.status, self.uri, self._get_reason().strip())
     74     else:
     75       return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
     76 
     77   __str__ = __repr__
     78 
     79 
     80 class InvalidJsonError(Error):
     81   """The JSON returned could not be parsed."""
     82   pass
     83 
     84 
     85 class UnknownFileType(Error):
     86   """File type unknown or unexpected."""
     87   pass
     88 
     89 
     90 class UnknownLinkType(Error):
     91   """Link type unknown or unexpected."""
     92   pass
     93 
     94 
     95 class UnknownApiNameOrVersion(Error):
     96   """No API with that name and version exists."""
     97   pass
     98 
     99 
    100 class UnacceptableMimeTypeError(Error):
    101   """That is an unacceptable mimetype for this operation."""
    102   pass
    103 
    104 
    105 class MediaUploadSizeError(Error):
    106   """Media is larger than the method can accept."""
    107   pass
    108 
    109 
    110 class ResumableUploadError(HttpError):
    111   """Error occured during resumable upload."""
    112   pass
    113 
    114 
    115 class InvalidChunkSizeError(Error):
    116   """The given chunksize is not valid."""
    117   pass
    118 
    119 class InvalidNotificationError(Error):
    120   """The channel Notification is invalid."""
    121   pass
    122 
    123 class BatchError(HttpError):
    124   """Error occured during batch operations."""
    125 
    126   @util.positional(2)
    127   def __init__(self, reason, resp=None, content=None):
    128     self.resp = resp
    129     self.content = content
    130     self.reason = reason
    131 
    132   def __repr__(self):
    133     if getattr(self.resp, 'status', None) is None:
    134       return '<BatchError "%s">' % (self.reason)
    135     else:
    136       return '<BatchError %s "%s">' % (self.resp.status, self.reason)
    137 
    138   __str__ = __repr__
    139 
    140 
    141 class UnexpectedMethodError(Error):
    142   """Exception raised by RequestMockBuilder on unexpected calls."""
    143 
    144   @util.positional(1)
    145   def __init__(self, methodId=None):
    146     """Constructor for an UnexpectedMethodError."""
    147     super(UnexpectedMethodError, self).__init__(
    148         'Received unexpected call %s' % methodId)
    149 
    150 
    151 class UnexpectedBodyError(Error):
    152   """Exception raised by RequestMockBuilder on unexpected bodies."""
    153 
    154   def __init__(self, expected, provided):
    155     """Constructor for an UnexpectedMethodError."""
    156     super(UnexpectedBodyError, self).__init__(
    157         'Expected: [%s] - Provided: [%s]' % (expected, provided))
    158