Skip to content

OMM interface overhaul: full-fidelity dicts, file/text loaders, TLE conversion, one parser for Rust and Python - #173

Open
ssmichael1 wants to merge 1 commit into
mainfrom
omm-interface
Open

OMM interface overhaul: full-fidelity dicts, file/text loaders, TLE conversion, one parser for Rust and Python#173
ssmichael1 wants to merge 1 commit into
mainfrom
omm-interface

Conversation

@ssmichael1

Copy link
Copy Markdown
Owner

Follow-up to the OMM interface review. Closes the gaps between the Rust and Python OMM paths and exposes what Rust already parsed.

Python

  • omm_from_url is no longer lossy. It returns every field the source provided: version, originator, COMMENT, CENTER_NAME/REF_FRAME/TIME_SYSTEM/MEAN_ELEMENT_THEORY, GM, mass/areas/coefficients, BTERM/AGOM, and all extras (Space-Track's OBJECT_TYPE, RCS_SIZE, LAUNCH_DATE, TLE_LINE1, …; XML USER_DEFINED parameters). Numbers come back as numbers, EPOCH as RFC 3339.
  • New omm_from_file(path) and omm_from_text(text), JSON or XML detected from content. The tests and the OMM tutorial no longer need xmltodict (dropped from the test extra and docs/requirements.txt).
  • TLE.from_omm(dict) / TLE.to_omm().
  • One parser. sgp4 dict inputs are flattened to JSON and handed to the same serde parser as Rust, replacing ~130 lines of hand-rolled field code. Verified behaviours: quoted numbers, None/"" optionals, sgp4 / utc metadata accepted, any level of an xmltodict tree (omm, body, segment, data node), EPOCH as str/satkit.time/datetime, numpy scalars, and an error that names the expected keys instead of a bare "OMM epoch is required".
  • SGP4-XP sets are refused. EPHEMERIS_TYPE: 4 raises instead of running classic SGP4 silently.
  • OMMDict TypedDict (runtime module satkit/_types.py, re-exported at top level) documents the keys and units; sgp4 is typed TLE | OMMDict | list[TLE | OMMDict]. stubtest passes.
  • omm_from_url releases the GIL during the fetch.

Rust (breaking, for 0.22)

  • OMM.epoch: Instant (was String; epoch_instant() kept as deprecated). No reparse per call, no Instant::INVALID fallback.
  • OMM derives Serialize (absent optionals skipped, EPOCH written as RFC 3339, extras written back).
  • Default removed; OMM::from_mean_elements(epoch, n, e, i, Ω, ω, M) replaces it.
  • OMM::from_tle / OMM::to_tle plus From<&TLE> / From<&OMM> impls; OBJECT_ID ↔ international designator conversion.
  • from_json_value, from_text, from_file, reset_cache; from_json_string accepts a bare object (the from_url string hack is gone).
  • One generic tolerant scalar parser replaces the three de_opt_* and four parse_optional_* helpers.
  • XML: COMMENT lines (header, metadata, data), CREATION_DATE, spacecraftParameters, and userDefinedParameters are read, so Space-Track XML and JSON now yield identical messages. OBJECT_NAME/OBJECT_ID default to UNKNOWN (trimmed dicts).
  • omm::Error is #[non_exhaustive]; InvalidFloat/InvalidInt/InvalidFloatField collapse into InvalidField { field, message }; new UnsupportedEphemerisType, UnexpectedJsonShape, UnrecognizedFormat.
  • Module docs rewritten; leftover "remove this branch if…" comments gone.

Not done: KVN parsing, covariance block, and a Python OMM class (dicts stay the Python representation on purpose).

Tests

  • Space-Track ships TLE_LINE1/2 with each OMM, so both parsers are checked against each other over the corpus (Rust: 200 records, Python: 100) — within 10 m at epoch + 3 h (the TLE epoch's 0.864 ms resolution bounds the difference; worst case seen 2 m).
  • Space-Track XML vs JSON parity (all 2000 records load; first record field-by-field identical).
  • Serialize round-trip, TLE round-trip (to_2line identical), tolerant scalars, rejection cases, cache-reset behaviour, xmltodict shapes, EPOCH variants.
  • cargo test --lib 305 passed, cargo test --doc omm 4 passed, pytest python/test/ 197 passed, stubtest clean, clippy -D warnings clean, notebook cells executed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GTxc7VmUFyqdpobZkg7Rb7

…onversion, one parser for Rust and Python

Python
- omm_from_url returns every field the source provided (metadata, COMMENT,
  Space-Track extras such as OBJECT_TYPE / RCS_SIZE / TLE_LINE1, XML
  USER_DEFINED parameters) instead of 17 keys, with numbers as numbers
- new omm_from_file / omm_from_text (JSON or XML, detected from content);
  the xmltodict workaround in the tests and tutorial is gone
- TLE.from_omm / TLE.to_omm convert between the representations
- sgp4 dict inputs go through the same serde parser as Rust: quoted numbers,
  null / empty optionals, case-insensitive MEAN_ELEMENT_THEORY / TIME_SYSTEM,
  any level of an xmltodict tree, EPOCH as str / time / datetime, and an
  error that names the expected keys
- propagation rejects EPHEMERIS_TYPE 4 (SGP4-XP) instead of silently running
  classic SGP4 on it
- OMMDict TypedDict (runtime module python/satkit/_types.py) in the stubs;
  sgp4 signature documents list[TLE | OMMDict]

Rust
- OMM.epoch is an Instant (was a String; epoch_instant() deprecated)
- OMM derives Serialize (absent optionals skipped, EPOCH as RFC 3339)
- from_mean_elements constructor replaces the invalid Default
- from_tle / to_tle (+ From impls), from_json_value, from_text, from_file,
  reset_cache; from_json_string accepts a bare object
- one generic tolerant scalar parser shared by the JSON and XML paths
- XML: COMMENT lines, CREATION_DATE, spacecraftParameters, and
  userDefinedParameters are read; OBJECT_NAME / OBJECT_ID default to UNKNOWN
- omm::Error is #[non_exhaustive]; InvalidFloat/InvalidInt/InvalidFloatField
  collapse into InvalidField; new UnsupportedEphemerisType,
  UnexpectedJsonShape, UnrecognizedFormat

Tests: Space-Track ships TLE lines with each OMM, so both parsers are now
checked against each other (Rust and Python); XML vs JSON parity on the
Space-Track corpus; serialize round-trip; TLE round-trip; rejection cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTxc7VmUFyqdpobZkg7Rb7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant