diff --git a/Algorithmia/CLI.py b/Algorithmia/CLI.py index 02d27f8..5703f49 100644 --- a/Algorithmia/CLI.py +++ b/Algorithmia/CLI.py @@ -2,10 +2,11 @@ import os from Algorithmia.errors import DataApiError from Algorithmia.algo_response import AlgoResponse +from Algorithmia.util import md5_for_file, md5_for_str import json, re, requests, six import toml import shutil - +from time import time class CLI: def __init__(self): @@ -245,6 +246,30 @@ def cat(self, path, client): return result + def lockAlgo(self, client, manifest_path="model_manifest.json"): + if os.path.exists(manifest_path): + with open(manifest_path, 'r') as f: + manifest_file = json.load(f) + manifest_file['timestamp'] = str(time()) + required_files = manifest_file['required_files'] + optional_files = manifest_file['optional_files'] + for i in range(len(required_files)): + uri = required_files[i]['source_uri'] + local_file = client.file(uri).getFile(as_path=True) + md5_checksum = md5_for_file(local_file) + required_files[i]['md5_checksum'] = md5_checksum + for i in range(len(optional_files)): + uri = required_files[i]['source_uri'] + local_file = client.file(uri).getFile(as_path=True) + md5_checksum = md5_for_file(local_file) + required_files[i]['md5_checksum'] = md5_checksum + lock_md5_checksum = md5_for_str(str(manifest_file)) + manifest_file['lock_checksum'] = lock_md5_checksum + with open('model_manifest.json.lock', 'w') as f: + json.dump(manifest_file, f) + else: + print("Expected to find a model_manifest.json file, none was discovered in working directory") + # algo cp def cp(self, src, dest, client): diff --git a/Algorithmia/__main__.py b/Algorithmia/__main__.py index c45e5fb..1befbcb 100644 --- a/Algorithmia/__main__.py +++ b/Algorithmia/__main__.py @@ -108,7 +108,7 @@ def main(): parser_cat.add_argument('--profile', action = 'store', type = str, default = 'default') #sub parser for getting environment template - parser_template = subparsers.add_parser('template',help='template downloads an environment template to the destination') + parser_template = subparsers.add_parser('template', help='template downloads an environment template to the destination') parser_template.add_argument('envid',help='environment specification id') parser_template.add_argument('dest',help='destination for template download') @@ -130,8 +130,12 @@ def main(): subparsers.add_parser('help') parser.add_argument('--profile', action = 'store', type = str, default = 'default') + #sub parser for lock + subparsers.add_parser('lock', help="locks a model_manifest.json file into a model_manifest.json.lock") + args = parser.parse_args() + #run auth before trying to create a client if args.cmd == 'auth': @@ -215,6 +219,9 @@ def main(): elif args.cmd == 'builds': print(CLI().getBuildLogs(args.user, args.algo, client)) + elif args.cmd == "lock": + print(CLI().lockAlgo(client)) + else: parser.parse_args(['-h']) diff --git a/Algorithmia/util.py b/Algorithmia/util.py index 382b586..aa2ffbb 100644 --- a/Algorithmia/util.py +++ b/Algorithmia/util.py @@ -1,4 +1,5 @@ import re +import hashlib from Algorithmia.errors import DataApiError FNAME_MATCH = re.compile(r'/([^/]+)$') # From the last slash to the end of the string @@ -30,3 +31,15 @@ def pathJoin(parent, base): if parent.endswith('/'): return parent + base return parent + '/' + base + +def md5_for_file(fname): + hash_md5 = hashlib.md5() + with open(fname, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return str(hash_md5.hexdigest()) + +def md5_for_str(content): + hash_md5 = hashlib.md5() + hash_md5.update(content.encode()) + return str(hash_md5.hexdigest()) \ No newline at end of file diff --git a/Test/client_test.py b/Test/client_test.py index edfda54..d484610 100644 --- a/Test/client_test.py +++ b/Test/client_test.py @@ -23,12 +23,12 @@ class ClientTest(unittest.TestCase): environment_name = "Python 3.9" def setUp(self): - self.admin_api_key = unicode(os.environ.get('ALGORITHMIA_A_KEY')) - self.regular_api_key = unicode(os.environ.get('ALGORITHMIA_API_KEY')) + self.admin_api_key = unicode(os.environ.get('ALGORITHMIA_A_KEY_1')) + self.regular_api_key = unicode(os.environ.get('ALGORITHMIA_API_KEY_1')) self.admin_username = self.admin_username + str(int(random() * 10000)) self.admin_org_name = self.admin_org_name + str(int(random() * 10000)) - self.admin_client = Algorithmia.client(api_address="https://test.algorithmia.com", + self.admin_client = Algorithmia.client(api_address="https://api.algorithmia.com", api_key=self.admin_api_key) self.regular_client = Algorithmia.client(api_address='https://api.algorithmia.com', api_key=self.regular_api_key) @@ -70,9 +70,7 @@ def test_get_environment(self): self.assertTrue(response is not None and u'environments' in response) def test_get_build_logs(self): - user = unicode(os.environ.get('ALGO_USER_NAME')) - algo = unicode('echo') - algo_path = u'%s/%s' % (user, algo) + algo_path = self.regular_client.username() + "/hello" result = self.regular_client.algo(algo_path).build_logs() if u'error' in result: @@ -83,9 +81,7 @@ def test_get_build_logs(self): def test_get_build_logs_no_ssl(self): client = Algorithmia.client(api_address='https://api.algorithmia.com', api_key=self.regular_api_key, ca_cert=False) - user = unicode(os.environ.get('ALGO_USER_NAME')) - algo = u'Echo' - result = client.algo(user + '/' + algo).build_logs() + result = client.algo(client.username() + '/' + "hello").build_logs() if u'error' in result: print(result) self.assertTrue("error" not in result)