Source code for nav.dataset.dataset_pds3_galileo_ssi

from pathlib import Path
from typing import Any, cast

from filecache import FCPath, FileCache

from nav.config import Config
from nav.support.misc import safe_lstrip_zero

from .dataset import ImageFile
from .dataset_pds3 import DataSetPDS3


[docs] class DataSetPDS3GalileoSSI(DataSetPDS3): """Implements dataset access for PDS3 Galileo SSI (Solid State Imager) data. This class provides specialized functionality for accessing and parsing Galileo SSI image data stored in PDS3 format. """ _MIN_VOL = 2 _MAX_VOL = 23 _ALL_VOLUME_NAMES = tuple(f'GO_{x:04d}' for x in range(_MIN_VOL, _MAX_VOL + 1)) _INDEX_COLUMNS = ('FILE_SPECIFICATION_NAME',) _VOLUMES_DIR_NAME = 'volumes' # Methods inherited from DataSetPDS3 @staticmethod def _get_label_filespec_from_index(row: dict[str, Any]) -> str: """Extracts the label file specification from a row from an index table. Parameters: row: Dictionary containing PDS3 index table row data. Returns: The file specification string from the row. """ filespec = cast(str, row['FILE_SPECIFICATION_NAME']) # Intentionally uppercase only if not filespec.endswith('.LBL'): raise ValueError(f'Bad Primary File Spec "{filespec}" - expected ".LBL"') # Intentionally uppercase only return filespec @staticmethod def _get_image_filespec_from_label_filespec(label_filespec: str) -> str: """Extracts the image file specification from a label file specification. Parameters: label_filespec: The label file specification string to parse. Returns: The image file specification string. """ # Intentionally uppercase only return label_filespec.replace('.LBL', '.IMG') @staticmethod def _get_img_name_from_label_filespec(filespec: str) -> str | None: """Extract the image name (with no extension) from a file specification. Parameters: filespec: The file specification string to parse. Raises: ValueError: If the file specification format is invalid. """ parts = filespec.split('/') if parts[0].upper().startswith('GO_'): parts = parts[1:] if not (2 <= len(parts) <= 4): raise ValueError( f'Bad Primary File Spec "{filespec}" - expected 2 to 4 directory levels' ) if parts[0].upper() == 'REDO': parts = parts[1:] if parts[0].upper() in ( 'RAW_CAL', 'VENUS', 'EARTH', 'MOON', 'GASPRA', 'IDA', 'SL9', 'EMCONJ', 'GOPEX', ): img_name = parts[1] elif parts[0].upper() in ( 'C3', 'C9', 'C10', 'C20', 'C21', 'C22', 'C30', 'E4', 'E6', 'E11', 'E12', 'E14', 'E15', 'E17', 'E18', 'E19', 'E26', 'G1', 'G2', 'G7', 'G8', 'G28', 'G29', 'I24', 'I25', 'I27', 'I31', 'I32', 'I33', 'J0', ): img_name = parts[2] else: raise ValueError(f'Bad Primary File Spec "{filespec}" - bad target directory') # Intentionally uppercase only if not img_name.endswith('.LBL'): return None img_name = img_name.rsplit('.', maxsplit=1)[0] return img_name @staticmethod def _img_name_valid(img_name: str) -> bool: """True if an image name is valid for this instrument. Parameters: img_name: The name of the image. Returns: True if the image name is valid for this instrument, False otherwise. """ img_name = img_name.upper() # Cdddddddddd[RS] if len(img_name) != 12 or img_name[0] != 'C' or img_name[11] not in 'RS': return False try: _ = int(safe_lstrip_zero(img_name[1:11])) except ValueError: return False return True @staticmethod def _extract_img_number(img_name: str) -> int: """Extract the image number from an image name. Parameters: img_name: The name of the image. Can be just the image name, the image filename, or the full file spec. Returns: The image number. Raises: ValueError: If the image name format is invalid. """ if not DataSetPDS3GalileoSSI._img_name_valid(img_name): raise ValueError(f'Invalid image name "{img_name}"') return int(safe_lstrip_zero(img_name[1:11])) @staticmethod def _volset_and_volume(volume: str) -> str: """Get the volset and volume name. Parameters: volume: The volume name. Returns: The volset and volume name. """ return f'GO_0xxx/{volume}' @staticmethod def _volume_to_index(volume: str) -> str: """Get the index file name for a volume. Parameters: volume: The volume name. Returns: The index file name. """ # Intentionally lowercase only return f'GO_0xxx/{volume}/{volume}_index.lbl' @staticmethod def _results_path_stub(volume: str, filespec: str) -> str: """Get the results path stub for an image filespec. Parameters: volume: The volume name. filespec: The filespec of the image. Returns: The results path stub. This is {volume}/{filespec} without the .IMG extension. """ return str(Path(f'{volume}/{filespec}').with_suffix('')) # Public methods def __init__( self, pds3_holdings_root: str | Path | FCPath | None = None, *, index_filecache: FileCache | None = None, pds3_holdings_filecache: FileCache | None = None, config: Config | None = None, ) -> None: """Initializes a Galileo SSI dataset handler. Parameters: pds3_holdings_root: Path to PDS3 holdings directory. If None, uses PDS3_HOLDINGS_DIR environment variable. May be a URL accepted by FCPath. index_filecache: FileCache object to use for index files. If None, creates a new one. pds3_holdings_filecache: FileCache object to use for PDS3 holdings files. If None, creates a new one. config: Configuration object to use. If None, uses DEFAULT_CONFIG. """ super().__init__( pds3_holdings_root=pds3_holdings_root, index_filecache=index_filecache, pds3_holdings_filecache=pds3_holdings_filecache, config=config, )
[docs] def pds4_bundle_template_dir(self) -> str: """Returns absolute path to template directory for PDS4 bundle generation.""" template_dir = None gossi_config = self.config.pds4.get('gossi', {}) if 'template_dir' in gossi_config: template_dir = str(gossi_config['template_dir']) if template_dir is None: template_dir = 'galileo_ssi_1.0' if Path(template_dir).is_absolute(): return template_dir pds4_templates_dir = Path(__file__).resolve().parent.parent.parent / 'pds4' / 'templates' return str(pds4_templates_dir / template_dir)
[docs] def pds4_bundle_name(self) -> str: """Returns bundle name for PDS4 bundle generation.""" gossi_config = self.config.pds4.get('gossi', {}) if 'bundle_name' in gossi_config: return str(gossi_config['bundle_name']) return 'galileo_ssi_backplanes_rsfrench2027'
[docs] @staticmethod def pds4_bundle_path_for_image(image_name: str) -> str: """Maps image name to bundle directory path.""" raise NotImplementedError
[docs] def pds4_path_stub(self, image_file: ImageFile) -> str: """Returns PDS4 path stub for bundle directory structure.""" raise NotImplementedError
[docs] def pds4_image_name_to_browse_lid(self, image_name: str) -> str: """Returns the browse LID for the given image name. Parameters: image_name: The image name to convert to a browse LID. Returns: The browse LID. """ raise NotImplementedError
[docs] def pds4_image_name_to_browse_lidvid(self, image_name: str) -> str: """Returns the browse LIDVID for the given image name. Parameters: image_name: The image name to convert to a browse LIDVID. Returns: The browse LIDVID. """ raise NotImplementedError
[docs] def pds4_image_name_to_data_lid(self, image_name: str) -> str: """Returns the data LID for the given image name. Parameters: image_name: The image name to convert to a data LID. Returns: The data LID. """ raise NotImplementedError
[docs] def pds4_image_name_to_data_lidvid(self, image_name: str) -> str: """Returns the data LIDVID for the given image name. Parameters: image_name: The image name to convert to a data LIDVID. Returns: The data LIDVID. """ raise NotImplementedError
[docs] def pds4_template_variables( self, *, image_file: ImageFile, nav_metadata: dict[str, Any], backplane_metadata: dict[str, Any], ) -> dict[str, Any]: """Returns template variables for PDS4 label generation.""" raise NotImplementedError