Skip to content

thiserror migration Phase 2: frames + itrfcoord + orbitprop#84

Merged
ssmichael1 merged 3 commits into
mainfrom
feat/thiserror-frames-orbitprop
Apr 26, 2026
Merged

thiserror migration Phase 2: frames + itrfcoord + orbitprop#84
ssmichael1 merged 3 commits into
mainfrom
feat/thiserror-frames-orbitprop

Conversation

@ssmichael1
Copy link
Copy Markdown
Owner

Summary

Phase 2 of the anyhowthiserror migration tracked in #81. Three modules, three commits, branched from main so it can merge independently of #83 (Phase 1: tle + omm).

Refs #81. (Not closing — Phase 3 covers internal modules in a follow-up.)

What changed

frames::Error (src/frames.rs):

  • InvalidFrame

Side change: mod frames promoted to pub mod frames so consumers can name satkit::frames::Error. The Frame re-export at the crate root is unchanged.

itrfcoord::Error (src/itrfcoord.rs):

  • InvalidSliceLength { got: usize } — used by both from_slice and TryFrom<&[f64]>

orbitprop::Error (src/orbitprop/error.rs):

  • InvalidStateColumns { c }, NoDenseOutputInSolution
  • OdeError(ode::OdeError) — manual From impl (numeris's OdeError doesn't impl std::error::Error)
  • RODAS4NoSTM, GaussJackson8NoSTM
  • PrecomputedOutOfRange { time, begin, end }
  • Precompute(String) — stringified pending Phase 3 (jplephem)
  • UnsupportedUncertaintyFrame { frame: Frame }
  • InvalidGravityOrder { order, degree }

The pre-existing propagator::PropagationError enum was folded into the unified orbitprop::Error (no external pub use was found).

Judgment calls worth a look

  1. mod framespub mod frames. Small public API expansion, needed so downstream consumers can name frames::Error. The Frame re-export at the crate root keeps existing imports working.
  2. propagator::PropagationError folded into orbitprop::Error. It was module-local with no external users; unification matches the issue's "module error" pattern.
  3. OdeError uses manual From impl rather than #[from] because numeris::ode::OdeError only impls Display, not std::error::Error. Forward-compatible — will keep working when numeris upgrades.
  4. Precompute(String) stringifies jplephem errors. Becomes typed #[from] jplephem::Error in Phase 3.
  5. Test modules opt back into anyhow::Result locally via use anyhow::Result;. Same pattern as Phase 1 — tests touch many ? boundaries (Instant::from_datetime, str::parse, io::Error) that aren't worth lifting into the public Error enum.
  6. Python binding pysatstate.propagate switched .map(Self) to Ok(Self(...?)) so ? converts orbitprop::Erroranyhow::Error via the blanket impl. Only binding that needed touching.

Test plan

  • cargo build — clean
  • cargo build --no-default-features — clean
  • cargo test --release — 159 lib + 41 doc tests pass
  • cargo check --manifest-path python/Cargo.toml — clean

🤖 Generated with Claude Code

ssmichael1 and others added 3 commits April 26, 2026 15:29
Introduces frames::Error and frames::Result for the frames module,
replacing the anyhow::Error returned by Frame's FromStr impl. The
single bail!("Invalid Frame") site becomes the explicit
Error::InvalidFrame variant.

The frames module is promoted from a private mod to pub mod so
downstream consumers can name and match on the Error type directly
(satkit::frames::Error::InvalidFrame). Frame itself is still
re-exported at the crate root, so existing callers see no change.

Refs #81 (Phase 2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… enum

Introduces itrfcoord::Error and itrfcoord::Result for the itrfcoord
module, replacing anyhow::Error used by ITRFCoord::from_slice and the
TryFrom<&[f64]> for ITRFCoord impl. Both bail!("Input slice must have
3 elements...") sites collapse onto a single Error::InvalidSliceLength
{ got } variant, which preserves the actual length in the message.

Refs #81 (Phase 2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… enum

Introduces orbitprop::Error and orbitprop::Result, exposed from
src/orbitprop/error.rs and re-exported via src/orbitprop/mod.rs.
Replaces anyhow::Result throughout satstate.rs, propagator.rs,
settings.rs, and precomputed.rs.

The previously private propagator::PropagationError enum is folded
into the unified module-level Error: its variants (InvalidStateColumns,
NoDenseOutputInSolution, OdeError, RODAS4NoSTM, GaussJackson8NoSTM)
become Error variants directly. New variants cover the bail! sites in
the other files:

  - Error::PrecomputedOutOfRange { time, begin, end }
    -- Precomputed::interp out-of-range
  - Error::Precompute(String)
    -- wraps still-anyhow errors from jplephem when building the
       precomputed table; will be retyped against jplephem's Error
       in Phase 3
  - Error::UnsupportedUncertaintyFrame { frame }
    -- SatState::set_pos_uncertainty / set_vel_uncertainty rejection
       of non-orbital frames
  - Error::InvalidGravityOrder { order, degree }
    -- PropSettings::set_gravity validation

`numeris::ode::OdeError` does not implement `std::error::Error`, so
its conversion is a manual `From` impl rather than `#[from]`.

Test modules use `use anyhow::Result;` locally so the existing
`?`-conversions from `Instant::from_datetime`, `parse::<f64>()`, etc.
keep working without polluting orbitprop::Error with non-orbitprop
variants.

The Python pysatstate.propagate() binding switches `.map(Self)` to
`Ok(Self(...?))` so it can use anyhow's blanket `From<E: StdError>`
to convert orbitprop::Error into anyhow::Error and then PyErr.

Refs #81 (Phase 2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ssmichael1 ssmichael1 marked this pull request as ready for review April 26, 2026 22:11
@ssmichael1 ssmichael1 merged commit d088770 into main Apr 26, 2026
4 checks passed
@ssmichael1 ssmichael1 deleted the feat/thiserror-frames-orbitprop branch April 26, 2026 22:20
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