codekingpro/portable-devtools
114k
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 at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# 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 and13# limitations under the License.14 15"""Errors for the library.16 17All exceptions defined by the library18should be defined in this file.19"""20from __future__ import absolute_import21 22__author__ = "jcgregorio@google.com (Joe Gregorio)"23 24import json25 26from googleapiclient import _helpers as util27 28 29class Error(Exception):30 """Base error for this module."""31 32 pass33 34 35class HttpError(Error):36 """HTTP data was invalid or unexpected."""37 38 @util.positional(3)39 def __init__(self, resp, content, uri=None):40 self.resp = resp41 if not isinstance(content, bytes):42 raise TypeError("HTTP content should be bytes")43 self.content = content44 self.uri = uri45 self.error_details = ""46 self.reason = self._get_reason()47 48 @property49 def status_code(self):50 """Return the HTTP status code from the response content."""51 return self.resp.status52 53 def _get_reason(self):54 """Calculate the reason for the error from the response content."""55 reason = self.resp.reason56 try:57 try:58 data = json.loads(self.content.decode("utf-8"))59 except json.JSONDecodeError:60 # In case it is not json61 data = self.content.decode("utf-8")62 if isinstance(data, dict):63 reason = data["error"]["message"]64 error_detail_keyword = next(65 (66 kw67 for kw in ["detail", "details", "errors", "message"]68 if kw in data["error"]69 ),70 "",71 )72 if error_detail_keyword:73 self.error_details = data["error"][error_detail_keyword]74 elif isinstance(data, list) and len(data) > 0:75 first_error = data[0]76 reason = first_error["error"]["message"]77 if "details" in first_error["error"]:78 self.error_details = first_error["error"]["details"]79 else:80 self.error_details = data81 except (ValueError, KeyError, TypeError):82 pass83 if reason is None:84 reason = ""85 return reason.strip()86 87 def __repr__(self):88 if self.error_details:89 return '<HttpError %s when requesting %s returned "%s". Details: "%s">' % (90 self.resp.status,91 self.uri,92 self.reason,93 self.error_details,94 )95 elif self.uri:96 return '<HttpError %s when requesting %s returned "%s">' % (97 self.resp.status,98 self.uri,99 self.reason,100 )101 else:102 return '<HttpError %s "%s">' % (self.resp.status, self.reason)103 104 __str__ = __repr__105 106 107class InvalidJsonError(Error):108 """The JSON returned could not be parsed."""109 110 pass111 112 113class UnknownFileType(Error):114 """File type unknown or unexpected."""115 116 pass117 118 119class UnknownLinkType(Error):120 """Link type unknown or unexpected."""121 122 pass123 124 125class UnknownApiNameOrVersion(Error):126 """No API with that name and version exists."""127 128 pass129 130 131class UnacceptableMimeTypeError(Error):132 """That is an unacceptable mimetype for this operation."""133 134 pass135 136 137class MediaUploadSizeError(Error):138 """Media is larger than the method can accept."""139 140 pass141 142 143class ResumableUploadError(HttpError):144 """Error occurred during resumable upload."""145 146 pass147 148 149class InvalidChunkSizeError(Error):150 """The given chunksize is not valid."""151 152 pass153 154 155class InvalidNotificationError(Error):156 """The channel Notification is invalid."""157 158 pass159 160 161class BatchError(HttpError):162 """Error occurred during batch operations."""163 164 @util.positional(2)165 def __init__(self, reason, resp=None, content=None):166 self.resp = resp167 self.content = content168 self.reason = reason169 170 def __repr__(self):171 if getattr(self.resp, "status", None) is None:172 return '<BatchError "%s">' % (self.reason)173 else:174 return '<BatchError %s "%s">' % (self.resp.status, self.reason)175 176 __str__ = __repr__177 178 179class UnexpectedMethodError(Error):180 """Exception raised by RequestMockBuilder on unexpected calls."""181 182 @util.positional(1)183 def __init__(self, methodId=None):184 """Constructor for an UnexpectedMethodError."""185 super(UnexpectedMethodError, self).__init__(186 "Received unexpected call %s" % methodId187 )188 189 190class UnexpectedBodyError(Error):191 """Exception raised by RequestMockBuilder on unexpected bodies."""192 193 def __init__(self, expected, provided):194 """Constructor for an UnexpectedMethodError."""195 super(UnexpectedBodyError, self).__init__(196 "Expected: [%s] - Provided: [%s]" % (expected, provided)197 )198 