def upload_odlc(client, odlc_file, image_file, team_id=None, actionable_override=None): """Upload a single odlc to the server Args: client: interop.Client connected to the server odlc_file: Path to file containing odlc details in the Object File Format. image_file: Path to odlc thumbnail. May be None. team_id: The username of the team on whose behalf to submit odlcs. Defaults to None. actionable_override: Manually sets the odlc to be actionable. Defaults to None. """ with open(odlc_file) as f: odlc = Odlc.deserialize(json.load(f)) odlc.team_id = team_id odlc.actionable_override = actionable_override logger.info('Uploading odlc %s: %r' % (odlc_file, odlc)) odlc = client.post_odlc(odlc) if image_file: logger.info('Uploading odlc thumbnail %s' % image_file) with open(image_file) as img: client.post_odlc_image(odlc.id, img.read()) else: logger.warning('No thumbnail for odlc %s' % odlc_file)
def post_manual_emergent_target(self, target, image_file_path): """ POST an emergent ODLC object to the interoperability server. :param target: The ODLC target object :type target: JSON, with the form: { "latitude" : float, "longitude" : float, "emergent_description" : String } :param image_file_path: The ODLC target image file name :type image_file_path: String :return: ID of the posted target """ odlc_target = Odlc( type="emergent", autonomous=False, latitude=target["latitude"], longitude=target["longitude"], description='Flint Hill School -- ODLC Emergent Target Submission: ' + str(target["emergent_description"])) returned_odlc = self.client.post_odlc(odlc_target) with open(image_file_path) as img_file: self.client.post_odlc_image(returned_odlc.id, img_file.read())
def post_manual_standard_target(self, target, image_file_path): """ POST a standard ODLC object to the interoperability server. :param target: The ODLC target object. :type target: JSON, with the form: { "latitude" : float, "longitude" : float, "orientation" : string, "shape" : string, "background_color" : string, "alphanumeric" : string, "alphanumeric_color" : string, } :param image_file_path: The ODLC target image file name. :type image_file_path: String :return: ID of the posted target. """ odlc_target = Odlc( type="standard", autonomous=False, latitude=target["latitude"], longitude=target["longitude"], orientation=target["orientation"], shape=target["shape"], background_color=target["background_color"], alphanumeric=target["alphanumeric"], alphanumeric_color=target["alphanumeric_color"], description='Flint Hill School -- ODLC Standard Target Submission') missing_data = True while missing_data: try: returned_odlc = self.client.post_odlc(odlc_target) missing_data = False except ConnectionError: sleep(GCSSettings.INTEROP_DISCONNECT_RETRY_RATE) # todo: 0.5 try: self.client = Client(GCSSettings.INTEROP_URL, GCSSettings.INTEROP_USERNAME, GCSSettings.INTEROP_PASSWORD) except: print("Failed to connect to Interop, retrying...") with open(image_file_path) as img_file: self.client.post_odlc_image(returned_odlc.id, img_file.read())
def convert_target(target_characteristics): """ Converts a target from the JSON data from the web UI to the interop compatible version. :param target_characteristics: dictionary :type target_characteristics: { "alphanumeric" : String, "alphanumeric_color" : String, "target_shape" : String, "orientation" : String, "base_image_filename" : String, "latitude" : float, "longitude" : float } """ return Odlc(target_characteristics)
def post_autonomous_target(self, target_info): """ POST a standard ODLC object to the interoperability server. :param target: The ODLC target object :type target: JSON, with the form: { "latitude" : float, "longitude" : float, "orientation" : string, "shape" : string, "background_color" : string, "alphanumeric" : string, "alphanumeric_color" : string, } :param image_file_path: The ODLC target image file name :type image_file_path: String :return: ID of the posted target """ image_file_path = target_info["target"][0]["current_crop_path"] odlc_target = Odlc( type="standard", autonomous=True, latitude=target_info["target"][0]["latitude"], longitude=target_info["target"][0]["longitude"], orientation=target_info["target"][0]["target_orientation"], shape=target_info["target"][0]["target_shape_type"], background_color=target_info["target"][0]["target_shape_color"], alphanumeric=target_info["target"][0]["target_letter"], alphanumeric_color=target_info["target"][0]["target_letter_color"], description="Flint Hill School -- ODLC Standard Target Submission") returned_odlc = self.client.post_odlc(odlc_target) with open(image_file_path) as img_file: self.client.post_odlc_image(returned_odlc.id, img_file.read())
def post_manual_emergent_target(self, target, image_file_path): """ POST an emergent ODLC object to the interoperability server. :param target: The ODLC target object. :type target: JSON, with the form of { "latitude" : float, "longitude" : float, "emergent_description" : String } :param image_file_path: The ODLC target image file name. :type image_file_path: String :return: ID of the posted target. """ odlc_target = Odlc( type="emergent", autonomous=False, latitude=target["latitude"], longitude=target["longitude"], description='Flint Hill School -- ODLC Emergent Target Submission: ' + str(target["emergent_description"])) # TODO: remove after testing """ returned_odlc = self.client.post_odlc(odlc_target) with open(image_file_path) as img_file: self.client.post_odlc_image(returned_odlc.id, img_file.read()) """ missing_data = True while missing_data: try: returned_odlc = self.client.post_odlc(odlc_target) missing_data = False except ConnectionError: sleep(GCSSettings.INTEROP_DISCONNECT_RETRY_RATE) try: self.client = Client(GCSSettings.INTEROP_URL, GCSSettings.INTEROP_USERNAME, GCSSettings.INTEROP_PASSWORD) except: print("Failed to connect to Interop., retrying...") missing_data = True with open(image_file_path) as img_file: while missing_data: try: self.client.post_odlc_image(returned_odlc.id, img_file.read()) missing_data = False except: sleep(GCSSettings.INTEROP_DISCONNECT_RETRY_RATE) try: self.client = Client(GCSSettings.INTEROP_URL, GCSSettings.INTEROP_USERNAME, GCSSettings.INTEROP_PASSWORD) except: print("Failed to connect to Interop., retrying...")
def load_odlc_file(odlc_filepath): """Loads odlcs from the given file. Args: odlc_filepath: The path to the odlc file to load. Returns: A list of (odlc, image_filepath) tuples. Raises: ValueError if the file is not properly formatted. """ odlcs = [] with open(odlc_filepath, 'r') as f: reader = csv.reader(f, delimiter='\t') for row in reader: odlc_type = row[1] latitude_str = row[2] longitude_str = row[3] orientation = row[4].lower() shape = row[5] background_color = row[6] alphanumeric = row[7] alphanumeric_color = row[8] image_filepath = row[9] description = row[10] odlc = Odlc() if odlc_type not in TARGET_TYPE_MAP: raise ValueError('Type %s not in %s' % (odlc_type, str(TARGET_TYPE_MAP))) odlc.type = TARGET_TYPE_MAP[odlc_type] # Parse latitude. Not required for off axis. if odlc.type != 'off_axis': match = LATITUDE_REGEX.match(latitude_str) if match: latitude = LATITUDE_DIR[match.group('dir')] * ( float(match.group('deg')) + float(match.group('min')) / 60 + float(match.group('sec')) / 3600) odlc.latitude = latitude else: raise ValueError('Latitude is not valid: %s' % latitude_str) # Parse longitude. Not required for off axis. if odlc.type != 'off_axis': match = LONGITUDE_REGEX.match(longitude_str) if match: longitude = LONGITUDE_DIR[match.group('dir')] * ( float(match.group('deg')) + float(match.group('min')) / 60 + float(match.group('sec')) / 3600) odlc.longitude = longitude else: raise ValueError('Longitude is not valid: %s' % longitude_str) if orientation: odlc.orientation = orientation if shape: odlc.shape = shape if background_color: odlc.background_color = background_color if alphanumeric: odlc.alphanumeric = alphanumeric if alphanumeric_color: odlc.alphanumeric_color = alphanumeric_color if description: odlc.description = description odlcs.append((odlc, image_filepath)) return odlcs