orbit-formats 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. orbit_formats-0.1.0/.gitattributes +5 -0
  2. orbit_formats-0.1.0/.github/CODEOWNERS +2 -0
  3. orbit_formats-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +59 -0
  4. orbit_formats-0.1.0/.github/ISSUE_TEMPLATE/chore.yml +25 -0
  5. orbit_formats-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. orbit_formats-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +41 -0
  7. orbit_formats-0.1.0/.github/pull_request_template.md +34 -0
  8. orbit_formats-0.1.0/.github/workflows/ci.yml +126 -0
  9. orbit_formats-0.1.0/.github/workflows/docs.yml +57 -0
  10. orbit_formats-0.1.0/.github/workflows/release.yml +74 -0
  11. orbit_formats-0.1.0/.gitignore +40 -0
  12. orbit_formats-0.1.0/.python-version +1 -0
  13. orbit_formats-0.1.0/CHANGELOG.md +47 -0
  14. orbit_formats-0.1.0/CITATION.cff +26 -0
  15. orbit_formats-0.1.0/CONTRIBUTING.md +57 -0
  16. orbit_formats-0.1.0/LICENSE +21 -0
  17. orbit_formats-0.1.0/PKG-INFO +140 -0
  18. orbit_formats-0.1.0/README.md +104 -0
  19. orbit_formats-0.1.0/docs/api.md +3 -0
  20. orbit_formats-0.1.0/docs/canonical-representation.md +112 -0
  21. orbit_formats-0.1.0/docs/cli.md +40 -0
  22. orbit_formats-0.1.0/docs/conversion-matrix.md +63 -0
  23. orbit_formats-0.1.0/docs/formats.md +81 -0
  24. orbit_formats-0.1.0/docs/getting-started.md +114 -0
  25. orbit_formats-0.1.0/docs/index.md +58 -0
  26. orbit_formats-0.1.0/docs/lossy-conversions.md +72 -0
  27. orbit_formats-0.1.0/mkdocs.yml +81 -0
  28. orbit_formats-0.1.0/pyproject.toml +134 -0
  29. orbit_formats-0.1.0/src/orbit_formats/__init__.py +88 -0
  30. orbit_formats-0.1.0/src/orbit_formats/adapters/__init__.py +11 -0
  31. orbit_formats-0.1.0/src/orbit_formats/adapters/base.py +38 -0
  32. orbit_formats-0.1.0/src/orbit_formats/api.py +137 -0
  33. orbit_formats-0.1.0/src/orbit_formats/canonical/__init__.py +33 -0
  34. orbit_formats-0.1.0/src/orbit_formats/canonical/attitude.py +18 -0
  35. orbit_formats-0.1.0/src/orbit_formats/canonical/base.py +178 -0
  36. orbit_formats-0.1.0/src/orbit_formats/canonical/conjunction.py +18 -0
  37. orbit_formats-0.1.0/src/orbit_formats/canonical/elements.py +124 -0
  38. orbit_formats-0.1.0/src/orbit_formats/canonical/ephemeris.py +108 -0
  39. orbit_formats-0.1.0/src/orbit_formats/canonical/fidelity.py +38 -0
  40. orbit_formats-0.1.0/src/orbit_formats/canonical/metadata.py +61 -0
  41. orbit_formats-0.1.0/src/orbit_formats/canonical/state.py +89 -0
  42. orbit_formats-0.1.0/src/orbit_formats/canonical/tracking.py +18 -0
  43. orbit_formats-0.1.0/src/orbit_formats/cli.py +107 -0
  44. orbit_formats-0.1.0/src/orbit_formats/convert/__init__.py +46 -0
  45. orbit_formats-0.1.0/src/orbit_formats/convert/elements.py +197 -0
  46. orbit_formats-0.1.0/src/orbit_formats/convert/graph.py +61 -0
  47. orbit_formats-0.1.0/src/orbit_formats/convert/time.py +78 -0
  48. orbit_formats-0.1.0/src/orbit_formats/detect.py +95 -0
  49. orbit_formats-0.1.0/src/orbit_formats/errors.py +111 -0
  50. orbit_formats-0.1.0/src/orbit_formats/formats.py +271 -0
  51. orbit_formats-0.1.0/src/orbit_formats/py.typed +0 -0
  52. orbit_formats-0.1.0/src/orbit_formats/readers/__init__.py +12 -0
  53. orbit_formats-0.1.0/src/orbit_formats/readers/ccsds.py +598 -0
  54. orbit_formats-0.1.0/src/orbit_formats/readers/gmat_report.py +400 -0
  55. orbit_formats-0.1.0/src/orbit_formats/readers/tle.py +212 -0
  56. orbit_formats-0.1.0/src/orbit_formats/registry.py +80 -0
  57. orbit_formats-0.1.0/src/orbit_formats/source.py +93 -0
  58. orbit_formats-0.1.0/src/orbit_formats/units.py +35 -0
  59. orbit_formats-0.1.0/src/orbit_formats/warnings.py +168 -0
  60. orbit_formats-0.1.0/src/orbit_formats/writers/__init__.py +12 -0
  61. orbit_formats-0.1.0/src/orbit_formats/writers/oem.py +217 -0
  62. orbit_formats-0.1.0/tests/conftest.py +44 -0
  63. orbit_formats-0.1.0/tests/data/oem/golden_roundtrip.oem +43 -0
  64. orbit_formats-0.1.0/tests/test_api.py +210 -0
  65. orbit_formats-0.1.0/tests/test_ccsds_oem.py +492 -0
  66. orbit_formats-0.1.0/tests/test_ccsds_oem_oracle.py +82 -0
  67. orbit_formats-0.1.0/tests/test_cli.py +185 -0
  68. orbit_formats-0.1.0/tests/test_convert_elements.py +164 -0
  69. orbit_formats-0.1.0/tests/test_convert_graph.py +126 -0
  70. orbit_formats-0.1.0/tests/test_convert_time.py +87 -0
  71. orbit_formats-0.1.0/tests/test_detect.py +131 -0
  72. orbit_formats-0.1.0/tests/test_elements.py +98 -0
  73. orbit_formats-0.1.0/tests/test_ephemeris.py +132 -0
  74. orbit_formats-0.1.0/tests/test_errors.py +40 -0
  75. orbit_formats-0.1.0/tests/test_fidelity_adapter.py +88 -0
  76. orbit_formats-0.1.0/tests/test_formats.py +72 -0
  77. orbit_formats-0.1.0/tests/test_future_stubs.py +13 -0
  78. orbit_formats-0.1.0/tests/test_gmat_report.py +387 -0
  79. orbit_formats-0.1.0/tests/test_metadata.py +58 -0
  80. orbit_formats-0.1.0/tests/test_oem_writer.py +217 -0
  81. orbit_formats-0.1.0/tests/test_package.py +8 -0
  82. orbit_formats-0.1.0/tests/test_source.py +74 -0
  83. orbit_formats-0.1.0/tests/test_state.py +88 -0
  84. orbit_formats-0.1.0/tests/test_tle.py +157 -0
  85. orbit_formats-0.1.0/tests/test_warnings.py +239 -0
  86. orbit_formats-0.1.0/uv.lock +1705 -0
