gmat-sweep 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 (70) hide show
  1. gmat_sweep-0.1.0/.github/CODEOWNERS +2 -0
  2. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/backend-request.yml +41 -0
  3. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +82 -0
  4. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/chore.yml +25 -0
  5. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +39 -0
  7. gmat_sweep-0.1.0/.github/ISSUE_TEMPLATE/use-case-fit.yml +41 -0
  8. gmat_sweep-0.1.0/.github/workflows/ci.yml +140 -0
  9. gmat_sweep-0.1.0/.github/workflows/docs.yml +57 -0
  10. gmat_sweep-0.1.0/.github/workflows/release.yml +74 -0
  11. gmat_sweep-0.1.0/.gitignore +40 -0
  12. gmat_sweep-0.1.0/.python-version +1 -0
  13. gmat_sweep-0.1.0/CHANGELOG.md +77 -0
  14. gmat_sweep-0.1.0/CONTRIBUTING.md +91 -0
  15. gmat_sweep-0.1.0/LICENSE +21 -0
  16. gmat_sweep-0.1.0/PKG-INFO +207 -0
  17. gmat_sweep-0.1.0/README.md +161 -0
  18. gmat_sweep-0.1.0/docs/api.md +53 -0
  19. gmat_sweep-0.1.0/docs/examples/01_sma_scan.ipynb +414 -0
  20. gmat_sweep-0.1.0/docs/examples/02_epoch_arrival_grid.ipynb +474 -0
  21. gmat_sweep-0.1.0/docs/examples/03_killed_sweep_recovery.ipynb +483 -0
  22. gmat_sweep-0.1.0/docs/examples/index.md +21 -0
  23. gmat_sweep-0.1.0/docs/examples/leo_keplerian.script +38 -0
  24. gmat_sweep-0.1.0/docs/examples/leo_short.script +39 -0
  25. gmat_sweep-0.1.0/docs/examples/transfer_porkchop.script +47 -0
  26. gmat_sweep-0.1.0/docs/faq.md +63 -0
  27. gmat_sweep-0.1.0/docs/getting-started.md +93 -0
  28. gmat_sweep-0.1.0/docs/index.md +52 -0
  29. gmat_sweep-0.1.0/docs/manifest-schema.md +143 -0
  30. gmat_sweep-0.1.0/docs/parameter-spec.md +130 -0
  31. gmat_sweep-0.1.0/docs/supported-versions.md +64 -0
  32. gmat_sweep-0.1.0/mkdocs.yml +88 -0
  33. gmat_sweep-0.1.0/pyproject.toml +154 -0
  34. gmat_sweep-0.1.0/src/gmat_sweep/__init__.py +54 -0
  35. gmat_sweep-0.1.0/src/gmat_sweep/aggregate.py +193 -0
  36. gmat_sweep-0.1.0/src/gmat_sweep/api.py +131 -0
  37. gmat_sweep-0.1.0/src/gmat_sweep/backends/__init__.py +8 -0
  38. gmat_sweep-0.1.0/src/gmat_sweep/backends/base.py +78 -0
  39. gmat_sweep-0.1.0/src/gmat_sweep/backends/joblib.py +100 -0
  40. gmat_sweep-0.1.0/src/gmat_sweep/cli.py +245 -0
  41. gmat_sweep-0.1.0/src/gmat_sweep/distributions.py +3 -0
  42. gmat_sweep-0.1.0/src/gmat_sweep/errors.py +76 -0
  43. gmat_sweep-0.1.0/src/gmat_sweep/grids.py +88 -0
  44. gmat_sweep-0.1.0/src/gmat_sweep/manifest.py +238 -0
  45. gmat_sweep-0.1.0/src/gmat_sweep/py.typed +0 -0
  46. gmat_sweep-0.1.0/src/gmat_sweep/spec.py +197 -0
  47. gmat_sweep-0.1.0/src/gmat_sweep/sweep.py +194 -0
  48. gmat_sweep-0.1.0/src/gmat_sweep/worker.py +131 -0
  49. gmat_sweep-0.1.0/tests/__init__.py +0 -0
  50. gmat_sweep-0.1.0/tests/conftest.py +117 -0
  51. gmat_sweep-0.1.0/tests/data/golden/sma_16.parquet +0 -0
  52. gmat_sweep-0.1.0/tests/data/leo_basic.script +73 -0
  53. gmat_sweep-0.1.0/tests/test_aggregate.py +220 -0
  54. gmat_sweep-0.1.0/tests/test_api.py +234 -0
  55. gmat_sweep-0.1.0/tests/test_backends_base.py +101 -0
  56. gmat_sweep-0.1.0/tests/test_backends_joblib.py +144 -0
  57. gmat_sweep-0.1.0/tests/test_cli.py +398 -0
  58. gmat_sweep-0.1.0/tests/test_errors.py +53 -0
  59. gmat_sweep-0.1.0/tests/test_failure_modes.py +291 -0
  60. gmat_sweep-0.1.0/tests/test_grids.py +188 -0
  61. gmat_sweep-0.1.0/tests/test_import.py +16 -0
  62. gmat_sweep-0.1.0/tests/test_manifest.py +511 -0
  63. gmat_sweep-0.1.0/tests/test_manifest_replay_contract.py +227 -0
  64. gmat_sweep-0.1.0/tests/test_param_roundtrip.py +121 -0
  65. gmat_sweep-0.1.0/tests/test_reference_sweep.py +91 -0
  66. gmat_sweep-0.1.0/tests/test_run_roundtrip.py +102 -0
  67. gmat_sweep-0.1.0/tests/test_spec.py +171 -0
  68. gmat_sweep-0.1.0/tests/test_sweep.py +324 -0
  69. gmat_sweep-0.1.0/tests/test_worker.py +350 -0
  70. gmat_sweep-0.1.0/uv.lock +4862 -0
