コード例 #1
0
def PackRequestAsComplexType(request, version):
    """Pack (recursively) a Python tuple object into a SOAP data holder.

   Args:
     request: instance of Python tuple object.
     version: str the API version being used.

  Returns:
    ZSI.TCcompound.ComplexType packed Python data.
  """
    if isinstance(request, dict):
        cpl = ZSI.TCcompound.ComplexType(ZSI.TCcompound.ComplexType, [])
        for key in request:
            value = request.get(key)
            data = PackRequestAsComplexType(value, version)
            if data and data != 'None':
                cpl.__dict__.__setitem__('_%s' % key, data)
        return cpl
    elif isinstance(request, list):
        if not SanityCheck.IsNewApi(version):
            request = CustomPackList(request)
        if isinstance(request, dict):
            return PackRequestAsComplexType(request, version)
        lst = []
        for item in request:
            data = PackRequestAsComplexType(item, version)
            lst.append(data)
        return lst
    elif isinstance(request, tuple):
        return request
    else:
        return request
コード例 #2
0
    def __init__(self, headers, config, op_config, lock, logger):
        """Inits AccountService.

    Args:
      headers: dict dictionary object with populated authentication
               credentials.
      config: dict dictionary object with populated configuration values.
      op_config: dict dictionary object with additional configuration values for
                 this operation.
      lock: thread.lock the thread lock
      logger: Logger the instance of Logger
    """
        url = [
            op_config['server'], 'api/adwords', op_config['version'],
            self.__class__.__name__
        ]
        if glob_sanity_check.IsNewApi(op_config['version']):
            url.insert(2, 'account')
        if config['access']: url.insert(len(url) - 1, config['access'])
        self.__service = WebService(headers, config, op_config, '/'.join(url),
                                    lock, logger)
        self.__config = config
        self.__op_config = op_config
        if self.__config['soap_lib'] == SOAPPY:
            from aw_api.soappy_toolkit import MessageHandler
            from aw_api.soappy_toolkit import SanityCheck
            self.__web_services = None
            self.__message_handler = MessageHandler
        elif self.__config['soap_lib'] == ZSI:
            from aw_api import API_VERSIONS
            from aw_api.zsi_toolkit import SanityCheck
            if op_config['version'] in API_VERSIONS:
                module = '%s_services' % self.__class__.__name__
                try:
                    web_services = __import__(
                        'aw_api.zsi_toolkit.%s.%s' %
                        (op_config['version'], module), globals(), locals(),
                        [''])
                except ImportError, e:
                    # If one of library's required modules is missing, re raise exception.
                    if str(e).find(module) < 0:
                        raise ImportError(e)
                    msg = (
                        'The version \'%s\' is not compatible with \'%s\'.' %
                        (op_config['version'], self.__class__.__name__))
                    raise ValidationError(msg)
            else:
                msg = 'Invalid API version, not one of %s.' % str(
                    list(API_VERSIONS))
                raise ValidationError(msg)
            self.__web_services = web_services
            self.__loc = eval('web_services.%sLocator()' %
                              self.__class__.__name__)
コード例 #3
0
def GetServiceConnection(headers, config, url, http_proxy, version):
    """Get SOAP service connection.

  Args:
    headers: dict dictionary object with populated authentication
             credentials.
    config: dict dictionary object with populated configuration values.
    url: str url of the web service to call.
    http_proxy: str HTTP proxy to use.
    version: str version of the API in use.

  Returns:
    instance SOAPpy.SOAPProxy with set headers.
  """
    # Catch empty SOAP header elements and exclude them from request.
    full_headers = {}
    for key in headers:
        if headers[key]: full_headers[key] = headers[key]

    if glob_sanity_check.IsNewApi(version):
        headers = SOAPpy.Types.headerType(
            {config['ns_target'][1]: full_headers})
        headers._setAttr('xmlns', config['ns_target'][0])
    else:
        headers = SOAPpy.Types.headerType(full_headers)
    service = SOAPpy.SOAPProxy(url, http_proxy=http_proxy, header=headers)
    service.config.dumpHeadersIn = 1
    service.config.dumpHeadersOut = 1
    service.config.dumpSOAPIn = 1
    service.config.dumpSOAPOut = 1

    # Turn off type information, since SOAPpy usually gets the types wrong.
    service.config.typed = 0

    # Turn on noroot, to skip including "SOAP-ENC:root" as part of the request.
    service.noroot = 1

    # Explicitly set the style of the namespace, otherwise will default to 1999.
    service.config.namespaceStyle = '2001'

    return service
