diff --git a/Algorithmia/CLI.py b/Algorithmia/CLI.py index 76e1da3..02d27f8 100644 --- a/Algorithmia/CLI.py +++ b/Algorithmia/CLI.py @@ -7,31 +7,36 @@ import shutil -class CLI(): +class CLI: def __init__(self): self.client = Algorithmia.client() # algo auth + def auth(self, apikey, apiaddress, cacert="", profile="default"): - #store api key in local config file and read from it each time a client needs to be created + # store api key in local config file and read from it each time a client needs to be created key = self.getconfigfile() config = toml.load(key) - if('profiles' in config.keys()): - if(profile in config['profiles'].keys()): + if ('profiles' in config.keys()): + if (profile in config['profiles'].keys()): config['profiles'][profile]['api_key'] = apikey config['profiles'][profile]['api_server'] = apiaddress config['profiles'][profile]['ca_cert'] = cacert else: - config['profiles'][profile] = {'api_key':apikey,'api_server':apiaddress,'ca_cert':cacert} + config['profiles'][profile] = {'api_key': apikey, 'api_server': apiaddress, 'ca_cert': cacert} else: - config['profiles'] = {profile:{'api_key':apikey,'api_server':apiaddress,'ca_cert':cacert}} + config['profiles'] = {profile: {'api_key': apikey, 'api_server': apiaddress, 'ca_cert': cacert}} with open(key, "w") as key: - toml.dump(config,key) - - self.ls(path = None,client = Algorithmia.client(self.getAPIkey(profile))) + toml.dump(config, key) + client = Algorithmia.client( + api_key=self.getAPIkey(profile), + api_address=self.getAPIaddress(profile), + ca_cert=self.getCert(profile) + ) + self.ls(path=None, client=client) # algo run run the the specified algo def runalgo(self, options, client): @@ -44,58 +49,58 @@ def runalgo(self, options, client): algo.set_options(timeout=options.timeout, stdout=options.debug) - #handle input type flags - if(options.data != None): - #data + # handle input type flags + if (options.data != None): + # data algo_input = options.data result = algo.pipe(algo_input) - elif(options.text != None): - #text + elif (options.text != None): + # text algo_input = options.text key = self.getAPIkey(options.profile) content = 'text/plain' algo_input = algo_input.encode('utf-8') - elif(options.json != None): - #json + elif (options.json != None): + # json algo_input = options.json key = self.getAPIkey(options.profile) content = 'application/json' - elif(options.binary != None): - #binary + elif (options.binary != None): + # binary algo_input = bytes(options.binary) key = self.getAPIkey(options.profile) content = 'application/octet-stream' - elif(options.data_file != None): - #data file - algo_input = open(options.data_file,"r").read() + elif (options.data_file != None): + # data file + algo_input = open(options.data_file, "r").read() result = algo.pipe(algo_input) - elif(options.text_file != None): - #text file - algo_input = open(options.text_file,"r").read() + elif (options.text_file != None): + # text file + algo_input = open(options.text_file, "r").read() key = self.getAPIkey(options.profile) content = 'text/plain' algo_input = algo_input.encode('utf-8') - elif(options.json_file != None): - #json file - #read json file and run algo with that input bypassing the auto detection of input type in pipe - with open(options.json_file,"r") as f: + elif (options.json_file != None): + # json file + # read json file and run algo with that input bypassing the auto detection of input type in pipe + with open(options.json_file, "r") as f: algo_input = f.read() key = self.getAPIkey(options.profile) content = 'application/json' algo_input = json.dumps(algo_input).encode('utf-8') - elif(options.binary_file != None): - #binary file - with open(options.binary_file,"rb") as f: + elif (options.binary_file != None): + # binary file + with open(options.binary_file, "rb") as f: algo_inputs = bytes(f.read()) key = self.getAPIkey(options.profile) content = 'application/octet-stream' @@ -104,25 +109,27 @@ def runalgo(self, options, client): else: output = "no valid input detected" - if(content != None): + if (content != None): result = AlgoResponse.create_algo_response(requests.post(url, data=algo_input, - headers={'Authorization':key,'Content-Type':content}, params= algo.query_parameters).json()) + headers={'Authorization': key, + 'Content-Type': content}, + params=algo.query_parameters).json()) - if(result != None): + if (result != None): output = result.result - #handle output flags + # handle output flags - #output to file if there is an output file specified - if(options.output != None): + # output to file if there is an output file specified + if (options.output != None): outputFile = options.output try: if isinstance(result.result, bytearray) or isinstance(result.result, bytes): - out = open(outputFile,"wb") + out = open(outputFile, "wb") out.write(result.result) out.close() else: - out = open(outputFile,"w") + out = open(outputFile, "w") out.write(result.result) out.close() output = "" @@ -132,18 +139,17 @@ def runalgo(self, options, client): return output - # algo mkdir def mkdir(self, path, client): - #make a dir in data collection + # make a dir in data collection newDir = client.dir(path) if newDir.exists() is False: newDir.create() # algo rmdir - def rmdir(self, path, client, force = False): - #remove a dir in data collection + def rmdir(self, path, client, force=False): + # remove a dir in data collection Dir = client.dir(path) @@ -153,10 +159,9 @@ def rmdir(self, path, client, force = False): except Algorithmia.errors.DataApiError as e: print(e) - def rm(self, path, client): - #for f in path + # for f in path file = client.file(path) try: if file.exists(): @@ -179,7 +184,7 @@ def ls(self, path, client, longlist=False): response = client.getHelper(f.url, **{}) if response.status_code != 200: - raise DataApiError("failed to get file info: " + str(response.content)) + raise DataApiError("failed to get file info: " + str(response.content)) responseContent = response.content if isinstance(responseContent, six.binary_type): @@ -225,14 +230,14 @@ def cat(self, path, client): for f in path: if '://' in f and not f.startswith("http"): if f[-1] == '*': - path += ['data://'+file.path for file in client.dir(f[:len(f)-2]).files()] + path += ['data://' + file.path for file in client.dir(f[:len(f) - 2]).files()] else: file = client.file(f) if file.exists(): result += file.getString() else: - result = "file does not exist "+f + result = "file does not exist " + f break else: print("operands must be a path to a remote data source data://") @@ -243,132 +248,130 @@ def cat(self, path, client): # algo cp def cp(self, src, dest, client): - if(src is None or dest is None): + if (src is None or dest is None): print("expected algo cp ") else: destLocation = client.file(dest) for f in src: - - #if dest is a directory apend the src name - #if there are multiple src files only the final one will be copied if dest is not a directory + # if dest is a directory apend the src name + # if there are multiple src files only the final one will be copied if dest is not a directory destPath = dest path = dest.split('/') - if(os.path.isdir(dest) or client.dir(dest).exists() and len(path) <= 5): - if(dest[-1] == '/' and path[-1] == ''): - destPath+=client.file(f).getName() - elif(len(path) == 4 or "data://" not in dest): - destPath+='/'+client.file(f).getName() + if (os.path.isdir(dest) or client.dir(dest).exists() and len(path) <= 5): + if (dest[-1] == '/' and path[-1] == ''): + destPath += client.file(f).getName() + elif (len(path) == 4 or "data://" not in dest): + destPath += '/' + client.file(f).getName() - if(f[-1] == '*'): - src += ['data://'+file.path for file in client.dir(f[:len(f)-2]).files()] + if (f[-1] == '*'): + src += ['data://' + file.path for file in client.dir(f[:len(f) - 2]).files()] - #if src is local and dest is remote - elif("data://" not in f and "data://" in dest): + # if src is local and dest is remote + elif ("data://" not in f and "data://" in dest): client.file(destPath).putFile(f) - #if src and dest are remote - elif("data://" in f and "data://" in dest): + # if src and dest are remote + elif ("data://" in f and "data://" in dest): file = client.file(f).getFile() filename = file.name file.close() client.file(destPath).putFile(filename) - #if src is remote and dest is local - elif("data://" in f and "data://" not in dest): + # if src is remote and dest is local + elif ("data://" in f and "data://" not in dest): file = client.file(f).getFile() filename = file.name file.close() - shutil.move(filename,destPath) + shutil.move(filename, destPath) else: print("at least one of the operands must be a path to a remote data source data://") - def get_environment_by_language(self,language,client): + def get_environment_by_language(self, language, client): response = client.get_environment(language) if "error" in response: return json.dumps(response) - return json.dumps(response['environments'],indent=1) - + return json.dumps(response['environments'], indent=1) def list_languages(self, client): response = client.get_supported_languages() table = [] if "error" not in response: - table.append("{:<25} {:<35}".format('Name','Description')) + table.append("{:<25} {:<35}".format('Name', 'Description')) for lang in response: - table.append("{:<25} {:<35}".format(lang['name'],lang['display_name'])) + table.append("{:<25} {:<35}".format(lang['name'], lang['display_name'])) else: table.append(json.dumps(response)) return table - def getBuildLogs(self, user, algo, client): - api_response = client.algo(user+'/'+algo).build_logs() - + api_response = client.algo(user + '/' + algo).build_logs() + if "error" in api_response: return json.dumps(api_response) return json.dumps(api_response['results'], indent=1) - def getconfigfile(self): - if(os.name == "posix"): - #if!windows - #~/.algorithmia/config - #create the api key file if it does not exist - keyPath = os.environ['HOME']+"/.algorithmia/" - - elif(os.name == "nt"): - #ifwindows - #%LOCALAPPDATA%\Algorithmia\config - #create the api key file if it does not exist + if (os.name == "posix"): + # if!windows + # ~/.algorithmia/config + # create the api key file if it does not exist + keyPath = os.environ['HOME'] + "/.algorithmia/" + + elif (os.name == "nt"): + # ifwindows + # %LOCALAPPDATA%\Algorithmia\config + # create the api key file if it does not exist keyPath = os.path.expandvars("%LOCALAPPDATA%\\Algorithmia\\") keyFile = "config" - if(not os.path.exists(keyPath)): + if (not os.path.exists(keyPath)): os.mkdir(keyPath) - if(not os.path.exists(keyPath+keyFile)): - with open(keyPath+keyFile,"w") as file: + if (not os.path.exists(keyPath + keyFile)): + with open(keyPath + keyFile, "w") as file: file.write("[profiles]\n") file.write("[profiles.default]\n") file.write("api_key = ''\n") file.write("api_server = ''\n") file.write("ca_cert = ''\n") - - key = keyPath+keyFile + key = keyPath + keyFile return key - def get_template(self,envid,dest,client): - response = client.get_template(envid,dest) + def get_template(self, envid, dest, client): + response = client.get_template(envid, dest) return response - def getAPIkey(self,profile): + def getAPIkey(self, profile): key = self.getconfigfile() config_dict = toml.load(key) - apikey = None - if('profiles' in config_dict.keys() and profile in config_dict['profiles'].keys()): - apikey = config_dict['profiles'][profile]['api_key'] - return apikey + if 'profiles' in config_dict and profile in config_dict['profiles'] and \ + config_dict['profiles'][profile]['api_key'] != "": + return config_dict['profiles'][profile]['api_key'] + else: + return None - def getAPIaddress(self,profile): + def getAPIaddress(self, profile): key = self.getconfigfile() config_dict = toml.load(key) - apiaddress = config_dict['profiles'][profile]['api_server'] - - return apiaddress + if config_dict['profiles'][profile]['api_server'] != "": + return config_dict['profiles'][profile]['api_server'] + else: + return None - def getCert(self,profile): + def getCert(self, profile): key = self.getconfigfile() config_dict = toml.load(key) - cert = None - if('profiles' in config_dict.keys() and profile in config_dict['profiles'].keys()): - cert = config_dict['profiles'][profile]['ca_cert'] - return cert + if 'profiles' in config_dict and profile in config_dict['profiles'] and \ + config_dict['profiles'][profile]['ca_cert'] != "": + return config_dict['profiles'][profile]['ca_cert'] + else: + return None diff --git a/Test/CLI_test.py b/Test/CLI_test.py index 4636fc6..35ca486 100644 --- a/Test/CLI_test.py +++ b/Test/CLI_test.py @@ -10,6 +10,7 @@ from Algorithmia.CLI import CLI import argparse import shutil +import toml class CLITest(unittest.TestCase): def setUp(self): @@ -142,7 +143,7 @@ def test_run(self): def test_auth(self): #key for test account key = os.getenv('ALGORITHMIA_API_KEY') - address = 'apiAddress' + address = 'https://api.algorithmia.com' profile = 'default' CLI().auth(key,address,profile=profile) resultK = CLI().getAPIkey(profile) @@ -160,7 +161,7 @@ def test_auth_cert(self): #key for test account key = os.getenv('ALGORITHMIA_API_KEY') - address = 'apiAddress' + address = 'https://api.algorithmia.com' cacert = localfile profile = 'test' @@ -215,6 +216,17 @@ def test_get_template(self): shutil.rmtree(filename) except OSError as e: print(e) + + def test_api_address_auth(self): + api_key = os.getenv('ALGORITHMIA_TEST_API_KEY') + api_address = "https://api.test.algorithmia.com" + CLI().auth(api_key, api_address) + profile = "default" + + client = Algorithmia.client(CLI().getAPIkey(profile), CLI().getAPIaddress(profile), CLI().getCert(profile)) + result2 = CLI().ls("data://.my", client) + print(result2) + self.assertTrue(result2 != "")