def __init__(self, headers=None, config=None, path=None, use_mcc=False, soap_lib=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/). use_mcc: bool state of the API request, whether to use MCC account. soap_lib: str soap library to use. Ex: headers = { 'email': '*****@*****.**', 'password': '******', 'clientEmail': '*****@*****.**', 'clientCustomerId': '1234567890', 'userAgent': 'GoogleTest', 'developerToken': '[email protected]++USD', 'validateOnly': 'n' } config = { 'home': '/path/to/home', 'log_home': '/path/to/logs/home', 'soap_lib': ZSI, 'xml_parser': PYXML, 'debug': 'n', 'xml_log': 'y', 'request_log': 'y', 'raw_response': 'n', 'use_strict': 'y', 'use_auth_token': 'y', 'use_pretty_xml': 'y', 'access': '' } path = '/path/to/home' use_mcc = False soap_lib = SOAPPY """ self.__lock = thread.allocate_lock() self.__loc = None self.__is_mcc = use_mcc if path is not None: # Update absolute path for a given instance of Client, based on provided # relative path. if os.path.isabs(path): Client.home = path else: # NOTE(api.sgrinberg): Keep first parameter of join() as os.getcwd(), # do not change it to Client.home. Otherwise, may break when multiple # instances of Client exist during program run. Client.home = os.path.join(os.getcwd(), path) # Update location for both pickles. Client.auth_pkl = os.path.join(Client.home, 'auth.pkl') Client.config_pkl = os.path.join(Client.home, 'config.pkl') # Only load from the pickle if config wasn't specified. self.__config = config or self.__LoadConfigValues() self.__SetMissingDefaultConfigValues(self.__config) self.__config['home'] = Client.home # Load the SOAP library to use. if soap_lib is not None: SanityCheck.ValidateConfigSoapLib(soap_lib) self.__config['soap_lib'] = soap_lib # Validate XML parser to use. SanityCheck.ValidateConfigXmlParser(self.__config['xml_parser']) # Initialize units and operations for current instance of Client object # (using list to take advantage of Python's pass-by-reference). self.__config['units'] = [0] self.__config['operations'] = [0] self.__config['last_units'] = [0] self.__config['last_operations'] = [0] # Only load from the pickle if 'headers' wasn't specified. if headers is None: self.__headers = self.__LoadAuthCredentials() else: self.__headers = headers # Internally, store user agent as 'userAgent'. if 'useragent' in self.__headers: self.__headers['userAgent'] = self.__headers['useragent'] self.__headers = Utils.UnLoadDictKeys(self.__headers, ['useragent']) if Utils.BoolTypeConvert(self.__config['use_strict']): SanityCheck.ValidateRequiredHeaders(self.__headers) # Load validateOnly header, if one was set. if 'validateOnly' in self.__headers: self.__headers['validateOnly'] = str( Utils.BoolTypeConvert(self.__headers['validateOnly'])) # Load/set authentication token. try: if Utils.BoolTypeConvert(self.__config['use_auth_token']): 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']) else: msg = 'Authentication data, email or/and password, 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. This is useful for when dummy credentials are set in # unit tests and requests are being made against v13. If v200909 is being # used and invalid credentials specified, this will be caught in # aw_api.WebService.CallMethod(). self.__headers['authToken'] = None self.__config['auth_token_epoch'] = 0 # Insert library name and version into userAgent. if (self.__headers['userAgent'].rfind( '%s v%s' % (LIB_SHORT_NAME, LIB_VERSION)) == -1): # Make sure library name shows up only once. if (self.__headers['userAgent'].rfind(LIB_SHORT_NAME) > -1 or self.__headers['userAgent'].rfind(LIB_NAME) > -1): pattern = re.compile('.*?: ') self.__headers['userAgent'] = pattern.sub( '', self.__headers['userAgent'], 1) self.__headers['userAgent'] = ( '%s v%s: %s' % (LIB_SHORT_NAME, LIB_VERSION, self.__headers['userAgent'])) # Sync library's version in the new userAgent with the one in the pickle. if headers is None: self.__WriteUpdatedAuthValue('userAgent', self.__headers['userAgent']) # Initialize logger. self.__logger = Logger(self.__config['log_home'])
elif source == 'config': # Prompt user to update configuration values. if header == 'soap_lib' or header == 'xml_parser': res = raw_input('%s: ' % prompt_msg).rstrip('\r') if not SanityCheck.IsConfigUserInputValid(res, ['1', '2']): msg = 'Possible values are \'1\' or \'2\'.' raise InvalidInputError(msg) else: res = raw_input('%s [y/n]: ' % prompt_msg).rstrip('\r') if not SanityCheck.IsConfigUserInputValid(res, ['y', 'n']): msg = 'Possible values are \'y\' or \'n\'.' raise InvalidInputError(msg) config[header] = res # Raise an exception, if required headers are missing. SanityCheck.ValidateRequiredHeaders(auth) if not SanityCheck.IsClientIdSet(auth['clientEmail'], auth['clientCustomerId']): msg = 'Set either clientEmail or clientCustomerId, but not both.' raise InvalidInputError(msg) # Load new authentication credentials into auth.pkl. try: fh = open(AUTH_PKL, 'w') try: pickle.dump(auth, fh) finally: fh.close() except IOError, e: logger.Log(LOG_NAME, e, log_level=Logger.ERROR)