@@ -0,0 +1,5 @@
1
+ # Golden / reference fixtures under tests/data are compared byte-for-byte by the
2
+ # round-trip tests. Git's line-ending normalisation (autocrlf on Windows checks out LF as
3
+ # CRLF) would otherwise rewrite them and break those byte-exact assertions, so treat the
4
+ # fixtures as binary — checked out verbatim, identical on every platform.
5
+ tests/data/** -text
@@ -0,0 +1,2 @@
1
+ # Default reviewer for everything in this repo.
2
+ * @djankov
@@ -0,0 +1,59 @@
1
+ name: Bug
2
+ description: Report a defect in orbit-formats.
3
+ title: "<short summary>"
4
+ labels: ["type:bug"]
5
+ body:
6
+ - type: textarea
7
+ id: what_happened
8
+ attributes:
9
+ label: What happened
10
+ description: Observed behavior. Include error messages and tracebacks verbatim.
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: what_expected
15
+ attributes:
16
+ label: What you expected
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: repro
21
+ attributes:
22
+ label: Minimal reproduction
23
+ description: >-
24
+ Smallest snippet that triggers the bug — the Python (or CLI) call and, if a
25
+ file fails to parse or convert, the smallest sample file that reproduces it.
26
+ render: python
27
+ validations:
28
+ required: true
29
+ - type: input
30
+ id: orbit_formats_version
31
+ attributes:
32
+ label: orbit-formats version
33
+ placeholder: "e.g. 0.1.0, or git sha"
34
+ validations:
35
+ required: true
36
+ - type: input
37
+ id: python_version
38
+ attributes:
39
+ label: Python version
40
+ placeholder: "e.g. 3.12.3"
41
+ validations:
42
+ required: true
43
+ - type: dropdown
44
+ id: os
45
+ attributes:
46
+ label: Operating system
47
+ options:
48
+ - Linux
49
+ - Windows
50
+ - macOS
51
+ - Other
52
+ validations:
53
+ required: true
54
+ - type: textarea
55
+ id: logs
56
+ attributes:
57
+ label: Logs
58
+ description: Relevant output — tracebacks, warnings, pytest output.
59
+ render: shell
@@ -0,0 +1,25 @@
1
+ name: Chore
2
+ description: Tooling, infra, hygiene, or other non-feature work.
3
+ title: "<short summary>"
4
+ labels: ["type:chore"]
5
+ body:
6
+ - type: textarea
7
+ id: what
8
+ attributes:
9
+ label: What
10
+ description: What needs to happen.
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: why
15
+ attributes:
16
+ label: Why
17
+ description: Why now. What's blocked or painful without it.
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: done
22
+ attributes:
23
+ label: Definition of done
24
+ value: |
25
+ - [ ]
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question or discussion
4
+ url: https://github.com/orgs/astro-tools/discussions
5
+ about: Open a discussion for usage questions, ideas, or general chat.
@@ -0,0 +1,41 @@
1
+ name: Feature
2
+ description: Propose a new capability or a non-trivial change.
3
+ title: "<short summary>"
4
+ labels: ["type:feature"]
5
+ body:
6
+ - type: textarea
7
+ id: summary
8
+ attributes:
9
+ label: Summary
10
+ description: One or two sentences describing what this feature is.
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: motivation
15
+ attributes:
16
+ label: Motivation
17
+ description: Why this matters. What can't users do today that they should be able to do?
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: acceptance
22
+ attributes:
23
+ label: Acceptance criteria
24
+ description: >-
25
+ Concrete, testable checkboxes. An outside reviewer should be able to read these
26
+ and tell whether the feature is done.
27
+ value: |
28
+ - [ ]
29
+ - [ ]
30
+ validations:
31
+ required: true
32
+ - type: textarea
33
+ id: out_of_scope
34
+ attributes:
35
+ label: Out of scope / non-goals
36
+ description: What this issue deliberately does not cover. Helps keep scope honest.
37
+ - type: textarea
38
+ id: notes
39
+ attributes:
40
+ label: Notes
41
+ description: Design notes, links to charter sections, references to prior art, open questions.
@@ -0,0 +1,34 @@
1
+ <!--
2
+ Thanks for contributing to orbit-formats. Keep PRs small and scoped to one issue.
3
+ -->
4
+
5
+ ## Summary
6
+
7
+ <!-- One or two sentences: what this PR changes and why. -->
8
+
9
+ Closes #
10
+
11
+ ## Changes
12
+
13
+ <!-- Short bullet list of the substantive changes. Omit trivia (formatting, imports). -->
14
+
15
+ -
16
+
17
+ ## Tested with
18
+
19
+ <!-- Tick what you ran locally. CI will re-run on Ubuntu, Windows, and macOS. -->
20
+
21
+ - [ ] `pytest`
22
+ - [ ] `ruff check`
23
+ - [ ] `ruff format --check`
24
+ - [ ] `mypy`
25
+
26
+ ## Breaking changes
27
+
28
+ <!-- "None" if none. Otherwise: what breaks, who is affected, migration notes. -->
29
+
30
+ None.
31
+
32
+ ## Notes for reviewers
33
+
34
+ <!-- Optional. Things to look at first, known rough edges, questions for the reviewer. -->
@@ -0,0 +1,126 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
11
+
12
+ jobs:
13
+ test:
14
+ name: test (${{ matrix.os }}, py${{ matrix.python-version }})
15
+ runs-on: ${{ matrix.os }}
16
+ timeout-minutes: 20
17
+ strategy:
18
+ fail-fast: false
19
+ # 3 OSes × 3 Python minors = 9 cells. orbit-formats is pure Python with no
20
+ # native or GMAT dependency, so the matrix is the platform/interpreter spread,
21
+ # nothing more.
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest, macos-latest]
24
+ python-version: ['3.10', '3.11', '3.12']
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - name: Set up Python ${{ matrix.python-version }}
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ - name: Install uv
34
+ uses: astral-sh/setup-uv@v4
35
+ with:
36
+ enable-cache: true
37
+ cache-dependency-glob: uv.lock
38
+
39
+ - name: Install project
40
+ run: uv sync --all-groups
41
+
42
+ - name: Run pytest
43
+ run: uv run pytest --cov --cov-report=term-missing
44
+
45
+ lint:
46
+ name: lint
47
+ runs-on: ubuntu-latest
48
+ timeout-minutes: 5
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ - uses: actions/setup-python@v5
52
+ with:
53
+ python-version: '3.12'
54
+ - uses: astral-sh/setup-uv@v4
55
+ with:
56
+ enable-cache: true
57
+ cache-dependency-glob: uv.lock
58
+ - run: uv sync --all-groups
59
+ - run: uv run ruff check
60
+ - run: uv run ruff format --check
61
+
62
+ typecheck:
63
+ name: typecheck
64
+ runs-on: ubuntu-latest
65
+ timeout-minutes: 10
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+ - uses: actions/setup-python@v5
69
+ with:
70
+ python-version: '3.12'
71
+ - uses: astral-sh/setup-uv@v4
72
+ with:
73
+ enable-cache: true
74
+ cache-dependency-glob: uv.lock
75
+ - run: uv sync --all-groups
76
+ - run: uv run mypy
77
+
78
+ # Smoke-check that `pip install orbit-formats` (no extras, no dev group) imports
79
+ # cleanly. Catches an extras-only dependency leaking into the default install path.
80
+ minimal-install:
81
+ name: minimal install smoke
82
+ runs-on: ubuntu-latest
83
+ timeout-minutes: 5
84
+ steps:
85
+ - uses: actions/checkout@v4
86
+ - uses: actions/setup-python@v5
87
+ with:
88
+ python-version: '3.12'
89
+ - run: pip install .
90
+ - run: python -c "import orbit_formats"
91
+
92
+ # Cross-validate the OEM writer against the ccsds-ndm oracle. ccsds-ndm is GPL-3.0, so
93
+ # it is never a runtime, extra, or dev dependency, never in uv.lock, and never shipped:
94
+ # it is installed transiently here with `uv run --with` and used only by this job's
95
+ # tests (which `importorskip` it, so they skip everywhere else). This keeps the whole
96
+ # distributed/locked project GPL-free while still validating against a reference impl.
97
+ oracle:
98
+ name: oracle cross-validation (ccsds-ndm)
99
+ runs-on: ubuntu-latest
100
+ timeout-minutes: 10
101
+ steps:
102
+ - uses: actions/checkout@v4
103
+ - uses: actions/setup-python@v5
104
+ with:
105
+ python-version: '3.12'
106
+ - uses: astral-sh/setup-uv@v4
107
+ with:
108
+ enable-cache: true
109
+ cache-dependency-glob: uv.lock
110
+ - run: uv sync --all-groups
111
+ - run: uv run --with ccsds-ndm pytest tests/test_ccsds_oem_oracle.py -v
112
+
113
+ # Validate CITATION.cff against the Citation File Format v1.2.0 schema. cffconvert
114
+ # is installed standalone because it is a CI-only schema check, not part of the dev
115
+ # or runtime dependency graph.
116
+ citation:
117
+ name: citation file (cffconvert)
118
+ runs-on: ubuntu-latest
119
+ timeout-minutes: 5
120
+ steps:
121
+ - uses: actions/checkout@v4
122
+ - uses: actions/setup-python@v5
123
+ with:
124
+ python-version: '3.12'
125
+ - run: pip install cffconvert==2.0.0
126
+ - run: cffconvert --validate -i CITATION.cff
@@ -0,0 +1,57 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ['v*']
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: docs-${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
13
+
14
+ jobs:
15
+ build:
16
+ name: build
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 5
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: '3.12'
24
+ - uses: astral-sh/setup-uv@v4
25
+ with:
26
+ enable-cache: true
27
+ cache-dependency-glob: uv.lock
28
+ - run: uv sync --all-groups
29
+ - run: uv run mkdocs build --strict
30
+
31
+ deploy:
32
+ name: deploy
33
+ needs: build
34
+ if: |
35
+ (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
36
+ github.event_name == 'workflow_dispatch'
37
+ runs-on: ubuntu-latest
38
+ timeout-minutes: 5
39
+ permissions:
40
+ contents: write
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ with:
44
+ fetch-depth: 0
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: '3.12'
48
+ - uses: astral-sh/setup-uv@v4
49
+ with:
50
+ enable-cache: true
51
+ cache-dependency-glob: uv.lock
52
+ - run: uv sync --all-groups
53
+ - name: Configure git identity
54
+ run: |
55
+ git config user.name "github-actions[bot]"
56
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
57
+ - run: uv run mkdocs gh-deploy --force --no-history
@@ -0,0 +1,74 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ name: build sdist + wheel
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 5
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: '3.12'
24
+ - uses: astral-sh/setup-uv@v4
25
+ with:
26
+ enable-cache: true
27
+ cache-dependency-glob: uv.lock
28
+ - run: uv build
29
+ - uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+ if-no-files-found: error
34
+
35
+ publish-pypi:
36
+ name: publish to PyPI
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ timeout-minutes: 10
40
+ environment:
41
+ name: pypi
42
+ url: https://pypi.org/p/orbit-formats
43
+ permissions:
44
+ id-token: write
45
+ steps:
46
+ - uses: actions/download-artifact@v4
47
+ with:
48
+ name: dist
49
+ path: dist/
50
+ - uses: pypa/gh-action-pypi-publish@release/v1
51
+ with:
52
+ skip-existing: true
53
+
54
+ github-release:
55
+ name: github release
56
+ needs: publish-pypi
57
+ runs-on: ubuntu-latest
58
+ timeout-minutes: 5
59
+ permissions:
60
+ contents: write
61
+ steps:
62
+ - uses: actions/download-artifact@v4
63
+ with:
64
+ name: dist
65
+ path: dist/
66
+ - name: Create GitHub Release
67
+ env:
68
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69
+ run: |
70
+ gh release create "${GITHUB_REF_NAME}" \
71
+ --repo "${GITHUB_REPOSITORY}" \
72
+ --title "${GITHUB_REF_NAME}" \
73
+ --generate-notes \
74
+ dist/*
@@ -0,0 +1,40 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg
7
+ *.egg-info/
8
+ .eggs/
9
+ build/
10
+ dist/
11
+ wheels/
12
+ *.whl
13
+
14
+ # Environments
15
+ .venv/
16
+ venv/
17
+ env/
18
+ .env
19
+
20
+ # uv
21
+ .uv-cache/
22
+
23
+ # Tooling caches
24
+ .pytest_cache/
25
+ .mypy_cache/
26
+ .ruff_cache/
27
+ .coverage
28
+ .coverage.*
29
+ coverage.xml
30
+ htmlcov/
31
+
32
+ # Docs build
33
+ site/
34
+ .cache/
35
+
36
+ # IDE / editor
37
+ .vscode/
38
+ .idea/
39
+ *.swp
40
+ .DS_Store
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to orbit-formats are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-05-30
11
+
12
+ First release. orbit-formats reads TLE, CCSDS OEM (KVN), and GMAT report files into a
13
+ single canonical representation, writes CCSDS OEM, and round-trips OEM losslessly —
14
+ emitting an explicit, structured warning whenever a conversion cannot preserve
15
+ information, never a silent drop.
16
+
17
+ ### Added
18
+
19
+ - Canonical representation: a federated, typed dataclass family — `StateVector`,
20
+ `Ephemeris`, and `MeanElementSet` — unified by a shared `Metadata` spine (reference
21
+ frame, time scale, central body, object id, units, provenance). State-series types
22
+ project to a gmat-run-identical DataFrame (`Epoch, X, Y, Z, VX, VY, VZ`, with the spine
23
+ on `DataFrame.attrs`) that downstream consumers can adopt without reshaping.
24
+ - Two-layer model: a faithful per-format fidelity layer beneath the canonical metamodel,
25
+ linked by an optional `source_native` handle, so a same-format round-trip stays
26
+ byte-identical (with `retain_source=True`) or content-lossless.
27
+ - Readers: TLE / 3LE (sgp4-backed mean elements, TEME / UTC), CCSDS OEM (in-house KVN
28
+ parser — multi-segment, with covariance and acceleration preserved on the fidelity
29
+ model), and GMAT report (whitespace-aligned tables into an ephemeris or state).
30
+ - Writer: CCSDS OEM (KVN), with byte-identical, content-lossless, and synthesised paths.
31
+ - Public API — `read`, `write`, `convert`, and `detect_format` — with
32
+ content-signature-first format auto-detection and an explicit `format=` override.
33
+ - Conversion graph: Cartesian ↔ Keplerian elements and time-scale conversion across UTC /
34
+ TAI / TT / TDB / GPS / UT1; conversions route through each format's preferred canonical
35
+ form.
36
+ - Lossy-conversion framework: structured, catchable warnings (`DroppedFieldWarning`,
37
+ `PrecisionLossWarning`, `ModelApproximationWarning`, `MissingFieldWarning`) that name
38
+ exactly what a conversion drops.
39
+ - Frame-rotation boundary: reference frames are tagged and preserved; a conversion that
40
+ would require rotating between distinct frames is refused rather than approximated.
41
+ - `orbit-formats convert` command-line interface for one-shot file-to-file conversion.
42
+ - Documentation site — the canonical-representation reference, a per-format reference, the
43
+ lossy-conversion semantics, and the conversion-capability matrix — and a typed
44
+ (`py.typed`), MIT-licensed package published to PyPI.
45
+
46
+ [Unreleased]: https://github.com/astro-tools/orbit-formats/compare/v0.1.0...HEAD
47
+ [0.1.0]: https://github.com/astro-tools/orbit-formats/releases/tag/v0.1.0
@@ -0,0 +1,26 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use orbit-formats in academic work, please cite it using the metadata below."
3
+ title: orbit-formats
4
+ abstract: >-
5
+ orbit-formats is a permissively-licensed Python library for reading, writing, and
6
+ losslessly converting between orbital state-vector and ephemeris file formats — TLE,
7
+ the CCSDS Navigation Data Message family, SP3, SPICE SPK, STK ephemeris, and GMAT
8
+ report. It reads each format into a single canonical in-memory representation and
9
+ emits an explicit, structured warning whenever a conversion cannot preserve
10
+ information.
11
+ type: software
12
+ authors:
13
+ - given-names: Dimitrije
14
+ family-names: Jankovic
15
+ version: 0.1.0
16
+ date-released: "2026-05-30"
17
+ license: MIT
18
+ repository-code: "https://github.com/astro-tools/orbit-formats"
19
+ url: "https://github.com/astro-tools/orbit-formats"
20
+ keywords:
21
+ - astrodynamics
22
+ - orbital-mechanics
23
+ - ephemeris
24
+ - ccsds
25
+ - tle
26
+ - space
@@ -0,0 +1,57 @@
1
+ # Contributing to orbit-formats
2
+
3
+ Thanks for your interest. This page is the one place to learn the workflow.
4
+
5
+ ## Getting set up
6
+
7
+ ```bash
8
+ git clone https://github.com/astro-tools/orbit-formats.git
9
+ cd orbit-formats
10
+ uv sync --all-groups
11
+ ```
12
+
13
+ This installs the package, its runtime dependencies, and the dev and docs groups.
14
+
15
+ ## Branches and PRs
16
+
17
+ - One issue per branch. Branch names use a short prefix for type:
18
+ - `feat/<slug>` — new capability, tied to a `type:feature` issue.
19
+ - `fix/<slug>` — bug fix, tied to a `type:bug` issue.
20
+ - `chore/<slug>` — infra / tooling / hygiene.
21
+ - `docs/<slug>` — docs-only change.
22
+ - Open a PR against `main`. Put `Closes #<N>` in the PR description so the issue
23
+ auto-closes on merge and the project board advances the card to Done.
24
+ - Squash-merge is the only merge method. The PR title becomes the squash commit
25
+ subject — write it as a complete imperative sentence.
26
+
27
+ ## Local checks before pushing
28
+
29
+ ```bash
30
+ uv run pytest # tests
31
+ uv run ruff check # lint
32
+ uv run ruff format --check # formatting
33
+ uv run mypy # types
34
+ ```
35
+
36
+ CI re-runs all four on Ubuntu, Windows, and macOS, across Python 3.10, 3.11, and 3.12.
37
+
38
+ ## Commit messages
39
+
40
+ Keep them short and imperative. One subject line, optional body.
41
+
42
+ Do not include AI or tool attribution trailers in commits, PR titles, PR descriptions,
43
+ or comments — see the repo-level convention.
44
+
45
+ ## Scope discipline
46
+
47
+ orbit-formats is an I/O and conversion library: it reads, writes, and converts orbital
48
+ state and ephemeris formats, and warns whenever a conversion cannot preserve
49
+ information. It is deliberately not a propagator, an integrator, or a general
50
+ frame-transformation engine. Before opening a feature issue, check the charter and the
51
+ existing issues to make sure the work belongs here.
52
+
53
+ ## Questions
54
+
55
+ Open a [discussion](https://github.com/orgs/astro-tools/discussions) rather than an
56
+ issue for open-ended questions, usage help, or brainstorming. The astro-tools org runs
57
+ a single shared discussions space — there is no per-repo discussions board.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 astro-tools
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.