Source code for plio.io.isis_serial_number
import warnings
import pvl
from pvl.collections import PVLModule
from itertools import chain
import plio
from plio.data import get_data
from plio.io.io_db import Translations, StringToMission, setup_db_session
from plio.utils.utils import find_in_dict, find_nested_in_dict
[docs]def get_isis_translation(label):
"""
Compute the ISIS serial number for a given image using
the input cube or the label extracted from the cube.
Parameters
----------
label : dict or str
A PVL dict object or file name to extract
the PVL object from
Returns
-------
translation : dict
A PVLModule object containing the extracted
translation file
"""
# Instantiate a DB session if not already instantiated
if not hasattr(plio, 'data_session'):
plio.data_session = setup_db_session(get_data('data.db'))
# Grab the label is not already read
if not isinstance(label, PVLModule):
label = pvl.load(label)
# Grab the spacecraft name and run it through the ISIS lookup
spacecraft_name = find_in_dict(label, 'SpacecraftName')
for row in plio.data_session.query(StringToMission).filter(StringToMission.key==spacecraft_name):
spacecraft_name = row.value.lower()
# Try and pull an instrument identifier
try:
instrumentid = find_in_dict(label, 'InstrumentId').capitalize()
except:
instrumentid = None
translation = None
# Grab the translation PVL object using the lookup
for row in plio.data_session.query(Translations).filter(Translations.mission==spacecraft_name,
Translations.instrument==instrumentid):
# Convert the JSON back to a PVL object
translation = PVLModule(row.translation)
return translation
[docs]def generate_serial_number(label):
"""
Generate an ISIS compatible serial number using the ISIS
team's translation files
Parameters
----------
label : dict or str
A PVLModule object (dict) or string PATH
to a file containing a PVL header
Returns
-------
: str
The ISIS compatible serial number
"""
if not isinstance(label, PVLModule):
label = pvl.load(label, decoder=SerialNumberDecoder())
# Get the translation information
translation = get_isis_translation(label)
if not translation:
warnings.warn('Unable to load an appropriate image translation.')
return
serial_number = []
# Sort the keys to ensure proper iteration order
keys = sorted(translation.keys())
for k in keys:
try:
group = translation[k]
search_key = group['InputKey']
search_position = group['InputPosition']
search_translation = {group['Translation'][1]:group['Translation'][0]}
sub_group = find_nested_in_dict(label, search_position)
serial_entry = sub_group[search_key]
if serial_entry in search_translation.keys():
serial_entry = search_translation[serial_entry]
elif '*' in search_translation.keys() and search_translation['*'] != '*':
serial_entry = search_translation['*']
serial_number.append(serial_entry)
except:
pass
return '/'.join(serial_number)
[docs]class SerialNumberDecoder(pvl.decoder.PVLDecoder):
"""
A PVL Decoder class to handle cube label parsing for the purpose of creating a valid ISIS
serial number. Inherits from the PVLDecoder in planetarypy's pvl module.
"""
[docs] def decode_simple_value(self, value: str):
"""Returns a Python object based on *value*, assuming
that *value* can be decoded as a PVL Simple Value::
<Simple-Value> ::= (<Numeric> | <String>)
Modified from https://pvl.readthedocs.io/en/stable/_modules/pvl/decoder.html#PVLDecoder.decode_simple_value
Modification entails stripping datetime from list of functions.
"""
for d in (
self.decode_quoted_string,
self.decode_non_decimal,
self.decode_decimal,
):
try:
return d(value)
except ValueError:
pass
if value.casefold() == self.grammar.none_keyword.casefold():
return None
if value.casefold() == self.grammar.true_keyword.casefold():
return True
if value.casefold() == self.grammar.false_keyword.casefold():
return False
return self.decode_unquoted_string(value)
[docs] def decode_unquoted_string(self, value: str) -> str:
"""Returns a Python ``str`` if *value* can be decoded
as an unquoted string, based on this decoder's grammar.
Raises a ValueError otherwise.
Modified from: https://pvl.readthedocs.io/en/stable/_modules/pvl/decoder.html#PVLDecoder.decode_unquoted_string
Modification entails removal of decode_datetime call
"""
for coll in (
("a comment", chain.from_iterable(self.grammar.comments)),
("some whitespace", self.grammar.whitespace),
("a special character", self.grammar.reserved_characters),
):
for item in coll[1]:
if item in value:
raise ValueError(
"Expected a Simple Value, but encountered "
f'{coll[0]} in "{self}": "{item}".'
)
agg_keywords = self.grammar.aggregation_keywords.items()
for kw in chain.from_iterable(agg_keywords):
if kw.casefold() == value.casefold():
raise ValueError(
"Expected a Simple Value, but encountered "
f'an aggregation keyword: "{value}".'
)
for es in self.grammar.end_statements:
if es.casefold() == value.casefold():
raise ValueError(
"Expected a Simple Value, but encountered "
f'an End-Statement: "{value}".'
)
return str(value)