32 def __init__(self, auth, output_dir, base_url): |
40 def __init__(self, auth, output_dir, base_url): |
33 self.auth = auth |
41 self.auth = auth |
34 self.output_dir = output_dir |
42 self.output_dir = output_dir |
35 self.base_url = base_url |
43 self.base_url = base_url |
36 self.session = requests.Session() |
44 self.session = requests.Session() |
37 self.construct_urls() |
45 |
38 |
|
39 def construct_urls(self): |
|
40 """ Construct all URLs needed for processing. """ |
|
41 # Construct the absolute URLs |
46 # Construct the absolute URLs |
42 self.login_url = urlparse.urljoin(self.base_url, 'accounts/login/') |
47 self.login_url = urlparse.urljoin(self.base_url, 'accounts/login/') |
43 self.upload_url = urlparse.urljoin(self.base_url, 'data_processing/measurements/quick/') |
48 self.upload_url = urlparse.urljoin(self.base_url, 'data_processing/measurements/quick/') |
44 self.download_preprocessed_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/download-preprocessed/') |
49 self.download_hirelpp_pattern = urlparse.urljoin(self.base_url, |
45 self.download_optical_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/download-optical/') |
50 'data_processing/measurements/{0}/download-hirelpp/') |
46 self.download_graph_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/download-plots/') |
51 self.download_cloudmask_pattern = urlparse.urljoin(self.base_url, |
|
52 'data_processing/measurements/{0}/download-cloudmask/') |
|
53 self.download_elpp_pattern = urlparse.urljoin(self.base_url, |
|
54 'data_processing/measurements/{0}/download-preprocessed/') |
|
55 self.download_elda_pattern = urlparse.urljoin(self.base_url, |
|
56 'data_processing/measurements/{0}/download-optical/') |
|
57 self.download_plot_pattern = urlparse.urljoin(self.base_url, |
|
58 'data_processing/measurements/{0}/download-plots/') |
|
59 self.download_elic_pattern = urlparse.urljoin(self.base_url, |
|
60 'data_processing/measurements/{0}/download-elic/') |
47 self.delete_measurement_pattern = urlparse.urljoin(self.base_url, 'admin/database/measurements/{0}/delete/') |
61 self.delete_measurement_pattern = urlparse.urljoin(self.base_url, 'admin/database/measurements/{0}/delete/') |
48 self.api_base_url = urlparse.urljoin(self.base_url, 'api/v1/') |
62 self.api_base_url = urlparse.urljoin(self.base_url, 'api/v1/') |
|
63 |
|
64 self.login_credentials = None |
49 |
65 |
50 def login(self, credentials): |
66 def login(self, credentials): |
51 """ Login the the website. """ |
67 """ Login the the website. """ |
52 logger.debug("Attempting to login to SCC, username %s." % credentials[0]) |
68 logger.debug("Attempting to login to SCC, username %s." % credentials[0]) |
53 self.login_credentials = {'username': credentials[0], |
69 self.login_credentials = {'username': credentials[0], |
74 return login_submit |
90 return login_submit |
75 |
91 |
76 def logout(self): |
92 def logout(self): |
77 pass |
93 pass |
78 |
94 |
79 def upload_file(self, filename, system_id): |
95 def upload_file(self, filename, system_id, force_upload, delete_related): |
80 """ Upload a filename for processing with a specific system. If the |
96 """ Upload a filename for processing with a specific system. If the |
81 upload is successful, it returns the measurement id. """ |
97 upload is successful, it returns the measurement id. """ |
|
98 |
|
99 measurement_id = self.measurement_id_from_file(filename) |
|
100 |
|
101 logger.debug('Checking if a measurement with the same id already exists on the SCC server.') |
|
102 existing_measurement = self.get_measurement(measurement_id) |
|
103 |
|
104 if existing_measurement: |
|
105 if force_upload: |
|
106 logger.info( |
|
107 "Measurement with id {} already exists on the SCC. Trying to delete it...".format(measurement_id)) |
|
108 self.delete_measurement(measurement_id, delete_related) |
|
109 else: |
|
110 logger.error( |
|
111 "Measurement with id {} already exists on the SCC. Use --force_upload flag to overwrite it.".format( |
|
112 measurement_id)) |
|
113 sys.exit(1) |
|
114 |
82 # Get submit page |
115 # Get submit page |
83 upload_page = self.session.get(self.upload_url, |
116 upload_page = self.session.get(self.upload_url, |
84 auth=self.auth, |
117 auth=self.auth, |
85 verify=False) |
118 verify=False) |
86 |
119 |
87 # Submit the data |
120 # Submit the data |
88 upload_data = {'system': system_id} |
121 upload_data = {'system': system_id} |
89 files = {'data': open(filename, 'rb')} |
122 files = {'data': open(filename, 'rb')} |
90 |
123 |
91 logger.info("Uploading of file %s started." % filename) |
124 logger.info("Uploading of file %s started." % filename) |
92 |
125 logger.debug("URL: {0}, data: {1}, 'X-CSRFToken': {2}".format(self.upload_url, |
|
126 upload_data, |
|
127 upload_page.cookies['csrftoken'])) |
93 upload_submit = self.session.post(self.upload_url, |
128 upload_submit = self.session.post(self.upload_url, |
94 data=upload_data, |
129 data=upload_data, |
95 files=files, |
130 files=files, |
96 headers={'X-CSRFToken': upload_page.cookies['csrftoken'], |
131 headers={'X-CSRFToken': upload_page.cookies['csrftoken'], |
97 'referer': self.upload_url,}, |
132 'referer': self.upload_url, }, |
98 verify=False, |
133 verify=False, |
99 auth=self.auth) |
134 auth=self.auth) |
100 |
135 |
101 if upload_submit.status_code != 200: |
136 if upload_submit.status_code != 200: |
102 logger.warning("Connection error. Status code: %s" % upload_submit.status_code) |
137 logger.warning("Connection error. Status code: %s" % upload_submit.status_code) |
143 local_file = os.path.join(local_dir, basename) |
197 local_file = os.path.join(local_dir, basename) |
144 |
198 |
145 with open(local_file, 'wb') as f: |
199 with open(local_file, 'wb') as f: |
146 f.write(zip_file.read(ziped_name)) |
200 f.write(zip_file.read(ziped_name)) |
147 |
201 |
148 def download_preprocessed(self, measurement_id): |
202 def download_hirelpp(self, measurement_id): |
|
203 """ Download hirelpp files for the measurement id. """ |
|
204 # Construct the download url |
|
205 download_url = self.download_hirelpp_pattern.format(measurement_id) |
|
206 try: |
|
207 self.download_files(measurement_id, 'scc_hirelpp', download_url) |
|
208 except Exception as e: |
|
209 logger.error("Could not download HiRElPP files. Error message: {}".format(e)) |
|
210 logger.debug('Download exception:', exc_info=True) |
|
211 |
|
212 def download_cloudmask(self, measurement_id): |
|
213 """ Download cloudmask files for the measurement id. """ |
|
214 # Construct the download url |
|
215 download_url = self.download_cloudmask_pattern.format(measurement_id) |
|
216 try: |
|
217 self.download_files(measurement_id, 'scc_cloudscreen', download_url) |
|
218 except Exception as e: |
|
219 logger.error("Could not download cloudscreen files. Error message: {}".format(e)) |
|
220 logger.debug('Download exception:', exc_info=True) |
|
221 |
|
222 def download_elpp(self, measurement_id): |
149 """ Download preprocessed files for the measurement id. """ |
223 """ Download preprocessed files for the measurement id. """ |
150 # Construct the download url |
224 # Construct the download url |
151 download_url = self.download_preprocessed_pattern.format(measurement_id) |
225 download_url = self.download_elpp_pattern.format(measurement_id) |
152 self.download_files(measurement_id, 'scc_preprocessed', download_url) |
226 try: |
153 |
227 self.download_files(measurement_id, 'scc_preprocessed', download_url) |
154 def download_optical(self, measurement_id): |
228 except Exception as e: |
|
229 logger.error("Could not download ElPP files. Error message: {}".format(e)) |
|
230 logger.debug('Download exception:', exc_info=True) |
|
231 |
|
232 def download_elda(self, measurement_id): |
155 """ Download optical files for the measurement id. """ |
233 """ Download optical files for the measurement id. """ |
156 # Construct the download url |
234 # Construct the download url |
157 download_url = self.download_optical_pattern.format(measurement_id) |
235 download_url = self.download_elda_pattern.format(measurement_id) |
158 self.download_files(measurement_id, 'scc_optical', download_url) |
236 try: |
159 |
237 self.download_files(measurement_id, 'scc_optical', download_url) |
160 def download_graphs(self, measurement_id): |
238 except Exception as e: |
|
239 logger.error("Could not download ELDA files. Error message: {}".format(e)) |
|
240 logger.debug('Download exception:', exc_info=True) |
|
241 |
|
242 def download_plots(self, measurement_id): |
161 """ Download profile graphs for the measurement id. """ |
243 """ Download profile graphs for the measurement id. """ |
162 # Construct the download url |
244 # Construct the download url |
163 download_url = self.download_graph_pattern.format(measurement_id) |
245 download_url = self.download_plot_pattern.format(measurement_id) |
164 self.download_files(measurement_id, 'scc_plots', download_url) |
246 try: |
165 |
247 self.download_files(measurement_id, 'scc_plots', download_url) |
166 def rerun_processing(self, measurement_id, monitor=True): |
248 except Exception as e: |
|
249 logger.error("Could not download ELDA plots. Error message: {}".format(e)) |
|
250 logger.debug('Download exception:', exc_info=True) |
|
251 |
|
252 def download_elic(self, measurement_id): |
|
253 """ Download ELIC files for the measurement id. """ |
|
254 # Construct the download url |
|
255 download_url = self.download_elic_pattern.format(measurement_id) |
|
256 try: |
|
257 self.download_files(measurement_id, 'scc_elic', download_url) |
|
258 except Exception as e: |
|
259 logger.error("Could not download ELIC files. Error message: {}".format(e)) |
|
260 logger.debug('Download exception:', exc_info=True) |
|
261 |
|
262 def download_eldec(self, measurement_id): |
|
263 """ Download ELDEC files for the measurement id. """ |
|
264 # Construct the download url |
|
265 download_url = self.download_elda_pattern.format(measurement_id) # ELDA patter is used for now |
|
266 try: |
|
267 self.download_files(measurement_id, 'scc_eldec', download_url) |
|
268 except Exception as e: |
|
269 logger.error("Could not download EDELC files. Error message: {}".format(e)) |
|
270 logger.debug('Download exception:', exc_info=True) |
|
271 |
|
272 def rerun_elpp(self, measurement_id, monitor=True): |
167 measurement = self.get_measurement(measurement_id) |
273 measurement = self.get_measurement(measurement_id) |
168 |
274 |
169 if measurement: |
275 if measurement: |
170 request = self.session.get(measurement.rerun_processing_url, auth=self.auth, |
276 request = self.session.get(measurement.rerun_elpp_url, auth=self.auth, |
171 verify=False, |
277 verify=False, |
172 stream=True) |
278 stream=True) |
173 |
279 |
174 if request.status_code != 200: |
280 if request.status_code != 200: |
175 logger.error( |
281 logger.error( |
176 "Could not rerun processing for %s. Status code: %s" % (measurement_id, request.status_code)) |
282 "Could not rerun ELPP for %s. Status code: %s" % (measurement_id, request.status_code)) |
177 return |
283 return |
178 |
284 |
179 if monitor: |
285 if monitor: |
180 self.monitor_processing(measurement_id) |
286 self.monitor_processing(measurement_id) |
181 |
287 |
198 return |
304 return |
199 |
305 |
200 if monitor: |
306 if monitor: |
201 self.monitor_processing(measurement_id) |
307 self.monitor_processing(measurement_id) |
202 |
308 |
203 def process(self, filename, system_id): |
309 def process(self, filename, system_id, force_upload, delete_related): |
204 """ Upload a file for processing and wait for the processing to finish. |
310 """ Upload a file for processing and wait for the processing to finish. |
205 If the processing is successful, it will download all produced files. |
311 If the processing is successful, it will download all produced files. |
206 """ |
312 """ |
207 logger.info("--- Processing started on %s. ---" % datetime.datetime.now()) |
313 logger.info("--- Processing started on %s. ---" % datetime.datetime.now()) |
|
314 |
208 # Upload file |
315 # Upload file |
209 measurement_id = self.upload_file(filename, system_id) |
316 measurement_id = self.upload_file(filename, system_id, force_upload, delete_related) |
210 |
317 |
211 measurement = self.monitor_processing(measurement_id) |
318 measurement = self.monitor_processing(measurement_id) |
212 return measurement |
319 return measurement |
213 |
320 |
214 def monitor_processing(self, measurement_id): |
321 def monitor_processing(self, measurement_id): |
215 """ Monitor the processing progress of a measurement id""" |
322 """ Monitor the processing progress of a measurement id""" |
216 |
323 |
217 measurement = self.get_measurement(measurement_id) |
324 measurement = self.get_measurement(measurement_id) |
218 if measurement is not None: |
325 if measurement is not None: |
219 while measurement.is_running: |
326 while measurement.is_running: |
220 logger.info("Measurement is being processed (status: %s, %s, %s). Please wait." % (measurement.upload, |
327 logger.info("Measurement is being processed (status: {}, {}, {}, {}, {}, {}). Please wait.".format( |
221 measurement.pre_processing, |
328 measurement.upload, |
222 measurement.processing)) |
329 measurement.hirelpp, |
|
330 measurement.cloudmask, |
|
331 measurement.elpp, |
|
332 measurement.elda, |
|
333 measurement.elic)) |
223 time.sleep(10) |
334 time.sleep(10) |
224 measurement = self.get_measurement(measurement_id) |
335 measurement = self.get_measurement(measurement_id) |
225 logger.info("Measurement processing finished (status: %s, %s, %s)." % (measurement.upload, |
336 logger.info("Measurement processing finished (status: {}, {}, {}, {}, {}, {}). Please wait.".format( |
226 measurement.pre_processing, |
337 measurement.upload, |
227 measurement.processing)) |
338 measurement.hirelpp, |
228 if measurement.pre_processing == 127: |
339 measurement.cloudmask, |
229 logger.info("Downloading preprocessed files.") |
340 measurement.elpp, |
230 self.download_preprocessed(measurement_id) |
341 measurement.elda, |
231 if measurement.processing == 127: |
342 measurement.elic)) |
232 logger.info("Downloading optical files.") |
343 if measurement.hirelpp == 127: |
233 self.download_optical(measurement_id) |
344 logger.info("Downloading HiRElPP files.") |
|
345 self.download_hirelpp(measurement_id) |
|
346 if measurement.cloudmask == 127: |
|
347 logger.info("Downloading cloud screening files.") |
|
348 self.download_cloudmask(measurement_id) |
|
349 if measurement.elpp == 127: |
|
350 logger.info("Downloading ELPP files.") |
|
351 self.download_elpp(measurement_id) |
|
352 if measurement.elda == 127: |
|
353 logger.info("Downloading ELDA files.") |
|
354 self.download_elda(measurement_id) |
234 logger.info("Downloading graphs.") |
355 logger.info("Downloading graphs.") |
235 self.download_graphs(measurement_id) |
356 self.download_plots(measurement_id) |
|
357 if measurement.elic == 127: |
|
358 logger.info("Downloading ELIC files.") |
|
359 self.download_elic(measurement_id) |
|
360 |
|
361 # TODO: Need to check ELDEC code (when it becomes available in the API) |
|
362 if measurement.is_calibration: |
|
363 logger.info("Downloading ELDEC files.") |
|
364 self.download_eldec(measurement_id) |
|
365 |
236 logger.info("--- Processing finished. ---") |
366 logger.info("--- Processing finished. ---") |
237 return measurement |
367 return measurement |
238 |
368 |
239 def get_status(self, measurement_id): |
369 def get_measurement(self, measurement_id): |
240 """ Get the processing status for a measurement id through the API. """ |
370 |
241 measurement_url = urlparse.urljoin(self.api_base_url, 'measurements/?id__exact=%s' % measurement_id) |
371 if measurement_id is None: |
|
372 return None |
|
373 |
|
374 measurement_url = urlparse.urljoin(self.api_base_url, 'measurements/%s/' % measurement_id) |
242 |
375 |
243 response = self.session.get(measurement_url, |
376 response = self.session.get(measurement_url, |
244 auth=self.auth, |
377 auth=self.auth, |
245 verify=False) |
378 verify=False) |
246 |
379 |
247 response_dict = response.json() |
380 response_dict = None |
248 |
381 if response.status_code == 200: |
249 if response_dict['objects']: |
382 response_dict = response.json() |
250 measurement_list = response_dict['objects'] |
383 if response.status_code == 404: |
251 measurement = Measurement(self.base_url, measurement_list[0]) |
384 logger.info("No measurement with id %s found on the SCC." % measurement_id) |
252 return measurement.upload, measurement.pre_processing, measurement.processing |
385 elif response.status_code != 200: |
253 else: |
|
254 logger.error("No measurement with id %s found on the SCC." % measurement_id) |
|
255 return None |
|
256 |
|
257 def get_measurement(self, measurement_id): |
|
258 measurement_url = urlparse.urljoin(self.api_base_url, 'measurements/%s/' % measurement_id) |
|
259 |
|
260 response = self.session.get(measurement_url, |
|
261 auth=self.auth, |
|
262 verify=False) |
|
263 |
|
264 if response.status_code != 200: |
|
265 logger.error('Could not access API. Status code %s.' % response.status_code) |
386 logger.error('Could not access API. Status code %s.' % response.status_code) |
266 sys.exit(1) |
387 sys.exit(1) |
267 |
388 |
268 response_dict = response.json() |
389 logger.debug("Response dictionary: {}".format(response_dict)) |
269 |
390 |
270 if response_dict: |
391 if response_dict: |
271 measurement = Measurement(self.base_url,response_dict) |
392 measurement = Measurement(self.base_url, response_dict) |
272 return measurement |
393 return measurement |
273 else: |
394 else: |
274 logger.error("No measurement with id %s found on the SCC." % measurement_id) |
|
275 return None |
395 return None |
276 |
396 |
277 def delete_measurement(self, measurement_id): |
397 def delete_measurement(self, measurement_id, delete_related=False): |
278 """ Deletes a measurement with the provided measurement id. The user |
398 """ Deletes a measurement with the provided measurement id. The user |
279 should have the appropriate permissions. |
399 should have the appropriate permissions. |
280 |
400 |
281 The procedures is performed directly through the web interface and |
401 The procedures is performed directly through the web interface and |
282 NOT through the API. |
402 NOT through the API. |
290 return None |
410 return None |
291 |
411 |
292 # Go the the page confirming the deletion |
412 # Go the the page confirming the deletion |
293 delete_url = self.delete_measurement_pattern.format(measurement.id) |
413 delete_url = self.delete_measurement_pattern.format(measurement.id) |
294 |
414 |
|
415 logger.debug("Delete url: {}".format(delete_url)) |
|
416 |
295 confirm_page = self.session.get(delete_url, |
417 confirm_page = self.session.get(delete_url, |
296 auth=self.auth, |
418 auth=self.auth, |
297 verify=False) |
419 verify=False) |
298 |
420 |
299 # Check that the page opened properly |
421 # Check that the page opened properly |
300 if confirm_page.status_code != 200: |
422 if confirm_page.status_code != 200: |
301 logger.warning("Could not open delete page. Status: {0}".format(confirm_page.status_code)) |
423 logger.warning("Could not open delete page. Status: {0}".format(confirm_page.status_code)) |
302 return None |
424 return None |
303 |
425 |
|
426 # Get the delete related value |
|
427 if delete_related: |
|
428 delete_related_option = 'delete_related' |
|
429 else: |
|
430 delete_related_option = 'not_delete_related' |
|
431 |
304 # Delete the measurement |
432 # Delete the measurement |
305 delete_page = self.session.post(delete_url, |
433 delete_page = self.session.post(delete_url, |
306 auth=self.auth, |
434 auth=self.auth, |
307 verify=False, |
435 verify=False, |
308 data={'post': 'yes'}, |
436 data={'post': 'yes', |
|
437 'select_delete_related_measurements': delete_related_option}, |
309 headers={'X-CSRFToken': confirm_page.cookies['csrftoken'], |
438 headers={'X-CSRFToken': confirm_page.cookies['csrftoken'], |
310 'referer': delete_url} |
439 'referer': delete_url} |
311 ) |
440 ) |
312 if delete_page.status_code != 200: |
441 if delete_page.status_code != 200: |
313 logger.warning("Something went wrong. Delete page status: {0}".format( |
442 logger.warning("Something went wrong. Delete page status: {0}".format( |
314 delete_page.status_code)) |
443 delete_page.status_code)) |
315 return None |
444 return None |
316 |
445 |
317 logger.info("Deleted measurement {0}".format(measurement_id)) |
446 logger.info("Deleted measurement {0}.".format(measurement_id)) |
318 return True |
447 return True |
319 |
448 |
320 def available_measurements(self): |
449 def available_measurements(self): |
321 """ Get a list of available measurement on the SCC. """ |
450 """ Get a list of available measurement on the SCC. """ |
322 measurement_url = urlparse.urljoin(self.api_base_url, 'measurements') |
451 measurement_url = urlparse.urljoin(self.api_base_url, 'measurements') |
323 response = self.session.get(measurement_url, |
452 response = self.session.get(measurement_url, |
324 auth=self.auth, |
453 auth=self.auth, |
325 verify=False) |
454 verify=False) |
326 response_dict = response.json() |
455 response_dict = response.json() |
327 |
456 |
328 measurements = None |
|
329 if response_dict: |
457 if response_dict: |
330 measurement_list = response_dict['objects'] |
458 measurement_list = response_dict['objects'] |
331 measurements = [Measurement(self.base_url, measurement_dict) for measurement_dict in measurement_list] |
459 measurements = [Measurement(self.base_url, measurement_dict) for measurement_dict in measurement_list] |
332 logger.info("Found %s measurements on the SCC." % len(measurements)) |
460 logger.info("Found %s measurements on the SCC." % len(measurements)) |
333 else: |
461 else: |
|
462 measurements = None |
334 logger.warning("No response received from the SCC when asked for available measurements.") |
463 logger.warning("No response received from the SCC when asked for available measurements.") |
335 |
464 |
336 return measurements |
465 return measurements |
337 |
466 |
338 def measurement_id_for_date(self, t1, call_sign='bu', base_number=0): |
467 def measurement_id_for_date(self, t1, call_sign, base_number=0): |
339 """ Give the first available measurement id on the SCC for the specific |
468 """ Give the first available measurement id on the SCC for the specific |
340 date. |
469 date. |
341 """ |
470 """ |
342 date_str = t1.strftime('%Y%m%d') |
471 date_str = t1.strftime('%Y%m%d') |
343 search_url = urlparse.urljoin(self.api_base_url, 'measurements/?id__startswith=%s' % date_str) |
472 search_url = urlparse.urljoin(self.api_base_url, 'measurements/?id__startswith=%s' % date_str) |
353 if response_dict: |
482 if response_dict: |
354 measurement_list = response_dict['objects'] |
483 measurement_list = response_dict['objects'] |
355 existing_ids = [measurement_dict['id'] for measurement_dict in measurement_list] |
484 existing_ids = [measurement_dict['id'] for measurement_dict in measurement_list] |
356 |
485 |
357 measurement_number = base_number |
486 measurement_number = base_number |
358 measurement_id = "%s%s%02i" % (date_str, call_sign, measurement_number) |
487 measurement_id = "%s%s%04i" % (date_str, call_sign, measurement_number) |
359 |
488 |
360 while measurement_id in existing_ids: |
489 while measurement_id in existing_ids: |
361 measurement_number = measurement_number + 1 |
490 measurement_number = measurement_number + 1 |
362 measurement_id = "%s%s%02i" % (date_str, call_sign, measurement_number) |
491 measurement_id = "%s%s%04i" % (date_str, call_sign, measurement_number) |
363 if measurement_number == 100: |
492 if measurement_number == 1000: |
364 raise ValueError('No available measurement id found.') |
493 raise ValueError('No available measurement id found.') |
365 |
494 |
366 return measurement_id |
495 return measurement_id |
367 |
496 |
368 |
497 def __enter__(self): |
369 class ApiObject: |
498 return self |
370 """ A generic class object. """ |
499 |
|
500 def __exit__(self, *args): |
|
501 logger.debug("Closing SCC connection session.") |
|
502 self.session.close() |
|
503 |
|
504 |
|
505 class Measurement: |
|
506 """ This class represents the measurement object as returned in the SCC API. |
|
507 """ |
371 |
508 |
372 def __init__(self, base_url, dict_response): |
509 def __init__(self, base_url, dict_response): |
373 self.base_url = base_url |
510 self.base_url = base_url |
|
511 |
|
512 # Define expected attributes to assist debuggin |
|
513 self.cloudmask = None |
|
514 self.elda = None |
|
515 self.elic = None |
|
516 self.elpp = None |
|
517 self.hirelpp = None |
|
518 self.id = None |
|
519 self.is_calibration = None |
|
520 self.is_running = None |
|
521 self.pre_processing_exit_code = None |
|
522 self.processing_exit_code = None |
|
523 self.resource_uri = None |
|
524 self.start = None |
|
525 self.stop = None |
|
526 self.system = None |
|
527 self.upload = None |
374 |
528 |
375 if dict_response: |
529 if dict_response: |
376 # Add the dictionary key value pairs as object properties |
530 # Add the dictionary key value pairs as object properties |
377 for key, value in dict_response.items(): |
531 for key, value in dict_response.items(): |
378 setattr(self, key, value) |
532 setattr(self, key, value) |
379 self.exists = True |
533 self.exists = True |
380 else: |
534 else: |
381 self.exists = False |
535 self.exists = False |
382 |
536 |
383 |
|
384 class Measurement(ApiObject): |
|
385 """ This class represents the measurement object as returned in the SCC API. |
|
386 """ |
|
387 |
|
388 @property |
537 @property |
389 def is_running(self): |
538 def rerun_elda_url(self): |
390 """ Returns True if the processing has not finished. |
539 url_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/rerun-elda/') |
391 """ |
540 return url_pattern.format(self.id) |
392 if self.upload == 0: |
|
393 return False |
|
394 if self.pre_processing == -127: |
|
395 return False |
|
396 if self.pre_processing == 127: |
|
397 if self.processing in [127, -127]: |
|
398 return False |
|
399 return True |
|
400 |
541 |
401 @property |
542 @property |
402 def rerun_processing_url(self): |
543 def rerun_elpp_url(self): |
403 url_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/rerun-optical/') |
544 url_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/rerun-elpp/') |
404 return url_pattern.format(self.id) |
545 return url_pattern.format(self.id) |
405 |
546 |
406 @property |
547 @property |
407 def rerun_all_url(self): |
548 def rerun_all_url(self): |
408 ulr_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/rerun-all/') |
549 ulr_pattern = urlparse.urljoin(self.base_url, 'data_processing/measurements/{0}/rerun-all/') |
409 return ulr_pattern.format(self.id) |
550 return ulr_pattern.format(self.id) |
410 |
551 |
411 def __str__(self): |
552 def __str__(self): |
412 return "%s: %s, %s, %s" % (self.id, |
553 return "Measurement {}".format(self.id) |
413 self.upload, |
554 |
414 self.pre_processing, |
555 |
415 self.processing) |
556 def upload_file(filename, system_id, force_upload, delete_related, settings): |
416 |
|
417 |
|
418 def upload_file(filename, system_id, settings): |
|
419 """ Shortcut function to upload a file to the SCC. """ |
557 """ Shortcut function to upload a file to the SCC. """ |
420 logger.info("Uploading file %s, using sytem %s" % (filename, system_id)) |
558 logger.info("Uploading file %s, using system %s." % (filename, system_id)) |
421 |
559 |
422 scc = SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) |
560 with SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) as scc: |
423 scc.login(settings['website_credentials']) |
561 scc.login(settings['website_credentials']) |
424 measurement_id = scc.upload_file(filename, system_id) |
562 measurement_id = scc.upload_file(filename, system_id, force_upload, delete_related) |
425 scc.logout() |
563 scc.logout() |
|
564 |
426 return measurement_id |
565 return measurement_id |
427 |
566 |
428 |
567 |
429 def process_file(filename, system_id, settings): |
568 def process_file(filename, system_id, force_upload, delete_related, settings): |
430 """ Shortcut function to process a file to the SCC. """ |
569 """ Shortcut function to process a file to the SCC. """ |
431 logger.info("Processing file %s, using sytem %s" % (filename, system_id)) |
570 logger.info("Processing file %s, using system %s." % (filename, system_id)) |
432 |
571 |
433 scc = SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) |
572 with SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) as scc: |
434 scc.login(settings['website_credentials']) |
573 scc.login(settings['website_credentials']) |
435 measurement = scc.process(filename, system_id) |
574 measurement = scc.process(filename, system_id, force_upload, delete_related) |
436 scc.logout() |
575 scc.logout() |
|
576 |
437 return measurement |
577 return measurement |
438 |
578 |
439 |
579 |
440 def delete_measurement(measurement_id, settings): |
580 def delete_measurement(measurement_id, settings, delete_related): |
441 """ Shortcut function to delete a measurement from the SCC. """ |
581 """ Shortcut function to delete a measurement from the SCC. """ |
442 logger.info("Deleting %s" % measurement_id) |
582 logger.info("Deleting %s." % measurement_id) |
443 |
583 |
444 scc = SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) |
584 with SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) as scc: |
445 scc.login(settings['website_credentials']) |
585 scc.login(settings['website_credentials']) |
446 scc.delete_measurement(measurement_id) |
586 scc.delete_measurement(measurement_id, delete_related) |
447 scc.logout() |
587 scc.logout() |
448 |
588 |
449 |
589 |
450 def rerun_all(measurement_id, monitor, settings): |
590 def rerun_all(measurement_id, monitor, settings): |
451 """ Shortcut function to delete a measurement from the SCC. """ |
591 """ Shortcut function to delete a measurement from the SCC. """ |
452 logger.info("Rerunning all products for %s" % measurement_id) |
592 logger.info("Rerunning all products for %s" % measurement_id) |
453 |
593 |
454 scc = SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) |
594 with SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) as scc: |
455 scc.login(settings['website_credentials']) |
595 scc.login(settings['website_credentials']) |
456 scc.rerun_all(measurement_id, monitor) |
596 scc.rerun_all(measurement_id, monitor) |
457 scc.logout() |
597 scc.logout() |
458 |
598 |
459 |
599 |
460 def rerun_processing(measurement_id, monitor, settings): |
600 def rerun_elpp(measurement_id, monitor, settings): |
461 """ Shortcut function to delete a measurement from the SCC. """ |
601 """ Shortcut function to delete a measurement from the SCC. """ |
462 logger.info("Rerunning (optical) processing for %s" % measurement_id) |
602 logger.info("Rerunning (optical) processing for %s" % measurement_id) |
463 |
603 |
464 scc = SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) |
604 with SCC(settings['basic_credentials'], settings['output_dir'], settings['base_url']) as scc: |
465 scc.login(settings['website_credentials']) |
605 scc.login(settings['website_credentials']) |
466 scc.rerun_processing(measurement_id, monitor) |
606 scc.rerun_elpp(measurement_id, monitor) |
467 scc.logout() |
607 scc.logout() |
468 |
608 |
469 |
609 |
470 def import_settings(config_file_path): |
610 def import_settings(config_file_path): |
471 """ Read the configuration file. |
611 """ Read the configuration file. |
472 |
612 |
497 parser.add_argument("filename", nargs='?', help="Measurement file name or path.", default='') |
638 parser.add_argument("filename", nargs='?', help="Measurement file name or path.", default='') |
498 parser.add_argument("system", nargs='?', help="Processing system id.", default=0) |
639 parser.add_argument("system", nargs='?', help="Processing system id.", default=0) |
499 parser.add_argument("-p", "--process", help="Wait for the results of the processing.", |
640 parser.add_argument("-p", "--process", help="Wait for the results of the processing.", |
500 action="store_true") |
641 action="store_true") |
501 parser.add_argument("--delete", help="Measurement ID to delete.") |
642 parser.add_argument("--delete", help="Measurement ID to delete.") |
502 parser.add_argument("--rerun-all", help="Measurement ID to rerun.") |
643 # parser.add_argument("--delete_related", help= |
503 parser.add_argument("--rerun-processing", help="Measurement ID to rerun processing routines.") |
644 # "Delete all related measurements. Use only if you know what you are doing!", |
|
645 # action="store_true") |
|
646 parser.add_argument("--force_upload", help="If measurement ID exists on SCC, delete before uploading.", |
|
647 action="store_true") |
|
648 parser.add_argument("--rerun-all", help="Rerun all processing steps for the provided measurement ID.") |
|
649 parser.add_argument("--rerun-elpp", help="Rerun low-resolution processing steps for the provided measurement ID.") |
504 |
650 |
505 # Verbosity settings from http://stackoverflow.com/a/20663028 |
651 # Verbosity settings from http://stackoverflow.com/a/20663028 |
506 parser.add_argument('-d', '--debug', help="Print debugging information.", action="store_const", |
652 parser.add_argument('-d', '--debug', help="Print debugging information.", action="store_const", |
507 dest="loglevel", const=logging.DEBUG, default=logging.INFO, |
653 dest="loglevel", const=logging.DEBUG, default=logging.INFO, |
508 ) |
654 ) |
510 dest="loglevel", const=logging.WARNING |
656 dest="loglevel", const=logging.WARNING |
511 ) |
657 ) |
512 |
658 |
513 args = parser.parse_args() |
659 args = parser.parse_args() |
514 |
660 |
|
661 # For now, don to allow to delete related measurements |
|
662 delete_related = False |
|
663 |
515 # Get the logger with the appropriate level |
664 # Get the logger with the appropriate level |
516 logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel) |
665 logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel) |
517 |
666 |
518 settings = import_settings(args.config) |
667 settings = import_settings(args.config) |
519 |
668 |
520 # If the arguments are OK, try to log-in to SCC and upload. |
669 # If the arguments are OK, try to log-in to SCC and upload. |
521 if args.delete: |
670 if args.delete: |
522 # If the delete is provided, do nothing else |
671 # If the delete is provided, do nothing else |
523 delete_measurement(args.delete, settings) |
672 delete_measurement(args.delete, settings, delete_related) |
524 elif args.rerun_all: |
673 elif args.rerun_all: |
525 rerun_all(args.rerun_all, args.process, settings) |
674 rerun_all(args.rerun_all, args.process, settings) |
526 elif args.rerun_processing: |
675 elif args.rerun_elpp: |
527 rerun_processing(args.rerun_processing, args.process, settings) |
676 rerun_elpp(args.rerun_elpp, args.process, settings) |
528 else: |
677 else: |
529 if (args.filename == '') or (args.system == 0): |
678 if (args.filename == '') or (args.system == 0): |
530 parser.error('Provide a valid filename and system parameters.\nRun with -h for help.\n') |
679 parser.error('Provide a valid filename and system parameters.\nRun with -h for help.\n') |
531 |
680 |
532 if args.process: |
681 if args.process: |
533 process_file(args.filename, args.system, settings) |
682 process_file(args.filename, args.system, args.force_upload, delete_related, settings) |
534 else: |
683 else: |
535 upload_file(args.filename, args.system, settings) |
684 upload_file(args.filename, args.system, args.force_upload, delete_related, settings) |