コード例 #4
0
 # Patch v2009*/*.py:
 #   - In local instances, whenever we encounter 'get' or 'mutate', we use
 #     'getXxx' or 'mutateXxx' respectively. The Xxx refer to the name of the
 #     service (i.e. Campaign, AdGroup).
 #
 # This patch allows Python to import generated types with out collision.
 # Otherwise, we end up with types like 'mutate_Dec', 'mutate', etc. which
 # show up in all services and cause invalid instance of a service to be
 # invoked (defaults to the first instance that is found). So, if you invoke
 # an instance of CampaignService and AdGroupService and then try to add an
 # ad group, it will invoke 'mutate' from wrong service (CampaignService in
 # this case) resulting in a failure.
 for f_name in os.listdir(os.path.abspath(target['location'])):
     f_path = os.path.join(os.path.abspath(target['location']), f_name)
     f_parts = f_name.split('Service_')
     if SanityCheck.IsNewApi(target['version']):
         if os.path.exists(f_path):
             fh = open(f_path, 'r')
         try:
             data = fh.read()
             ops = ['get', 'mutate']
             if f_name.find('_services.py') > -1:
                 for op in ops:
                     data = data.replace('def %s(' % op,
                                         'def %s%s(' % (op, f_parts[0]))
                     data = data.replace('# op: %s' % op,
                                         '# %s: get%s' % (op, f_parts[0]))
                     data = data.replace('%sRequest' % op,
                                         '%s%sRequest' % (op, f_parts[0]))
                     data = data.replace('%sResponse' % op,
                                         '%s%sResponse' % (op, f_parts[0]))
コード例 #5
0
  def CallRawMethod(self, soap_message):
    """Make an API call by posting raw SOAP XML message.

    Args:
      soap_message: str SOAP XML message.

    Returns:
      tuple response from the API method.
    """
    # Acquire thread lock.
    self.__lock.acquire()

    try:
      buf = SoapBuffer(
          xml_parser=self.__config['xml_parser'],
          pretty_xml=Utils.BoolTypeConvert(self.__config['use_pretty_xml']))
      http_header = {
          'post': '%s' % self.__url,
          'host': 'sandbox.google.com',
          'user_agent': '%s v%s; WebService.py' % (LIB_SHORT_NAME, LIB_VERSION),
          'content_type': 'text/xml; charset=\"UTF-8\"',
          'content_length': '%d' % len(soap_message),
          'soap_action': ''
      }

      version = self.__url.split('/')[-2]
      if SanityCheck.IsNewApi(version):
        http_header['host'] = 'adwords-%s' % http_header['host']

      index = self.__url.find('adwords.google.com')
      if index > -1:
        http_header['host'] = 'adwords.google.com'

      self.__url = ''.join(['https://', http_header['host'], self.__url])

      start_time = time.strftime('%Y-%m-%d %H:%M:%S')
      buf.write(
          ('%s Outgoing HTTP headers %s\nPOST %s\nHost: %s\nUser-Agent: '
           '%s\nContent-type: %s\nContent-length: %s\nSOAPAction: %s\n%s\n%s '
           'Outgoing SOAP %s\n%s\n%s\n' % ('*'*3, '*'*46, http_header['post'],
                                           http_header['host'],
                                           http_header['user_agent'],
                                           http_header['content_type'],
                                           http_header['content_length'],
                                           http_header['soap_action'], '*'*72,
                                           '*'*3, '*'*54, soap_message,
                                           '*'*72)))

      # Construct header and send SOAP message.
      web_service = httplib.HTTPS(http_header['host'])
      web_service.putrequest('POST', http_header['post'])
      web_service.putheader('Host', http_header['host'])
      web_service.putheader('User-Agent', http_header['user_agent'])
      web_service.putheader('Content-type', http_header['content_type'])
      web_service.putheader('Content-length', http_header['content_length'])
      web_service.putheader('SOAPAction', http_header['soap_action'])
      web_service.endheaders()
      web_service.send(soap_message)

      # Get response.
      status_code, status_message, header = web_service.getreply()
      response = web_service.getfile().read()

      header = str(header).replace('\r', '')
      buf.write(('%s Incoming HTTP headers %s\n%s %s\n%s\n%s\n%s Incoming SOAP'
                 ' %s\n%s\n%s\n' % ('*'*3, '*'*46, status_code, status_message,
                                    header, '*'*72, '*'*3, '*'*54, response,
                                    '*'*72)))
      stop_time = time.strftime('%Y-%m-%d %H:%M:%S')

      # Catch local errors prior to going down to the SOAP layer, which may not
      # exist for this error instance.
      if not buf.IsHandshakeComplete() or not buf.IsSoap():
        # The buffer contains non-XML data, most likely an HTML page. This
        # happens in the case of 502 errors.
        html_error = Utils.GetErrorFromHtml(buf.GetBufferAsStr())
        if html_error:
          msg = '%s' % html_error
        else:
          msg = 'Unknown error.'
        raise Error(msg)

      self.__ManageSoap(buf, start_time, stop_time,
                        {'data': buf.GetBufferAsStr()})
    finally:
      # Release thread lock.
      if self.__lock.locked():
        self.__lock.release()

    return (response,)
