64 self.delete_measurement_pattern = urlparse.urljoin(self.base_url, 'admin/database/measurements/{0}/delete/') |
64 self.delete_measurement_pattern = urlparse.urljoin(self.base_url, 'admin/database/measurements/{0}/delete/') |
65 |
65 |
66 self.api_base_url = urlparse.urljoin(self.base_url, 'api/v1/') |
66 self.api_base_url = urlparse.urljoin(self.base_url, 'api/v1/') |
67 self.api_measurement_pattern = urlparse.urljoin(self.api_base_url, 'measurements/{0}/') |
67 self.api_measurement_pattern = urlparse.urljoin(self.api_base_url, 'measurements/{0}/') |
68 self.api_measurements_url = urlparse.urljoin(self.api_base_url, 'measurements') |
68 self.api_measurements_url = urlparse.urljoin(self.api_base_url, 'measurements') |
|
69 self.api_sounding_search_pattern = urlparse.urljoin(self.api_base_url, 'sounding_files/?filename={0}') |
|
70 self.api_lidarratio_search_pattern = urlparse.urljoin(self.api_base_url, 'lidarratio_files/?filename={0}') |
|
71 self.api_overlap_search_pattern = urlparse.urljoin(self.api_base_url, 'overlap_files/?filename={0}') |
69 |
72 |
70 def login(self, credentials): |
73 def login(self, credentials): |
71 """ Login to SCC. """ |
74 """ Login to SCC. """ |
72 logger.debug("Attempting to login to SCC, username %s." % credentials[0]) |
75 logger.debug("Attempting to login to SCC, username %s." % credentials[0]) |
73 login_credentials = {'username': credentials[0], |
76 login_credentials = {'username': credentials[0], |
102 # Submit the data |
105 # Submit the data |
103 upload_data = {'system': system_id} |
106 upload_data = {'system': system_id} |
104 files = {'data': open(filename, 'rb')} |
107 files = {'data': open(filename, 'rb')} |
105 |
108 |
106 if rs_filename is not None: |
109 if rs_filename is not None: |
107 logger.debug('Adding sounding file %s' % rs_filename) |
110 ancillary_file, _ = self.get_ancillary(rs_filename, 'sounding') |
108 files['sounding_file'] = open(rs_filename, 'rb') |
111 |
|
112 if ancillary_file.already_on_scc: |
|
113 logger.warning("Sounding file {0.filename} already on the SCC with id {0.id}. Ignoring it.".format(ancillary_file)) |
|
114 else: |
|
115 logger.debug('Adding sounding file %s' % rs_filename) |
|
116 files['sounding_file'] = open(rs_filename, 'rb') |
109 |
117 |
110 if ov_filename is not None: |
118 if ov_filename is not None: |
111 logger.debug('Adding overlap file %s' % ov_filename) |
119 ancillary_file, _ = self.get_ancillary(ov_filename, 'overlap') |
112 files['overlap_file'] = open(ov_filename, 'rb') |
120 |
|
121 if ancillary_file.already_on_scc: |
|
122 logger.warning("Overlap file {0.filename} already on the SCC with id {0.id}. Ignoring it.".format(ancillary_file)) |
|
123 else: |
|
124 logger.debug('Adding overlap file %s' % ov_filename) |
|
125 files['overlap_file'] = open(ov_filename, 'rb') |
113 |
126 |
114 if lr_filename is not None: |
127 if lr_filename is not None: |
115 logger.debug('Adding lidar ratio file %s' % lr_filename) |
128 ancillary_file, _ = self.get_ancillary(lr_filename, 'lidarratio') |
116 files['lidar_ratio_file'] = open(lr_filename, 'rb') |
129 |
|
130 if ancillary_file.already_on_scc: |
|
131 logger.warning( |
|
132 "Lidar ratio file {0.filename} already on the SCC with id {0.id}. Ignoring it.".format(ancillary_file)) |
|
133 else: |
|
134 logger.debug('Adding lidar ratio file %s' % lr_filename) |
|
135 files['lidar_ratio_file'] = open(lr_filename, 'rb') |
117 |
136 |
118 logger.info("Uploading of file(s) %s started." % filename) |
137 logger.info("Uploading of file(s) %s started." % filename) |
119 |
138 |
120 upload_submit = self.session.post(self.upload_url, |
139 upload_submit = self.session.post(self.upload_url, |
121 data=upload_data, |
140 data=upload_data, |
451 measurement_number = measurement_number + 1 |
470 measurement_number = measurement_number + 1 |
452 measurement_id = "%s%02i" % (base_id, measurement_number) |
471 measurement_id = "%s%02i" % (base_id, measurement_number) |
453 |
472 |
454 return measurement_id |
473 return measurement_id |
455 |
474 |
|
475 def get_ancillary(self, filename, file_type): |
|
476 """ |
|
477 Try to get the ancillary file data from the SCC API. |
|
478 |
|
479 The result will always be an API object. If the file does not exist, the .exists property is set to False. |
|
480 |
|
481 Parameters |
|
482 ---------- |
|
483 filename : str |
|
484 Filename of the uploaded file. |
|
485 file_type : str |
|
486 Type of ancillary file. One of 'sounding', 'overlap', 'lidarratio'. |
|
487 |
|
488 Returns |
|
489 : AncillaryFile |
|
490 The api object. |
|
491 """ |
|
492 assert file_type in ['sounding', 'overlap', 'lidarratio'] |
|
493 |
|
494 if file_type == 'sounding': |
|
495 file_url = self.api_sounding_search_pattern.format(filename) |
|
496 elif file_type == 'overlap': |
|
497 file_url = self.api_overlap_search_pattern.format(filename) |
|
498 else: |
|
499 file_url = self.api_lidarratio_search_pattern.format(filename) |
|
500 |
|
501 response = self.session.get(file_url) |
|
502 |
|
503 if not response.ok: |
|
504 logger.error('Could not access API. Status code %s.' % response.status_code) |
|
505 return None, response.status_code |
|
506 |
|
507 response_dict = response.json() |
|
508 object_list = response_dict['objects'] |
|
509 |
|
510 logger.debug("Ancillary file JSON: {0}".format(object_list)) |
|
511 |
|
512 if object_list: |
|
513 ancillary_file = AncillaryFile(self.api_base_url, object_list[0]) # Assume only one file is returned |
|
514 else: |
|
515 ancillary_file = AncillaryFile(self.api_base_url, None) # Create an empty object |
|
516 |
|
517 return ancillary_file, response.status_code |
|
518 |
456 class PageNotAccessibleError(RuntimeError): |
519 class PageNotAccessibleError(RuntimeError): |
457 pass |
520 pass |
458 |
521 |
459 |
522 |
460 class ApiObject(object): |
523 class ApiObject(object): |
493 def __str__(self): |
556 def __str__(self): |
494 return "%s: %s, %s, %s" % (self.id, |
557 return "%s: %s, %s, %s" % (self.id, |
495 self.upload, |
558 self.upload, |
496 self.pre_processing, |
559 self.pre_processing, |
497 self.processing) |
560 self.processing) |
|
561 |
|
562 |
|
563 class AncillaryFile(ApiObject): |
|
564 """ This class represents the ancilalry file object as returned in the SCC API. |
|
565 """ |
|
566 @property |
|
567 def already_on_scc(self): |
|
568 if self.exists is False: |
|
569 return False |
|
570 |
|
571 return not self.status == 'missing' |
|
572 |
|
573 def __str__(self): |
|
574 return "%s: %s, %s" % (self.id, |
|
575 self.filename, |
|
576 self.status) |
498 |
577 |
499 |
578 |
500 def process_file(filename, system_id, settings, monitor=True, rs_filename=None, lr_filename=None, ov_filename=None): |
579 def process_file(filename, system_id, settings, monitor=True, rs_filename=None, lr_filename=None, ov_filename=None): |
501 """ Shortcut function to process a file to the SCC. """ |
580 """ Shortcut function to process a file to the SCC. """ |
502 logger.info("Processing file %s, using system %s" % (filename, system_id)) |
581 logger.info("Processing file %s, using system %s" % (filename, system_id)) |