Skip to content

Commit e6ef6c2

Browse files
committed
2 parents b2b1d63 + 8fe7046 commit e6ef6c2

File tree

8 files changed

+211
-1
lines changed

8 files changed

+211
-1
lines changed

.gitlab-ci.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,30 @@ stages:
44
- python37
55
- python38
66
- python39
7+
- deploy
78

89
variables:
910
PROJECT_NAME: algorithmia-python
1011
DOCKER_HOST: tcp://docker:2375/
1112
DOCKER_DRIVER: overlay2
1213
RUNNING_ON_BUILD_SERVER: "true"
14+
TWINE_USERNAME: __token__
15+
CLIENT_VERSION: $CI_COMMIT_TAG
16+
17+
18+
deploy:
19+
stage: deploy
20+
only:
21+
- tags
22+
image: python:3.7
23+
script:
24+
# - export CLIENT_VERSION=$(git describe --abbrev=0 2>/dev/null || echo '')
25+
- echo $CLIENT_VERSION
26+
- python -m pip install --upgrade pip
27+
- pip install wheel twine setuptools
28+
- python setup.py sdist bdist_wheel
29+
- python3 setup.py sdist bdist_wheel --universal
30+
- twine upload -r pypi dist/*
1331

1432
test:
1533
stage: test

Algorithmia/CLI.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,26 @@ def cp(self, src, dest, client):
287287
else:
288288
print("at least one of the operands must be a path to a remote data source data://")
289289

290+
def get_environment_by_language(self,language,client):
291+
response = client.get_environment(language)
292+
if "error" in response:
293+
return json.dumps(response)
294+
return json.dumps(response['environments'],indent=1)
295+
296+
297+
def list_languages(self, client):
298+
response = client.get_supported_languages()
299+
return response
300+
301+
302+
def getBuildLogs(self, user, algo, client):
303+
api_response = client.algo(user+'/'+algo).build_logs()
304+
305+
if "error" in api_response:
306+
return json.dumps(api_response)
307+
return json.dumps(api_response['results'], indent=1)
308+
309+
290310
def getconfigfile(self):
291311
if(os.name == "posix"):
292312
#if!windows
@@ -318,6 +338,10 @@ def getconfigfile(self):
318338

319339
return key
320340

341+
def get_template(self,envid,dest,client):
342+
response = client.get_template(envid,dest)
343+
return response
344+
321345
def getAPIkey(self,profile):
322346
key = self.getconfigfile()
323347
config_dict = toml.load(key)

Algorithmia/__main__.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ def main():
107107
parser_cat.add_argument('path', nargs = '*', help = 'file(s) to concatenate and print')
108108
parser_cat.add_argument('--profile', action = 'store', type = str, default = 'default')
109109

110+
#sub parser for getting environment template
111+
parser_template = subparsers.add_parser('template',help='template <envid> <dest> downloads an environment template to the destination')
112+
parser_template.add_argument('envid',help='environment specification id')
113+
parser_template.add_argument('dest',help='destination for template download')
114+
115+
#sub parser for getting environment by language name
116+
parser_env = subparsers.add_parser('environment', help = 'environment <language> gets environment info by language')
117+
parser_env.add_argument('language', help='supported language name')
118+
119+
120+
#sub parser for listing languages
121+
subparsers.add_parser('languages', help = 'lists supported languages')
122+
123+
#sub parser for builds
124+
parser_builds = subparsers.add_parser('builds', help = 'builds <user> <algo> gets build logs for algorithm')
125+
parser_builds.add_argument('user')
126+
parser_builds.add_argument('algo',help='algorithm name')
127+
128+
#sub parser for help
129+
110130
subparsers.add_parser('help')
111131
parser.add_argument('--profile', action = 'store', type = str, default = 'default')
112132

@@ -179,6 +199,23 @@ def main():
179199

180200
elif args.cmd == 'cat':
181201
print(CLI().cat(args.path, client))
202+
203+
elif args.cmd == 'languages':
204+
response = CLI().list_languages(client)
205+
print("{:<25} {:<35}".format('Name','Description'))
206+
for lang in response:
207+
print("{:<25} {:<35}".format(lang['name'],lang['display_name']))
208+
209+
elif args.cmd == 'template':
210+
CLI().get_template(args.envid,args.dest,client)
211+
212+
elif args.cmd == 'environment':
213+
response = CLI().get_environment_by_language(args.language,client)
214+
print(response)
215+
216+
elif args.cmd == 'builds':
217+
print(CLI().getBuildLogs(args.user, args.algo, client))
218+
182219
else:
183220
parser.parse_args(['-h'])
184221

Algorithmia/algorithm.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ def get_build_logs(self, build_id):
112112
error_message = json.loads(e.body)
113113
raise raiseAlgoApiError(error_message)
114114

115+
def build_logs(self):
116+
url = '/v1/algorithms/'+self.username+'/'+self.algoname+'/builds'
117+
response = json.loads(self.client.getHelper(url).content.decode('utf-8'))
118+
return response
119+
115120

116121
def get_scm_status(self):
117122
try:

Algorithmia/client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from tempfile import mkstemp
1111
import atexit
1212
import json, re, requests, six, certifi
13+
import tarfile
1314
import os
1415

1516

@@ -114,6 +115,50 @@ def invite_to_org(self,orgname,username):
114115
response = self.putHelper(url,data={})
115116
return response
116117

118+
119+
def get_template(self,envid,dest,save_tar=False):
120+
url = "/v1/algorithm-environments/edge/environment-specifications/"+envid+"/template"
121+
filename="template.tar.gz"
122+
123+
if not os.path.exists(dest):
124+
os.makedirs(dest)
125+
126+
filepath = os.path.join(dest, filename)
127+
response = self.getStreamHelper(url)
128+
129+
if response.ok:
130+
with open(filepath, 'wb') as f:
131+
for chunk in response.iter_content(chunk_size=1024 * 8):
132+
if chunk:
133+
f.write(chunk)
134+
f.flush()
135+
os.fsync(f.fileno())
136+
137+
tar = tarfile.open(filepath, "r:gz")
138+
tar.extractall(dest)
139+
tar.close()
140+
141+
if not save_tar:
142+
try:
143+
os.remove(filepath)
144+
except OSError as e:
145+
print(e)
146+
return response
147+
else:
148+
return json.loads(response.content.decode("utf-8"))
149+
150+
def get_environment(self,language):
151+
url = "/v1/algorithm-environments/edge/languages/"+language+"/environments"
152+
response = self.getHelper(url)
153+
return response.json()
154+
155+
def get_supported_languages(self):
156+
url ="/v1/algorithm-environments/edge/languages"
157+
response = self.getHelper(url)
158+
return response.json()
159+
160+
161+
117162
# Used to send insight data to Algorithm Queue Reader in cluster
118163
def report_insights(self, insights):
119164
return Insights(insights)
@@ -152,6 +197,12 @@ def getHelper(self, url, **query_parameters):
152197
headers['Authorization'] = self.apiKey
153198
return self.requestSession.get(self.apiAddress + url, headers=headers, params=query_parameters)
154199

200+
def getStreamHelper(self, url, **query_parameters):
201+
headers = {}
202+
if self.apiKey is not None:
203+
headers['Authorization'] = self.apiKey
204+
return self.requestSession.get(self.apiAddress + url, headers=headers, params=query_parameters, stream=True)
205+
155206
def patchHelper(self, url, params):
156207
headers = {'content-type': 'application/json'}
157208
if self.apiKey is not None:

Test/CLI_test.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
import unittest
77
import os
8+
import json
89
import Algorithmia
910
from Algorithmia.CLI import CLI
1011
import argparse
12+
import shutil
1113

1214
class CLITest(unittest.TestCase):
1315
def setUp(self):
@@ -67,6 +69,15 @@ def test_cat(self):
6769
result = CLI().cat([file],self.client)
6870
self.assertEqual(result, fileContents)
6971

72+
def test_get_build_logs(self):
73+
user=os.environ.get('ALGO_USER_NAME')
74+
algo="Echo"
75+
76+
result = json.loads(CLI().getBuildLogs(user,algo,self.client))
77+
if "error" in result:
78+
print(result)
79+
self.assertTrue("error" not in result)
80+
7081

7182
#local to remote
7283
def test_cp_L2R(self):
@@ -160,6 +171,20 @@ def test_auth_cert(self):
160171
self.assertEqual(resultK, key)
161172
self.assertEqual(resultA, address)
162173
self.assertEqual(resultC, cacert)
174+
175+
def test_get_environment(self):
176+
result = CLI().get_environment_by_language("python2",self.client)
177+
print(result)
178+
if("error" in result):
179+
print(result)
180+
self.assertTrue(result is not None and "display_name" in result)
181+
182+
def test_list_languages(self):
183+
result = CLI().list_languages(self.client)
184+
if("error" in result):
185+
print(result)
186+
self.assertTrue(result is not None and "name" in result[0])
187+
163188

164189
def test_rm(self):
165190
localfile = "./TestFiles/testRM.txt"
@@ -180,6 +205,18 @@ def test_rm(self):
180205

181206
self.assertTrue("testRM.txt" in result1 and "testRM.txt" not in result2)
182207

208+
def test_get_template(self):
209+
filename = "./temptest"
210+
envid = "36fd467e-fbfe-4ea6-aa66-df3f403b7132"
211+
response = CLI().get_template(envid,filename,self.client)
212+
print(response)
213+
self.assertTrue(response.ok)
214+
try:
215+
shutil.rmtree(filename)
216+
except OSError as e:
217+
print(e)
218+
219+
183220

184221
if __name__ == '__main__':
185222
unittest.main()

Test/client_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from datetime import datetime, time
2+
import shutil
23
import sys
34
import os
45
from random import seed
@@ -38,6 +39,23 @@ def test_get_org(self):
3839
response = self.c.get_org("a_myOrg84")
3940
self.assertEqual("a_myOrg84",response['org_name'])
4041

42+
def test_get_environment(self):
43+
client =Algorithmia.client(api_key=os.environ.get('ALGORITHMIA_API_KEY'))
44+
response = client.get_environment("python2")
45+
print(response)
46+
if("error" in response):
47+
print(response)
48+
self.assertTrue(response is not None and "environments" in response)
49+
50+
def test_get_build_logs(self):
51+
client = Algorithmia.client(api_key=os.environ.get('ALGORITHMIA_API_KEY'))
52+
user = os.environ.get('ALGO_USER_NAME')
53+
algo = "Echo"
54+
result = client.algo(user+'/'+algo).build_logs()
55+
if "error" in result:
56+
print(result)
57+
self.assertTrue("error" not in result)
58+
4159

4260
def test_edit_org(self):
4361
orgname="a_myOrg84"
@@ -57,6 +75,26 @@ def test_edit_org(self):
5775
response = self.c.edit_org(orgname,obj)
5876
self.assertEqual(204,response.status_code)
5977

78+
def test_get_template(self):
79+
filename = "./temptest"
80+
client =Algorithmia.client(api_key=os.environ.get('ALGORITHMIA_API_KEY'))
81+
response = client.get_template("36fd467e-fbfe-4ea6-aa66-df3f403b7132",filename)
82+
print(response)
83+
self.assertTrue(response.ok)
84+
try:
85+
shutil.rmtree(filename)
86+
except OSError as e:
87+
print(e)
88+
89+
def test_get_supported_languages(self):
90+
client = Algorithmia.client(api_key=os.environ.get('ALGORITHMIA_API_KEY'))
91+
response = client.get_supported_languages()
92+
language_found = any('anaconda3' in languages['name'] for languages in response)
93+
if("error" in response):
94+
print(response)
95+
self.assertTrue(response is not None and language_found)
96+
97+
6098
def test_invite_to_org(self):
6199
response = self.c.invite_to_org("a_myOrg38","a_Mrtest4")
62100
self.assertEqual(200,response.status_code)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name='algorithmia',
7-
version='1.8.2',
7+
version=os.environ.get('CLIENT_VERSION', '0.0.0'),
88
description='Algorithmia Python Client',
99
long_description='Algorithmia Python Client is a client library for accessing Algorithmia from python code. This library also gets bundled with any Python algorithms in Algorithmia.',
1010
url='http://github.com/algorithmiaio/algorithmia-python',

0 commit comments

Comments
 (0)