コード例 #6
0
  def CallMethod(self, method_name, params, service_name=None, loc=None,
                 request=None):
    """Make an API call to specified method.

    Args:
      method_name: str API method name.
      params: list list of parameters to send to the API method.
      [optional]
      service_name: str API service name.
      loc: service locator.
      request: instance holder of the SOAP request.

    Returns:
      tuple/str response from the API method. If 'raw_response' flag enabled a
                string is returned, tuple otherwise.
    """
    # Acquire thread lock.
    self.__lock.acquire()

    try:
      headers = self.__headers
      config = self.__config

      # Temporarily redirect HTTP headers and SOAP from STDOUT into a buffer.
      buf = SoapBuffer(
          xml_parser=config['xml_parser'],
          pretty_xml=Utils.BoolTypeConvert(config['use_pretty_xml']))
      old_stdout = sys.stdout
      sys.stdout = buf

      start_time = time.strftime('%Y-%m-%d %H:%M:%S')
      response = ()
      raw_response = ''
      error = {}
      try:
        if Utils.BoolTypeConvert(config['use_strict']):
          SanityCheck.ValidateHeadersForServer(headers,
                                               self.__op_config['server'])

        # Load/unload version specific authentication and configuration data.
        if SanityCheck.IsNewApi(self.__op_config['version']):
          # Set boolean to the format expected by the server, True => true.
          if 'validateOnly' in headers:
            headers['validateOnly'] = headers['validateOnly'].lower()

          # Load/set authentication token. If authentication token has expired,
          # regenerate it.
          now = time.time()
          if (Utils.BoolTypeConvert(config['use_auth_token']) and
              (('authToken' not in headers and
                'auth_token_epoch' not in config) or
               int(now - config['auth_token_epoch']) >= AUTH_TOKEN_EXPIRE)):
            if ('email' not in headers or not headers['email'] or
                'password' not in headers or not headers['password']):
              msg = ('Required authentication headers, \'email\' and '
                     '\'password\', are missing. Unable to regenerate '
                     'authentication token.')
              raise ValidationError(msg)
            headers['authToken'] = Utils.GetAuthToken(headers['email'],
                                                      headers['password'])
            config['auth_token_epoch'] = time.time()
            self.__headers = headers
            self.__config = config
          elif not Utils.BoolTypeConvert(config['use_auth_token']):
            msg = ('Requests via %s require use of authentication token.'
                   % self.__op_config['version'])
            raise ValidationError(msg)

          headers = Utils.UnLoadDictKeys(Utils.CleanUpDict(headers),
                                         ['email', 'password'])
          name_space = '/'.join(['https://adwords.google.com/api/adwords',
                                 self.__op_config['group'],
                                 self.__op_config['version']])
          config['ns_target'] = (name_space, 'RequestHeader')
        else:
          headers['useragent'] = headers['userAgent']
          headers = Utils.UnLoadDictKeys(headers, ['authToken', 'userAgent'])
          config = Utils.UnLoadDictKeys(config, ['ns_target',
                                                 'auth_token_epoch'])

        # Fire off API request and handle the response.
        if config['soap_lib'] == SOAPPY:
          from aw_api.soappy_toolkit import MessageHandler
          service = MessageHandler.GetServiceConnection(
              headers, config, self.__url, self.__op_config['http_proxy'],
              self.__op_config['version'])

          if not SanityCheck.IsNewApi(self.__op_config['version']):
            response = MessageHandler.UnpackResponseAsDict(
                service.invoke(method_name, params))
          else:
            response = MessageHandler.UnpackResponseAsDict(
                service._callWithBody(MessageHandler.SetRequestParams(
                    config, method_name, params)))
        elif config['soap_lib'] == ZSI:
          from aw_api.zsi_toolkit import MessageHandler
          service = MessageHandler.GetServiceConnection(
              headers, config, self.__url, self.__op_config['http_proxy'],
              service_name, loc)
          request = MessageHandler.SetRequestParams(self.__op_config, request,
                                                    params)

          response = MessageHandler.UnpackResponseAsTuple(
              eval('service.%s(request)' % method_name))

          # The response should always be tuple. If it's not, there must be
          # something wrong with MessageHandler.UnpackResponseAsTuple().
          if len(response) == 1 and isinstance(response[0], list):
            response = tuple(response[0])

        if isinstance(response, list):
          response = tuple(response)
        elif isinstance(response, tuple):
          pass
        else:
          if response:
            response = (response,)
          else:
            response = ()
      except Exception, e:
        error['data'] = e
      stop_time = time.strftime('%Y-%m-%d %H:%M:%S')

      # Restore STDOUT.
      sys.stdout = old_stdout

      # When debugging mode is ON, fetch last traceback.
      if Utils.BoolTypeConvert(self.__config['debug']):
        error['trace'] = Utils.LastStackTrace()

      # Catch local errors prior to going down to the SOAP layer, which may not
      # exist for this error instance.
      if 'data' in error and not buf.IsHandshakeComplete():
        # Check if buffer contains non-XML data, most likely an HTML page. This
        # happens in the case of 502 errors (and similar). Otherwise, this is a
        # local error and API request was never made.
        html_error = Utils.GetErrorFromHtml(buf.GetBufferAsStr())
        if html_error:
          msg = '%s' % html_error
        else:
          msg = str(error['data'])
          if Utils.BoolTypeConvert(self.__config['debug']):
            msg += '\n%s' % error['trace']

        # When debugging mode is ON, store the raw content of the buffer.
        if Utils.BoolTypeConvert(self.__config['debug']):
          error['raw_data'] = buf.GetBufferAsStr()

        # Catch errors from AuthToken and ValidationError levels, raised during
        # try/except above.
        if isinstance(error['data'], AuthTokenError):
          raise AuthTokenError(msg)
        elif isinstance(error['data'], ValidationError):
          raise ValidationError(error['data'])
        if 'raw_data' in error:
          msg = '%s [RAW DATA: %s]' % (msg, error['raw_data'])
        raise Error(msg)

      if Utils.BoolTypeConvert(self.__config['raw_response']):
        raw_response = buf.GetRawSOAPIn()

      self.__ManageSoap(buf, start_time, stop_time, error)