@classmethod
    def perform(cls, session, validate, *args, **kwargs):
        """Send, parse, validate and check success of this call.
        *args and **kwargs are passed to protocol.build_transaction.

        :param session: a PlaySession used to send this request.
        :param validate: if False, do not validate
        """
        # TODO link up these docs

        call_name = cls.__name__

        if cls.gets_logged:
            log.debug("%s(args=%s, kwargs=%s)",
                      call_name,
                      [utils.truncate(a) for a in args],
                      dict((k, utils.truncate(v)) for (k, v) in kwargs.items())
                      )
        else:
            log.debug("%s(<omitted>)", call_name)

        req_kwargs = cls.build_request(*args, **kwargs)

        response = session.send(req_kwargs, cls.required_auth)
        # TODO trim the logged response if it's huge?

        safe_req_kwargs = req_kwargs.copy()
        if safe_req_kwargs.get('headers', {}).get('Authorization', None) is not None:
            safe_req_kwargs['headers']['Authorization'] = '<omitted>'

        if cls.fail_on_non_200:
            try:
                response.raise_for_status()
            except requests.HTTPError as e:
                err_msg = str(e)

                if cls.gets_logged:
                    err_msg += "\n(requests kwargs: %r)" % (safe_req_kwargs)
                    err_msg += "\n(response was: %r)" % response.text

                raise CallFailure(err_msg, call_name)

        try:
            parsed_response = cls.parse_response(response)
        except ParseException:
            err_msg = ("the server's response could not be understood."
                       " The call may still have succeeded, but it's unlikely.")
            if cls.gets_logged:
                err_msg += "\n(requests kwargs: %r)" % (safe_req_kwargs)
                err_msg += "\n(response was: %r)" % response.text
                log.exception("could not parse %s response: %r", call_name, response.text)
            else:
                log.exception("could not parse %s response: (omitted)", call_name)

            raise CallFailure(err_msg, call_name)

        if cls.gets_logged:
            log.debug(cls.filter_response(parsed_response))

        try:
            # order is important; validate only has a schema for a successful response
            cls.check_success(response, parsed_response)
            if validate:
                cls.validate(response, parsed_response)
        except CallFailure as e:
            if not cls.gets_logged:
                raise

            # otherwise, reraise a new exception with our req/res context
            err_msg = ("{e_message}\n"
                       "(requests kwargs: {req_kwargs!r})\n"
                       "(response was: {content!r})").format(
                           e_message=str(e),
                           req_kwargs=safe_req_kwargs,
                           content=response.text)
            raise_from(CallFailure(err_msg, e.callname), e)

        except ValidationException as e:
            # TODO shouldn't be using formatting
            err_msg = "the response format for %s was not recognized." % call_name
            err_msg += "\n\n%s\n" % e

            if cls.gets_logged:
                raw_response = response.text

                if len(raw_response) > 10000:
                    raw_response = raw_response[:10000] + '...'

                err_msg += ("\nFirst, try the develop branch."
                            " If you can recreate this error with the most recent code"
                            " please [create an issue](http://goo.gl/qbAW8) that includes"
                            " the above ValidationException"
                            " and the following request/response:\n%r\n\n%r\n"
                            "\nA traceback follows:\n") % (safe_req_kwargs, raw_response)

            log.exception(err_msg)

        return parsed_response
dataset/ETHPy150Open simon-weber/gmusicapi/gmusicapi/protocol/shared.py/Call.perform/original