Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
model.py410 linesDownload Raw Back to 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 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"""Model objects for requests and responses.16 17Each API may support one or more serializations, such18as JSON, Atom, etc. The model classes are responsible19for converting between the wire format and the Python20object representation.21"""22from __future__ import absolute_import23 24__author__ = "jcgregorio@google.com (Joe Gregorio)"25 26import json27import logging28import platform29import urllib30 31from googleapiclient import version as googleapiclient_version32from googleapiclient.errors import HttpError33 34_LIBRARY_VERSION = googleapiclient_version.__version__35_PY_VERSION = platform.python_version()36 37LOGGER = logging.getLogger(__name__)38 39dump_request_response = False40 41 42def _abstract():43    raise NotImplementedError("You need to override this function")44 45 46class Model(object):47    """Model base class.48 49    All Model classes should implement this interface.50    The Model serializes and de-serializes between a wire51    format such as JSON and a Python object representation.52    """53 54    def request(self, headers, path_params, query_params, body_value):55        """Updates outgoing requests with a serialized body.56 57        Args:58          headers: dict, request headers59          path_params: dict, parameters that appear in the request path60          query_params: dict, parameters that appear in the query61          body_value: object, the request body as a Python object, which must be62                      serializable.63        Returns:64          A tuple of (headers, path_params, query, body)65 66          headers: dict, request headers67          path_params: dict, parameters that appear in the request path68          query: string, query part of the request URI69          body: string, the body serialized in the desired wire format.70        """71        _abstract()72 73    def response(self, resp, content):74        """Convert the response wire format into a Python object.75 76        Args:77          resp: httplib2.Response, the HTTP response headers and status78          content: string, the body of the HTTP response79 80        Returns:81          The body de-serialized as a Python object.82 83        Raises:84          googleapiclient.errors.HttpError if a non 2xx response is received.85        """86        _abstract()87 88 89class BaseModel(Model):90    """Base model class.91 92    Subclasses should provide implementations for the "serialize" and93    "deserialize" methods, as well as values for the following class attributes.94 95    Attributes:96      accept: The value to use for the HTTP Accept header.97      content_type: The value to use for the HTTP Content-type header.98      no_content_response: The value to return when deserializing a 204 "No99          Content" response.100      alt_param: The value to supply as the "alt" query parameter for requests.101    """102 103    accept = None104    content_type = None105    no_content_response = None106    alt_param = None107 108    def _log_request(self, headers, path_params, query, body):109        """Logs debugging information about the request if requested."""110        if dump_request_response:111            LOGGER.info("--request-start--")112            LOGGER.info("-headers-start-")113            for h, v in headers.items():114                LOGGER.info("%s: %s", h, v)115            LOGGER.info("-headers-end-")116            LOGGER.info("-path-parameters-start-")117            for h, v in path_params.items():118                LOGGER.info("%s: %s", h, v)119            LOGGER.info("-path-parameters-end-")120            LOGGER.info("body: %s", body)121            LOGGER.info("query: %s", query)122            LOGGER.info("--request-end--")123 124    def request(self, headers, path_params, query_params, body_value):125        """Updates outgoing requests with a serialized body.126 127        Args:128          headers: dict, request headers129          path_params: dict, parameters that appear in the request path130          query_params: dict, parameters that appear in the query131          body_value: object, the request body as a Python object, which must be132                      serializable by json.133        Returns:134          A tuple of (headers, path_params, query, body)135 136          headers: dict, request headers137          path_params: dict, parameters that appear in the request path138          query: string, query part of the request URI139          body: string, the body serialized as JSON140        """141        query = self._build_query(query_params)142        headers["accept"] = self.accept143        headers["accept-encoding"] = "gzip, deflate"144        if "user-agent" in headers:145            headers["user-agent"] += " "146        else:147            headers["user-agent"] = ""148        headers["user-agent"] += "(gzip)"149        if "x-goog-api-client" in headers:150            headers["x-goog-api-client"] += " "151        else:152            headers["x-goog-api-client"] = ""153        headers["x-goog-api-client"] += "gdcl/%s gl-python/%s" % (154            _LIBRARY_VERSION,155            _PY_VERSION,156        )157 158        if body_value is not None:159            headers["content-type"] = self.content_type160            body_value = self.serialize(body_value)161        self._log_request(headers, path_params, query, body_value)162        return (headers, path_params, query, body_value)163 164    def _build_query(self, params):165        """Builds a query string.166 167        Args:168          params: dict, the query parameters169 170        Returns:171          The query parameters properly encoded into an HTTP URI query string.172        """173        if self.alt_param is not None:174            params.update({"alt": self.alt_param})175        astuples = []176        for key, value in params.items():177            if type(value) == type([]):178                for x in value:179                    x = x.encode("utf-8")180                    astuples.append((key, x))181            else:182                if isinstance(value, str) and callable(value.encode):183                    value = value.encode("utf-8")184                astuples.append((key, value))185        return "?" + urllib.parse.urlencode(astuples)186 187    def _log_response(self, resp, content):188        """Logs debugging information about the response if requested."""189        if dump_request_response:190            LOGGER.info("--response-start--")191            for h, v in resp.items():192                LOGGER.info("%s: %s", h, v)193            if content:194                LOGGER.info(content)195            LOGGER.info("--response-end--")196 197    def response(self, resp, content):198        """Convert the response wire format into a Python object.199 200        Args:201          resp: httplib2.Response, the HTTP response headers and status202          content: string, the body of the HTTP response203 204        Returns:205          The body de-serialized as a Python object.206 207        Raises:208          googleapiclient.errors.HttpError if a non 2xx response is received.209        """210        self._log_response(resp, content)211        # Error handling is TBD, for example, do we retry212        # for some operation/error combinations?213        if resp.status < 300:214            if resp.status == 204:215                # A 204: No Content response should be treated differently216                # to all the other success states217                return self.no_content_response218            return self.deserialize(content)219        else:220            LOGGER.debug("Content from bad request was: %r" % content)221            raise HttpError(resp, content)222 223    def serialize(self, body_value):224        """Perform the actual Python object serialization.225 226        Args:227          body_value: object, the request body as a Python object.228 229        Returns:230          string, the body in serialized form.231        """232        _abstract()233 234    def deserialize(self, content):235        """Perform the actual deserialization from response string to Python236        object.237 238        Args:239          content: string, the body of the HTTP response240 241        Returns:242          The body de-serialized as a Python object.243        """244        _abstract()245 246 247class JsonModel(BaseModel):248    """Model class for JSON.249 250    Serializes and de-serializes between JSON and the Python251    object representation of HTTP request and response bodies.252    """253 254    accept = "application/json"255    content_type = "application/json"256    alt_param = "json"257 258    def __init__(self, data_wrapper=False):259        """Construct a JsonModel.260 261        Args:262          data_wrapper: boolean, wrap requests and responses in a data wrapper263        """264        self._data_wrapper = data_wrapper265 266    def serialize(self, body_value):267        if (268            isinstance(body_value, dict)269            and "data" not in body_value270            and self._data_wrapper271        ):272            body_value = {"data": body_value}273        return json.dumps(body_value)274 275    def deserialize(self, content):276        try:277            content = content.decode("utf-8")278        except AttributeError:279            pass280        try:281            body = json.loads(content)282        except json.decoder.JSONDecodeError:283            body = content284        else:285            if self._data_wrapper and "data" in body:286                body = body["data"]287        return body288 289    @property290    def no_content_response(self):291        return {}292 293 294class RawModel(JsonModel):295    """Model class for requests that don't return JSON.296 297    Serializes and de-serializes between JSON and the Python298    object representation of HTTP request, and returns the raw bytes299    of the response body.300    """301 302    accept = "*/*"303    content_type = "application/json"304    alt_param = None305 306    def deserialize(self, content):307        return content308 309    @property310    def no_content_response(self):311        return ""312 313 314class MediaModel(JsonModel):315    """Model class for requests that return Media.316 317    Serializes and de-serializes between JSON and the Python318    object representation of HTTP request, and returns the raw bytes319    of the response body.320    """321 322    accept = "*/*"323    content_type = "application/json"324    alt_param = "media"325 326    def deserialize(self, content):327        return content328 329    @property330    def no_content_response(self):331        return ""332 333 334class ProtocolBufferModel(BaseModel):335    """Model class for protocol buffers.336 337    Serializes and de-serializes the binary protocol buffer sent in the HTTP338    request and response bodies.339    """340 341    accept = "application/x-protobuf"342    content_type = "application/x-protobuf"343    alt_param = "proto"344 345    def __init__(self, protocol_buffer):346        """Constructs a ProtocolBufferModel.347 348        The serialized protocol buffer returned in an HTTP response will be349        de-serialized using the given protocol buffer class.350 351        Args:352          protocol_buffer: The protocol buffer class used to de-serialize a353          response from the API.354        """355        self._protocol_buffer = protocol_buffer356 357    def serialize(self, body_value):358        return body_value.SerializeToString()359 360    def deserialize(self, content):361        return self._protocol_buffer.FromString(content)362 363    @property364    def no_content_response(self):365        return self._protocol_buffer()366 367 368def makepatch(original, modified):369    """Create a patch object.370 371    Some methods support PATCH, an efficient way to send updates to a resource.372    This method allows the easy construction of patch bodies by looking at the373    differences between a resource before and after it was modified.374 375    Args:376      original: object, the original deserialized resource377      modified: object, the modified deserialized resource378    Returns:379      An object that contains only the changes from original to modified, in a380      form suitable to pass to a PATCH method.381 382    Example usage:383      item = service.activities().get(postid=postid, userid=userid).execute()384      original = copy.deepcopy(item)385      item['object']['content'] = 'This is updated.'386      service.activities.patch(postid=postid, userid=userid,387        body=makepatch(original, item)).execute()388    """389    patch = {}390    for key, original_value in original.items():391        modified_value = modified.get(key, None)392        if modified_value is None:393            # Use None to signal that the element is deleted394            patch[key] = None395        elif original_value != modified_value:396            if type(original_value) == type({}):397                # Recursively descend objects398                patch[key] = makepatch(original_value, modified_value)399            else:400                # In the case of simple types or arrays we just replace401                patch[key] = modified_value402        else:403            # Don't add anything to patch if there's no change404            pass405    for key in modified:406        if key not in original:407            patch[key] = modified[key]408 409    return patch410 
codekingpro/portable-devtools · Team Ai