55from datetime import datetime
66import hashlib
77import random
8+ from requests import api
9+ from requests .models import Response
810import yaml
911import uuid
1012
@@ -14,7 +16,16 @@ def get_entry(
1416 query : dict ,
1517 token : str = None ,
1618)-> list :
17-
19+ """
20+ Internal function to retreive and item from the registy using a query
21+ Args:
22+ | url: str of the registry url
23+ | enpoint: enpoint (table)
24+ | query: dict forming a query
25+ | token: (optional) str of the registry token
26+ Returns:
27+ | dict: responce from registry
28+ """
1829 headers = {}
1930
2031 if token is not None :
@@ -54,7 +65,16 @@ def get_entity(
5465 id : int ,
5566 token : str = None ,
5667)-> list :
57-
68+ """
69+ Internal function to get an item from the registry using it's id
70+ Args:
71+ | url: str of the registry url
72+ | enpoint: endpoint (table)
73+ | id: id of the item
74+ | token: (optional) str of the registry token
75+ Returns:
76+ | dict: responce from registry
77+ """
5878 headers = {}
5979
6080 if token is not None :
@@ -72,7 +92,13 @@ def get_entity(
7292 return response .json ()
7393
7494def extract_id (url : str )-> str :
75-
95+ """
96+ Internal function to return the id from an api url
97+ Args:
98+ | url: str of the api url
99+ Returns:
100+ | str: id derrived from the url
101+ """
76102 parse = urllib .parse .urlsplit (url ).path
77103 extract = list (filter (None , parse .split ('/' )))[- 1 ]
78104
@@ -84,7 +110,16 @@ def post_entry(
84110 data : dict ,
85111 token : str ,
86112)-> dict :
87-
113+ """
114+ Internal function to post and entry on the registry
115+ Args:
116+ | url: str of the registry url
117+ | enpoint: str of the endpoint (table)
118+ | data: a dictionary containing the data to be posted
119+ | token: str of the registry token
120+ Returns:
121+ | dict: responce from registry
122+ """
88123 headers = {
89124 'Authorization' : 'token ' + token ,
90125 'Content-type' : 'application/json'
@@ -110,7 +145,15 @@ def patch_entry(
110145 data : dict ,
111146 token : str
112147)-> dict :
113-
148+ """
149+ Internal function to patch and entry on the registry
150+ Args:
151+ | url: str of the url of what to be patched
152+ | data: a dictionary containing the data to be patched
153+ | token: str of the registry token
154+ Returns:
155+ | dict: responce from registry
156+ """
114157 headers = {
115158 'Authorization' : 'token ' + token ,
116159 'Content-type' : 'application/json'
@@ -125,6 +168,14 @@ def patch_entry(
125168 return response .json ()
126169
127170def post_storage_root (url , data , token ):
171+ """
172+ Internal function to post a storage root to the registry
173+ the function first adds file:// if the root is local
174+ Args:
175+ | url: str the url for the storage root e.g. https://github.com/
176+ Returns:
177+ | dict: repsonse from the local registy
178+ """
128179 if 'local' in data .keys ():
129180 if data ['local' ]:
130181 data ['root' ] = 'file://' + data ['root' ]
@@ -133,22 +184,40 @@ def post_storage_root(url, data, token):
133184 return post_entry (url , 'storage_root' , data , token )
134185
135186def remove_local_from_root (root : str ):
187+ """
188+ Internal function to remove prepending file:// from a given root
189+ Args:
190+ | root: the root
191+ Returns:
192+ | str: the root without file://
193+ """
136194 if 'file://' in root :
137195 root = root .replace ('file://' , '' )
138196
139197 return root
140198
141199
142200def random_hash ()-> str :
201+ """
202+ Internal function to generate a random unique hash
143203
204+ Returns:
205+ | str: 40 character randomly generated hash.
206+ """
144207 seed = datetime .now ().timestamp () * random .uniform (1 , 1000000 )
145208 seed = str (seed ).encode ('utf-8' )
146209 hashed = hashlib .sha1 (seed )
147210
148211 return hashed .hexdigest ()
149212
150213def get_file_hash (path : str )-> str :
151-
214+ """
215+ Internal function to return a files sha1 hash
216+ Args:
217+ | path: str file path
218+ Returns:
219+ | str: sha1 hash
220+ """
152221 with open (path , 'rb' ) as data :
153222 data = data .read ()
154223 #data = data.encode('utf-8')
@@ -157,27 +226,68 @@ def get_file_hash(path: str)-> str:
157226 return hashed .hexdigest ()
158227
159228def read_token (token_path : str ):
229+ """
230+ Internal function read a token from a given file
231+ Args:
232+ | token_path: path to token
233+ Returns:
234+ | str: token
235+ """
160236 with open (token_path ) as token :
161237 token = token .readline ().strip ()
162238 return token
163239
164240def get_token (token_path : str ):
241+ """
242+ Internal function alias for read_token()
243+ Args:
244+ | token_path: path to token
245+ Returns:
246+ | str: token
247+ """
165248 return read_token (token_path )
166249
167250def is_file (filename : str ):
251+ """
252+ Internal function to check whether a file exists
253+ Args:
254+ | filename: file to check
255+ Returns:
256+ | boolean: whether the file exists
257+ """
168258 return os .path .isfile (filename )
169259
170260def is_yaml (filename : str ):
261+ """
262+ Internal function to check whether a file can be opened as a YAML file
263+ ! warning returns True if the file can be coerced into yaml format
264+ Args:
265+ | filename: path to the yaml file
266+ Returns:
267+ | boolean: can the file be coerced into a yaml format?
268+ """
171269 try :
172270 with open (filename , 'r' ) as data :
173271 yaml .safe_load (data )
174272 except : return False
175273 return True
176274
177275def is_valid_yaml (filename : str ):
276+ """
277+ Internal function validate whether a file exists and can be coerced into a yaml format
278+ Args:
279+ | filename: path to the yaml file
280+ Returns:
281+ | boolean: does the file exist and can it be coerced into a yaml format
282+ """
178283 return is_file (filename ) & is_yaml (filename )
179284
180285def generate_uuid ():
286+ """
287+ Internal function similar to random hash
288+ Returns:
289+ | str: a random unique identifier
290+ """
181291 return datetime .now ().strftime ('%Y%m-%d%H-%M%S-' ) + str (uuid .uuid4 ())
182292
183293def get_handle_index_from_path (handle : dict , path : str ):
@@ -198,4 +308,121 @@ def get_handle_index_from_path(handle: dict, path: str):
198308 for input in handle ['input' ]:
199309 if handle ['input' ][input ]['path' ] == path :
200310 tmp = input
201- return tmp
311+ return tmp
312+
313+ def register_issues (token : str , handle : dict ):
314+ """
315+ Internal function, should only be called from finalise.
316+ """
317+
318+ api_url = handle ['yaml' ]['run_metadata' ]['local_data_registry_url' ]
319+ print (handle )
320+ issues = handle ['issues' ]
321+ groups = set (handle ['issues' ][i ]['group' ] for i in handle ['issues' ])
322+
323+ for group in groups :
324+ component_list = []
325+ issue = None
326+ severity = None
327+ for i in issues :
328+ if issues [i ]['group' ] == group :
329+ type = issues [i ]['type' ]
330+ issue = issues [i ]['issue' ]
331+ severity = issues [i ]['severity' ]
332+ index = issues [i ]['index' ]
333+ data_product = issues [i ]['use_data_product' ]
334+ component = issues [i ]['use_component' ]
335+ version = issues [i ]['version' ]
336+ namespace = issues [i ]['use_namespace' ]
337+
338+ component_url = None
339+ object_id = None
340+ if type == 'config' :
341+ object_id = handle ['model_config' ]
342+ elif type == 'submission_script' :
343+ object_id = handle ['submission_script' ]
344+ elif type == 'github_repo' :
345+ object_id = handle ['code_repo' ]
346+
347+ if object_id :
348+ component_url = get_entry (
349+ url = api_url ,
350+ endpoint = 'object_component' ,
351+ query = {
352+ 'object' : extract_id (object_id ),
353+ 'whole_object' : True
354+ }
355+ )[0 ]['url' ]
356+
357+ if index :
358+ if 'output' in handle .keys ():
359+ for ii in handle ['output' ]:
360+ if handle ['output' ][ii ] == index :
361+ if 'component_url' in handle ['output' ][ii ].keys ():
362+ component_url = handle ['output' ][ii ]['component_url' ]
363+ else :
364+ 'No Component Found Please run finalise()'
365+ if 'input' in handle .keys ():
366+ for ii in handle ['input' ]:
367+ if handle ['input' ][ii ] == index :
368+ if 'component_url' in handle ['input' ][ii ].keys ():
369+ component_url = handle ['input' ][ii ]['component_url' ]
370+ else :
371+ 'No Component Found Please run finalise()'
372+
373+ if data_product :
374+ current_namespace = get_entry (
375+ url = api_url ,
376+ endpoint = 'namespace' ,
377+ query = {
378+ 'name' : namespace
379+ }
380+ )[0 ]['url' ]
381+
382+ object = get_entry (
383+ url = api_url ,
384+ endpoint = 'data_product' ,
385+ query = {
386+ 'name' : data_product ,
387+ 'version' : version ,
388+ 'namespace' : extract_id (current_namespace )
389+ }
390+ )[0 ]['object' ]
391+ object_id = extract_id (object )
392+ if component :
393+ component_url = get_entry (
394+ url = api_url ,
395+ endpoint = 'object_component' ,
396+ query = {
397+ 'name' : component ,
398+ 'object' : object_id
399+ }
400+ )
401+ else :
402+ component_obj = get_entry (
403+ url = api_url ,
404+ endpoint = 'object_component' ,
405+ query = {
406+ 'object' : object_id ,
407+ 'whole_object' : True
408+ }
409+ )
410+ component_url = component_obj [0 ]['url' ]
411+
412+ if component_url :
413+ component_list .append (component_url )
414+
415+ # Register the issue:
416+ print ('Registering issue:' + group )
417+ current_issue = post_entry (
418+ url = api_url ,
419+ endpoint = 'issue' ,
420+ data = {
421+ 'severity' : severity ,
422+ 'description' : issue ,
423+ 'component_issues' : component_list
424+ },
425+ token = token
426+ )
427+
428+
0 commit comments