def __init__(self, lib_sig, headers, config, op_config, url, lock, logger=None): """Inits WebService. Args: lib_sig: str Client library signature. 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. url: str URL of the web service to call. lock: thread.lock Thread lock. logger: Logger Instance of Logger. """ self._lib_sig = lib_sig self._headers = headers self._config = config self._op_config = op_config self._url = url self._lock = lock self._logger = logger self._start_time = 0 self._stop_time = 0 self._response = None if self._logger is None: self._logger = Logger(lib_sig, self._config['log_home'])
def main(): logger = Logger(os.path.join(LOG_HOME)) #获取新的token refresh_token = GenerateRefreshToken() # Load existing authentication credentials from dfa_api_auth.pkl. old_auth = {} if os.path.exists(AUTH_PKL): try: fh = open(AUTH_PKL, 'r') try: old_auth = pickle.load(fh) finally: fh.close() except IOError, e: logger.Log(LOG_NAME, e, log_level=Logger.ERROR)
# distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Script to run all existing unit tests.""" __author__ = '[email protected] (Stan Grinberg)' import glob import os import sys sys.path.append(os.path.join('..', '..', '..')) import unittest from adspygoogle.adwords import LIB_SIG from adspygoogle.common.Logger import Logger LOG_NAME = 'adwords_api_lib' LOGGER = Logger(LIB_SIG, os.path.join('..', '..', '..', 'logs')) suite = unittest.TestSuite() tests = [test[:-3] for test in glob.glob('*_unittest.py')] for test in tests: module = __import__(test) suite.addTest(unittest.TestLoader().loadTestsFromModule(module)) if __name__ == '__main__': LOGGER.Log(LOG_NAME, 'Start all unit tests.', log_level=Logger.DEBUG) unittest.TextTestRunner(verbosity=1).run(suite) LOGGER.Log(LOG_NAME, 'End all unit tests.', log_level=Logger.DEBUG)
def __init__(self, headers=None, config=None, path=None): """Inits Client. Args: [optional] headers: dict Object with populated authentication credentials. config: dict Object with client configuration values. path: str Relative or absolute path to home directory (i.e. location of pickles and logs/). Example: headers = { 'email': '*****@*****.**', 'password': '******', 'authToken': '...', 'applicationName': 'GoogleTest', 'networkCode': 'ca-01234567', 'oauth2credentials': 'See use_oauth2.py' } config = { 'home': '/path/to/home', 'log_home': '/path/to/logs/home', 'proxy': 'http://example.com:8080', 'xml_parser': '1', # PYXML = 1, ELEMENTREE = 2 'debug': 'n', 'raw_debug': 'n', 'xml_log': 'y', 'request_log': 'y', 'raw_response': 'n', 'strict': 'y', 'pretty_xml': 'y', 'compress': 'y', 'access': '' } path = '/path/to/home' """ super(DfpClient, self).__init__(headers, config, path) self.__lock = thread.allocate_lock() self.__loc = None if path is not None: # Update absolute path for a given instance of DfpClient, based on # provided relative path. if os.path.isabs(path): DfpClient.home = path else: # NOTE(api.sgrinberg): Keep first parameter of join() as os.getcwd(), # do not change it to DfpClient.home. Otherwise, may break when # multiple instances of DfpClient exist during program run. DfpClient.home = os.path.join(os.getcwd(), path) # If pickles don't exist at given location, default to "~". if (not headers and not config and (not os.path.exists(os.path.join(DfpClient.home, DfpClient.auth_pkl_name)) or not os.path.exists(os.path.join(DfpClient.home, DfpClient.config_pkl_name)))): DfpClient.home = os.path.expanduser('~') elif not headers: DfpClient.home = os.path.expanduser('~') # Update location for both pickles. DfpClient.auth_pkl = os.path.join(DfpClient.home, DfpClient.auth_pkl_name) DfpClient.config_pkl = os.path.join(DfpClient.home, DfpClient.config_pkl_name) # Only load from the pickle if config wasn't specified. self._config = config or self.__LoadConfigValues() self._config = self.__SetMissingDefaultConfigValues(self._config) self._config['home'] = DfpClient.home # Validate XML parser to use. SanityCheck.ValidateConfigXmlParser(self._config['xml_parser']) # Only load from the pickle if 'headers' wasn't specified. if headers is None: self._headers = self.__LoadAuthCredentials() else: if Utils.BoolTypeConvert(self._config['strict']): SanityCheck.ValidateRequiredHeaders(headers, REQUIRED_SOAP_HEADERS) self._headers = headers # Load/set authentication token. try: if headers and 'authToken' in headers and headers['authToken']: self._headers['authToken'] = headers['authToken'] elif 'email' in self._headers and 'password' in self._headers: self._headers['authToken'] = Utils.GetAuthToken( self._headers['email'], self._headers['password'], AUTH_TOKEN_SERVICE, LIB_SIG, self._config['proxy']) elif (self._headers.get('oauth2credentials')): # If they have oauth2credentials, that's also fine. pass else: msg = ('Authentication data, email or/and password, OAuth2 credentials ' 'is missing.') raise ValidationError(msg) self._config['auth_token_epoch'] = time.time() except AuthTokenError: # We would end up here if non-valid Google Account's credentials were # specified. self._headers['authToken'] = None self._config['auth_token_epoch'] = 0 # Initialize logger. self.__logger = Logger(LIB_SIG, self._config['log_home'])
class WebService(object): """Implements WebService. Responsible for sending and recieving SOAP XML requests. """ def __init__(self, lib_sig, headers, config, op_config, url, lock, logger=None): """Inits WebService. Args: lib_sig: str Client library signature. 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. url: str URL of the web service to call. lock: thread.lock Thread lock. logger: Logger Instance of Logger. """ self._lib_sig = lib_sig self._headers = headers self._config = config self._op_config = op_config self._url = url self._lock = lock self._logger = logger self._start_time = 0 self._stop_time = 0 self._response = None if self._logger is None: self._logger = Logger(lib_sig, self._config['log_home']) def _ManageSoap(self, buf, log_handlers, lib_url, errors, start_time, stop_time, error={}): """Manage SOAP XML message. Args: buf: SoapBuffer SOAP buffer. log_handlers: list Log handlers. lib_url: str URL of the project's home. errors: dict Map of errors available for the API. start_time: str Time before service call was invoked. stop_time: str Time after service call was invoked. [optional] error: dict Error, if any. """ # Load trace errors, if any. if error and 'trace' in error: error_msg = error['trace'] else: error_msg = '' # Check if response was successful or not. if error and 'data' in error: is_fault = True else: is_fault = False # Forward SOAP XML, errors, and other debugging data to console, external # file, both, or ignore. Each handler supports the following elements, # tag: Config value for this handler. If left empty, will never write # data to file. # target: Target/destination represented by this handler (i.e. FILE, # CONSOLE, etc.). Initially, it should be set to Logger.NONE. # name: Name of the log file to use. # data: Data to write. for handler in log_handlers: if handler['tag'] == 'xml_log': handler['target'] = Logger.NONE handler['data'] += str( 'StartTime: %s\n%s\n%s\n%s\n%s\nEndTime: %s' % (start_time, buf.GetHeadersOut(), buf.GetSoapOut(), buf.GetHeadersIn(), buf.GetSoapIn(), stop_time)) elif handler['tag'] == 'request_log': handler['target'] = Logger.NONE handler['data'] += ' isFault=%s' % is_fault elif handler['tag'] == '': handler['target'] = Logger.NONE handler['data'] += 'DEBUG: %s' % error_msg for handler in log_handlers: if (handler['tag'] and Utils.BoolTypeConvert(self._config[handler['tag']])): handler['target'] = Logger.FILE # If debugging is On, raise handler's target two levels, # NONE -> CONSOLE # FILE -> FILE_AND_CONSOLE. if Utils.BoolTypeConvert(self._config['debug']): handler['target'] += 2 if (handler['target'] != Logger.NONE and handler['data'] and handler['data'] != 'None' and handler['data'] != 'DEBUG: '): self._logger.Log(handler['name'], handler['data'], log_level=Logger.DEBUG, log_handler=handler['target']) # If raw response is requested, no need to validate and throw appropriate # error. Up to the end user to handle successful or failed request. if Utils.BoolTypeConvert(self._config['raw_response']): return # Report SOAP fault. if is_fault: try: fault = buf.GetFaultAsDict() if not fault: msg = error['data'] except: fault = None # An error is not a SOAP fault, but check if some other error. if error_msg: msg = error_msg else: msg = ('Unable to parse incoming SOAP XML. Please, file ' 'a bug at %s/issues/list.' % lib_url) # Release thread lock. if self._lock.locked(): self._lock.release() if not fault and msg: return msg return fault return None def CallMethod(self, headers, config, method_name, params, buf, is_jaxb_api, lib_sig, lib_url, service_name=None, loc=None, request=None): """Make an API call to specified method. Args: headers: dict Dictionary object with populated authentication credentials. config: dict Dictionary object with populated configuration values. method_name: str API method name. params: list List of parameters to send to the API method. buf: SoapBuffer SOAP buffer. is_jaxb_api: str Whether API uses JAXB. lib_sig: str Signature of the client library. lib_url: str URL of the project's home. [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. """ # Temporarily redirect HTTP headers and SOAP from STDOUT into a buffer. if not Utils.BoolTypeConvert(self._config['raw_debug']): old_stdout = sys.stdout sys.stdout = buf response = () error = {} try: # Fire off API request and handle the response. if config['soap_lib'] == SOAPPY: from adspygoogle.common.soappy import MessageHandler service = MessageHandler.GetServiceConnection( headers, config, self._url, self._op_config['http_proxy'], is_jaxb_api) if not is_jaxb_api: response = MessageHandler.UnpackResponseAsDict( service.invoke(method_name, params)) else: if not params: params = ('') response = MessageHandler.UnpackResponseAsDict( service._callWithBody( MessageHandler.SetRequestParams( config, method_name, params))) elif config['soap_lib'] == ZSI: from adspygoogle.common.zsi import MessageHandler service = MessageHandler.GetServiceConnection( headers, config, self._op_config, self._url, service_name, loc) request = MessageHandler.SetRequestParams( request, params, is_jaxb_api) 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 # Restore STDOUT. if not Utils.BoolTypeConvert(self._config['raw_debug']): sys.stdout = old_stdout # When debugging mode is ON, fetch last traceback. if Utils.BoolTypeConvert(self._config['debug']): if Utils.LastStackTrace() and Utils.LastStackTrace() != 'None': 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']) return Error(msg) if Utils.BoolTypeConvert(self._config['raw_response']): response = buf.GetRawSOAPIn() if error: response = error return response
import pickle from adspygoogle.common import SanityCheck from adspygoogle.common.Errors import InvalidInputError from adspygoogle.common.Logger import Logger HOME = os.path.expanduser('~') AUTH_PKL = os.path.join(HOME, 'dfa_api_auth.pkl') CONFIG_PKL = os.path.join(HOME, 'dfa_api_config.pkl') LOG_HOME = os.path.join(HOME, 'logs') LOG_NAME = 'dfa_api_lib' logger = Logger(os.path.join(LOG_HOME)) # Load existing authentication credentials from dfa_api_auth.pkl. old_auth = {} if os.path.exists(AUTH_PKL): try: fh = open(AUTH_PKL, 'r') try: old_auth = pickle.load(fh) finally: fh.close() except IOError, e: logger.Log(LOG_NAME, e, log_level=Logger.ERROR) # Prompt user for authentication and configuration values. print """
def __init__(self, headers=None, config=None, path=None): """Inits DfaClient. Args: [optional] headers: dict Object with populated authentication credentials. config: dict Object with client configuration values. path: str Relative or absolute path to home directory (i.e. location of pickles and logs/). Example: headers = { 'Username': '******', 'Password': '******', 'AuthToken': '...' } config = { 'home': '/path/to/home', 'log_home': '/path/to/logs/home', 'xml_parser': '1', # PYXML = 1, ELEMENTREE = 2 'debug': 'n', 'raw_debug': 'n', 'xml_log': 'y', 'request_log': 'y', 'raw_response': 'n', 'strict': 'y', 'pretty_xml': 'y', 'compress': 'y', } path = '/path/to/home' """ super(DfaClient, self).__init__(headers, config, path) self.__lock = threading.RLock() self.__loc = None if path is not None: # Update absolute path for a given instance of DfaClient, based on # provided relative path. if os.path.isabs(path): DfaClient.home = path else: # NOTE(api.sgrinberg): Keep first parameter of join() as os.getcwd(), # do not change it to DfaClient.home. Otherwise, may break when # multiple instances of DfaClient exist during program run. DfaClient.home = os.path.join(os.getcwd(), path) # If pickles don't exist at given location, default to "~". if (not headers and not config and (not os.path.exists( os.path.join(DfaClient.home, DfaClient.auth_pkl_name)) or not os.path.exists( os.path.join(DfaClient.home, DfaClient.config_pkl_name)))): DfaClient.home = os.path.expanduser('~') elif not headers: DfaClient.home = os.path.expanduser('~') # Update location for both pickles. DfaClient.auth_pkl = os.path.join(DfaClient.home, DfaClient.auth_pkl_name) DfaClient.config_pkl = os.path.join(DfaClient.home, DfaClient.config_pkl_name) # Only load from the pickle if config wasn't specified. self._config = config or self.__LoadConfigValues() self._config = self.__SetMissingDefaultConfigValues(self._config) self._config['home'] = DfaClient.home # Validate XML parser to use. SanityCheck.ValidateConfigXmlParser(self._config['xml_parser']) # Only load from the pickle if 'headers' wasn't specified. if headers is None: self._headers = self.__LoadAuthCredentials() else: # Pass app_name from config as appName to headers if still present if self._config.get('app_name', None): headers['appName'] = self._config['app_name'] if Utils.BoolTypeConvert(self._config['strict']): SanityCheck.ValidateRequiredHeaders(headers, REQUIRED_SOAP_HEADERS) self._headers = headers # Initialize logger. self.__logger = Logger(LIB_SIG, self._config['log_home'])