Source code for ptr.esa.export

"""ESA export functions."""

from datetime import datetime
from json import dumps
from pathlib import Path

from ..datetime import iso
from ..ptx import read_ptr


[docs]def export_timeline(fname, ptr, subgroup='', source='GENERIC', **kwargs): """Export a PTR observation blocks into segments. CSV and JSON files are natively compatible with the JUICE timeline tool: .. code-block:: text https://juicesoc.esac.esa.int/tm/?trajectory=CREMA_5_0 Parameters ---------- fname: str or pathlib.Path Output filename. Currently, only ``.json`` and ``.csv`` are supported. ptr: str or pathlib.Path PTR text or file name. subgroup: str, optional Subgroup keyword (default: ``<EMPTY>``). source: str, optional Source / working group entry (default: ``GENERIC``). **kwargs: JSON output extra keywords, defaults: - ``crema = 'CREMA_5_0'`` - ``timeline = 'LOCAL'`` - ``creation_date = None`` - ``overwritten = False`` Returns ------- pathlib.Path Output filename. Raises ------ ValueError If the provided filename does not end with ``.json`` or ``.csv``. See Also -------- extract_segments format_csv format_json """ # Parse PTR ptr = read_ptr(ptr) # Extract segments list: [[NAME, START_TIME, STOP_TIME, SUBGROUP, SOURCE], ...] segments = extract_segments(ptr, subgroup=subgroup, source=source) # Export in a output file fname = Path(fname) ext = fname.suffix.lower() if ext == '.csv': content = format_csv(segments) elif ext == '.json': content = format_json(segments, fname.stem, **kwargs) else: raise ValueError('The output file must be a JSON or a CSV file.') # Create parents folder if needed fname.parent.mkdir(parents=True, exist_ok=True) # Save the segments content fname.write_text(content, encoding='utf-8') return fname
[docs]def extract_segments(ptr, subgroup='', source='GENERIC'): """Extract PTR observation blocks as segment windows. Segment format: ``[NAME, START_TIME, STOP_TIME, SUBGROUP, SOURCE]`` Parameters ---------- ptr: PointingRequestMessage Parsed pointing request message. subgroup: str, optional Subgroup keyword (default: ``<EMPTY>``). source: str, optional Source / working group entry (default: ``GENERIC``). Returns ------- list List of segments. Note ---- - The ``NAME`` keyword is extracted from the comment ``OBS_NAME`` in the metadata comment properties if present or set to ``PTR_OBS_BLOCK`` if not present. If a ``OBS_ID`` comment property is present, if will be appended to the ``NAME`` as ``{OBS_NAME}_{OBS_ID}``. - ``START`` and ``STOP`` times are return as ISO format: ``2032-07-08T15:53:52.350Z`` - The ``SUBGROUP`` is optional. - The ``SOURCE`` can be empty. If a PTR block has the ``PRIME`` property in the metadata, ``SOURCE`` uses that value for the given block. See Also -------- export_timeline """ segments = [] for block in ptr: # Assign the default source to the segment source. seg_source = source seg_name = 'PTR_OBS_BLOCK' seg_subgroup = subgroup # Check if the block contains information about the observation if meta := block.metadata: prop = meta.properties if 'OBS_NAME' in prop: seg_subgroup = prop['OBS_NAME'] seg_name = prop['OBS_NAME'] if 'PRIME' in prop: seg_source = prop['PRIME'] if seg_source != 'SOC': seg_name = f"{prop['PRIME']}_PRIME_OBSERVATION" else: seg_name = prop['OBS_NAME'] # Append segments.append([ seg_name, iso(block.start.datetime), iso(block.end.datetime), seg_subgroup, seg_source, ]) return segments
[docs]def format_csv(segments, header='# name, t_start, t_end, subgroup, source'): """Format segments as a CSV string. Parameters ---------- segments: list List of events as: ``[NAME, START_TIME, STOP_TIME, SUBGROUP, SOURCE]`` header: str, optional Optional file header. Returns ------- str Formatted CSV string. Note ---- The delimiter is a comma character (``,``). """ if header: segments = [header.split(', ')] + segments return '\n'.join([','.join(event) for event in segments])
[docs]def format_json(segments, fname, crema='CREMA_5_0', timeline='LOCAL', creation_date=None, overwritten=False): """Format segments as a JSON string. Parameters ---------- segments: list List of events as: ``[NAME, START_TIME, STOP_TIME, SUBGROUP, SOURCE]`` crema: str, optional Top level ``crema`` keyword. timeline: str, optional Top level ``timeline`` keyword. creation_date: str or datetime.datetime, optional File creation datetime in ISO format. If none provided (default), the current datetime will be used. overwritten: bool, optional Segment event ``overwritten`` keyword. Returns ------- str Formatted JSON string. Note ---- The ``SUBGROUP`` field is used to store the name that will be displayed in the JUICE timeline tool. If none is provided, the ``NAME`` field will be used instead. """ return dumps({ 'creationDate': iso(creation_date if creation_date else datetime.now()), 'name': fname, 'segments': [ { 'start': start, 'end': stop, 'segment_definition': name, 'name': subgroup if subgroup else name, 'overwritten': overwritten, 'timeline': timeline, 'source': source, 'resources': [], } for name, start, stop, subgroup, source in segments ], 'segmentGroups': [], 'trajectory': crema, 'localStoragePk': '', })