@@ -0,0 +1,2 @@
1
+ # Default reviewer for everything in this repo.
2
+ * @djankov
@@ -0,0 +1,41 @@
1
+ name: Backend request
2
+ description: Request a new execution backend behind the Pool abstraction.
3
+ title: "Backend: <name>"
4
+ labels: ["type:backend-request"]
5
+ body:
6
+ - type: input
7
+ id: backend_name
8
+ attributes:
9
+ label: Backend
10
+ description: Name of the execution surface (e.g. Slurm, Kubernetes, MPI, AWS Batch).
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: motivation
15
+ attributes:
16
+ label: Why this backend
17
+ description: What can't you do with the shipped backends (LocalJoblibPool, DaskPool, RayPool)? Cluster you already have? Org policy? Scale ceiling?
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: subprocess_isolation
22
+ attributes:
23
+ label: Subprocess-isolation contract
24
+ description: |
25
+ gmat-sweep guarantees one fresh Python interpreter per run (gmatpy cannot
26
+ be cleanly re-initialised in-process). Any backend that doesn't honour
27
+ this contract is rejected at import time. Briefly describe how the
28
+ proposed backend would satisfy it (one task per pod / one srun job per
29
+ run / etc.).
30
+ validations:
31
+ required: true
32
+ - type: textarea
33
+ id: prior_art
34
+ attributes:
35
+ label: Prior art
36
+ description: Existing Python wrappers, recipes, libraries you'd want us to consider.
37
+ - type: textarea
38
+ id: willingness
39
+ attributes:
40
+ label: Willingness to contribute
41
+ description: Are you offering a PR, an evaluation environment, sample workloads, or just flagging the need?
@@ -0,0 +1,82 @@
1
+ name: Bug
2
+ description: Report a defect in gmat-sweep.
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: Smallest snippet that triggers the bug. A `.script` fragment plus the Python that drives the sweep is ideal.
24
+ render: python
25
+ validations:
26
+ required: true
27
+ - type: input
28
+ id: gmat_sweep_version
29
+ attributes:
30
+ label: gmat-sweep version
31
+ placeholder: "e.g. 0.1.0, or git sha"
32
+ validations:
33
+ required: true
34
+ - type: input
35
+ id: gmat_run_version
36
+ attributes:
37
+ label: gmat-run version
38
+ placeholder: "e.g. 0.4.0"
39
+ validations:
40
+ required: true
41
+ - type: input
42
+ id: gmat_version
43
+ attributes:
44
+ label: GMAT version
45
+ placeholder: "e.g. R2026a"
46
+ validations:
47
+ required: true
48
+ - type: input
49
+ id: python_version
50
+ attributes:
51
+ label: Python version
52
+ placeholder: "e.g. 3.12.3"
53
+ validations:
54
+ required: true
55
+ - type: dropdown
56
+ id: backend
57
+ attributes:
58
+ label: Backend
59
+ options:
60
+ - LocalJoblibPool (default)
61
+ - DaskPool
62
+ - RayPool
63
+ - Other / unsure
64
+ validations:
65
+ required: true
66
+ - type: dropdown
67
+ id: os
68
+ attributes:
69
+ label: Operating system
70
+ options:
71
+ - Linux
72
+ - Windows
73
+ - macOS
74
+ - Other
75
+ validations:
76
+ required: true
77
+ - type: textarea
78
+ id: logs
79
+ attributes:
80
+ label: Logs
81
+ description: Relevant per-worker logs, the sweep manifest, captured stderr, pytest output.
82
+ 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 in the org-wide space for usage questions, ideas, or general chat.
@@ -0,0 +1,39 @@
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: Concrete, testable checkboxes. An outside reviewer should be able to read these and tell whether the feature is done.
25
+ value: |
26
+ - [ ]
27
+ - [ ]
28
+ validations:
29
+ required: true
30
+ - type: textarea
31
+ id: out_of_scope
32
+ attributes:
33
+ label: Out of scope / non-goals
34
+ description: What this issue deliberately does not cover. Helps keep scope honest.
35
+ - type: textarea
36
+ id: notes
37
+ attributes:
38
+ label: Notes
39
+ description: Design notes, links to charter sections, references to prior art, open questions.
@@ -0,0 +1,41 @@
1
+ name: Use-case fit
2
+ description: I want to use gmat-sweep for X — does it fit?
3
+ title: "<short summary of the use case>"
4
+ labels: ["type:use-case-fit"]
5
+ body:
6
+ - type: textarea
7
+ id: use_case
8
+ attributes:
9
+ label: What you want to do
10
+ description: Describe the analysis or workflow you have in mind. A launch-window scan? A dispersion study? Something else?
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: parameters
15
+ attributes:
16
+ label: What you'd be sweeping
17
+ description: Which fields would vary, and roughly how (grid? Monte Carlo? Latin hypercube? something else)? Order-of-magnitude run count.
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: existing_workflow
22
+ attributes:
23
+ label: How you do this today
24
+ description: Hand-rolled multiprocessing? A spreadsheet? Paramat? Nothing yet? Helps us understand the pain point.
25
+ - type: textarea
26
+ id: blockers
27
+ attributes:
28
+ label: What's stopping you from just trying it
29
+ description: Missing feature, unclear docs, uncertainty about scale, license concern, scope question?
30
+ validations:
31
+ required: true
32
+ - type: input
33
+ id: gmat_version
34
+ attributes:
35
+ label: GMAT version
36
+ placeholder: "e.g. R2026a"
37
+ - type: textarea
38
+ id: notes
39
+ attributes:
40
+ label: Notes
41
+ description: Links to a paper, prior project, GMAT script — anything that helps us understand the use case.
@@ -0,0 +1,140 @@
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 }}, ${{ matrix.gmat-version }})
15
+ runs-on: ${{ matrix.os }}
16
+ timeout-minutes: 30
17
+ strategy:
18
+ fail-fast: false
19
+ # 2 OSes × 3 Python minors × 2 GMAT releases = 12 cells. macOS is
20
+ # deferred to v0.2 per the charter; R2026a is the primary target,
21
+ # R2025a is the previous release we still support.
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest]
24
+ python-version: ['3.10', '3.11', '3.12']
25
+ gmat-version: [R2025a, R2026a]
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ - name: Set up Python ${{ matrix.python-version }}
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v4
36
+ with:
37
+ enable-cache: true
38
+ cache-dependency-glob: uv.lock
39
+
40
+ - uses: astro-tools/setup-gmat@v0
41
+ with:
42
+ version: ${{ matrix.gmat-version }}
43
+ cache: true
44
+
45
+ - name: Install project
46
+ run: uv sync --all-groups
47
+
48
+ - name: Run pytest
49
+ # `-m "integration or not integration"` overrides the default
50
+ # marker filter in pyproject.toml so CI runs both unit and
51
+ # integration suites in a single invocation.
52
+ run: uv run pytest -m "integration or not integration" --cov --cov-report=term-missing
53
+
54
+ # Coverage gates run on a single matrix combination — the .coverage
55
+ # data is identical across runners. Overall floor matches the v0.1
56
+ # charter DoD; the four per-file gates match CONTRIBUTING.md.
57
+
58
+ - name: Enforce overall coverage (>=80%)
59
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
60
+ run: uv run coverage report --fail-under=80
61
+
62
+ - name: Enforce grids.py coverage (>=95%)
63
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
64
+ run: uv run coverage report --include='src/gmat_sweep/grids.py' --fail-under=95
65
+
66
+ - name: Enforce distributions.py coverage (>=95%)
67
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
68
+ run: uv run coverage report --include='src/gmat_sweep/distributions.py' --fail-under=95
69
+
70
+ - name: Enforce manifest.py coverage (>=95%)
71
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
72
+ run: uv run coverage report --include='src/gmat_sweep/manifest.py' --fail-under=95
73
+
74
+ - name: Enforce aggregate.py coverage (>=95%)
75
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
76
+ run: uv run coverage report --include='src/gmat_sweep/aggregate.py' --fail-under=95
77
+
78
+ # Smoke-execute the example notebooks end-to-end. Catches "someone changed
79
+ # the public surface and forgot to refresh the committed notebook"
80
+ # regressions without paying the cost of nbval-style strict comparison
81
+ # (notebooks are committed with cleared outputs). One matrix combo is
82
+ # enough — the underlying surface is covered cross-platform by the rest
83
+ # of the test job. Notebook 03 uses signal.SIGINT against a child
84
+ # process, so it is Linux-only (Windows lacks the matching semantics).
85
+ - name: Smoke-execute example notebooks
86
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
87
+ working-directory: docs/examples
88
+ run: |
89
+ uv sync --all-groups --extra examples
90
+ uv run jupyter execute 01_sma_scan.ipynb
91
+ uv run jupyter execute 02_epoch_arrival_grid.ipynb
92
+ uv run jupyter execute 03_killed_sweep_recovery.ipynb
93
+
94
+ lint:
95
+ name: lint
96
+ runs-on: ubuntu-latest
97
+ timeout-minutes: 5
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - uses: actions/setup-python@v5
101
+ with:
102
+ python-version: '3.12'
103
+ - uses: astral-sh/setup-uv@v4
104
+ with:
105
+ enable-cache: true
106
+ cache-dependency-glob: uv.lock
107
+ - run: uv sync --all-groups
108
+ - run: uv run ruff check
109
+ - run: uv run ruff format --check
110
+
111
+ typecheck:
112
+ name: typecheck
113
+ runs-on: ubuntu-latest
114
+ timeout-minutes: 10
115
+ steps:
116
+ - uses: actions/checkout@v4
117
+ - uses: actions/setup-python@v5
118
+ with:
119
+ python-version: '3.12'
120
+ - uses: astral-sh/setup-uv@v4
121
+ with:
122
+ enable-cache: true
123
+ cache-dependency-glob: uv.lock
124
+ - run: uv sync --all-groups
125
+ - run: uv run mypy
126
+
127
+ # Smoke-check that `pip install gmat-sweep` (no extras, no dev group)
128
+ # imports cleanly. Catches an extras-only or dev-only dependency leaking
129
+ # into the default install path.
130
+ minimal-install:
131
+ name: minimal install smoke
132
+ runs-on: ubuntu-latest
133
+ timeout-minutes: 5
134
+ steps:
135
+ - uses: actions/checkout@v4
136
+ - uses: actions/setup-python@v5
137
+ with:
138
+ python-version: '3.12'
139
+ - run: pip install .
140
+ - run: python -c "import gmat_sweep"
@@ -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/gmat-sweep
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,77 @@
1
+ # Changelog
2
+
3
+ All notable changes to gmat-sweep 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
+ ## [0.1.0] — 2026-05-04
9
+
10
+ Initial public release. The MVP slice of the charter: full-factorial parameter
11
+ sweeps over a `gmat-run` mission, parallelised across subprocess workers,
12
+ aggregated into a `(run_id, time)`-MultiIndexed `pandas.DataFrame`, and backed
13
+ by a durable JSON Lines manifest.
14
+
15
+ ### Added
16
+
17
+ - `sweep(mission, grid=..., workers=...)` — public entry point for
18
+ full-factorial parameter grids. Materialises the cartesian product into one
19
+ [`RunSpec`][gmat_sweep.RunSpec] per cell, dispatches through the default
20
+ [`LocalJoblibPool`][gmat_sweep.Pool] backend, and returns the aggregated
21
+ multi-indexed DataFrame (#9).
22
+ - `gmat_sweep.full_factorial` and `gmat_sweep.expand_grid_to_run_specs` —
23
+ cartesian-product expansion with deterministic, lexicographic key ordering
24
+ and zero-based `run_id` assignment, the contract every manifest and future
25
+ resume flow depends on (#4).
26
+ - [`Pool`][gmat_sweep.Pool] ABC with the `subprocess_isolated` invariant
27
+ enforced at class-definition time, plus the default
28
+ [`LocalJoblibPool`][gmat_sweep.Pool] implementation backed by joblib's loky
29
+ executor — every run spawns a fresh Python interpreter that imports
30
+ `gmatpy` once, sidestepping the well-known reinit limitation (#7).
31
+ - Single-run worker callable that imports `gmat_run`, applies overrides via the
32
+ dotted-path setter, runs the mission, serialises every `ReportFile` to
33
+ Parquet, and converts every exception into a `RunOutcome.failed(...)` so a
34
+ single bad run never aborts the sweep (#6).
35
+ - Lazy `(run_id, time)`-MultiIndex aggregation from per-run Parquet via
36
+ pyarrow's dataset API. Failed and skipped runs surface as one row with the
37
+ `__status` column populated (#8).
38
+ - JSON Lines manifest with one header line and one fsync'd
39
+ [`ManifestEntry`][gmat_sweep.ManifestEntry] per run. `Manifest.load`
40
+ tolerates a single torn last line (a `Ctrl-C`'d sweep leaves a parseable
41
+ file). Header captures canonical script SHA-256, `gmat_sweep` /
42
+ `gmat_run` / GMAT install / Python / OS versions, the materialised parameter
43
+ spec, and the run count. Includes `find_failed` / `find_missing` lookup
44
+ helpers for the v0.2 resume flow (#5).
45
+ - Typed exception hierarchy under `gmat_sweep.errors` rooted at
46
+ [`GmatSweepError`][gmat_sweep.GmatSweepError] —
47
+ [`SweepConfigError`][gmat_sweep.SweepConfigError],
48
+ [`RunFailed`][gmat_sweep.RunFailed],
49
+ [`BackendError`][gmat_sweep.BackendError], and
50
+ [`ManifestCorruptError`][gmat_sweep.ManifestCorruptError] — alongside
51
+ JSON-serialisable [`RunSpec`][gmat_sweep.RunSpec] /
52
+ [`SweepSpec`][gmat_sweep.SweepSpec] / [`RunOutcome`][gmat_sweep.RunOutcome]
53
+ dataclasses (#3).
54
+ - `gmat-sweep` console script with `run` and `show` subcommands. `run`
55
+ accepts repeated `--grid name=lo:hi:count` linspace and `--grid
56
+ name=v1,v2,v3` explicit-list axes; `show` prints a one-line summary of an
57
+ existing manifest (#10).
58
+ - Validation test suite — per-run round-trip, parameter-spec round-trip
59
+ (float / int / datetime / vector / str enum), 16-run reference-sweep
60
+ regression, failure-mode coverage (invalid override, divergent solver, bad
61
+ script, OOM), and a manifest-replay contract test that pins the v0.1
62
+ manifest format ahead of v0.2's resume flow (#11).
63
+ - MkDocs-Material documentation site auto-deployed to GitHub Pages on tag
64
+ pushes, with mkdocstrings-driven API reference, parameter-spec and
65
+ manifest-schema reference pages, supported-versions table, and FAQ
66
+ (#12, #28).
67
+ - Three runnable example notebooks rendered into the docs site —
68
+ single-axis SMA scan, two-axis epoch × time-of-flight grid, and a
69
+ surviving-a-kill walkthrough demonstrating manifest durability (#13, #29).
70
+ - CI on Ubuntu + Windows × Python 3.10 / 3.11 / 3.12 × R2025a / R2026a (12
71
+ cells) via `astro-tools/setup-gmat`, with both unit and integration suites
72
+ enabled. Coverage gates: ≥ 80 % overall and ≥ 95 % each on `grids.py`,
73
+ `distributions.py`, `manifest.py`, and `aggregate.py` (#2).
74
+ - Release workflow: `uv build` → PyPI trusted publishing →
75
+ `gh release create --generate-notes` on `v*` tags (#2).
76
+
77
+ [0.1.0]: https://github.com/astro-tools/gmat-sweep/releases/tag/v0.1.0