microlens-submit 0.12.2__tar.gz → 0.16.1__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.
- microlens_submit-0.16.1/MANIFEST.in +2 -0
- {microlens_submit-0.12.2/microlens_submit.egg-info → microlens_submit-0.16.1}/PKG-INFO +52 -14
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/README.md +43 -12
- microlens_submit-0.16.1/microlens_submit/__init__.py +13 -0
- microlens_submit-0.16.1/microlens_submit/cli/__init__.py +5 -0
- microlens_submit-0.16.1/microlens_submit/cli/__main__.py +6 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/__init__.py +1 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/dossier.py +139 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/export.py +177 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/init.py +172 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/solutions.py +722 -0
- microlens_submit-0.16.1/microlens_submit/cli/commands/validation.py +241 -0
- microlens_submit-0.16.1/microlens_submit/cli/main.py +120 -0
- microlens_submit-0.16.1/microlens_submit/dossier/__init__.py +51 -0
- microlens_submit-0.16.1/microlens_submit/dossier/dashboard.py +503 -0
- microlens_submit-0.16.1/microlens_submit/dossier/event_page.py +370 -0
- microlens_submit-0.16.1/microlens_submit/dossier/full_report.py +330 -0
- microlens_submit-0.16.1/microlens_submit/dossier/solution_page.py +534 -0
- microlens_submit-0.16.1/microlens_submit/dossier/utils.py +111 -0
- microlens_submit-0.16.1/microlens_submit/error_messages.py +283 -0
- microlens_submit-0.16.1/microlens_submit/models/__init__.py +28 -0
- microlens_submit-0.16.1/microlens_submit/models/event.py +406 -0
- microlens_submit-0.16.1/microlens_submit/models/solution.py +569 -0
- microlens_submit-0.16.1/microlens_submit/models/submission.py +569 -0
- microlens_submit-0.16.1/microlens_submit/tier_validation.py +208 -0
- microlens_submit-0.16.1/microlens_submit/utils.py +373 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit/validate_parameters.py +478 -180
- {microlens_submit-0.12.2 → microlens_submit-0.16.1/microlens_submit.egg-info}/PKG-INFO +52 -14
- microlens_submit-0.16.1/microlens_submit.egg-info/SOURCES.txt +42 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit.egg-info/requires.txt +4 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/pyproject.toml +18 -6
- microlens_submit-0.16.1/setup.py +65 -0
- microlens_submit-0.16.1/tests/test_api.py +1048 -0
- microlens_submit-0.16.1/tests/test_cli.py +1732 -0
- microlens_submit-0.16.1/tests/test_dossier_generation.py +443 -0
- microlens_submit-0.16.1/tests/test_dossier_pages.py +49 -0
- microlens_submit-0.16.1/tests/test_tier_validation.py +518 -0
- microlens_submit-0.12.2/MANIFEST.in +0 -2
- microlens_submit-0.12.2/microlens_submit/__init__.py +0 -163
- microlens_submit-0.12.2/microlens_submit/api.py +0 -1257
- microlens_submit-0.12.2/microlens_submit/cli.py +0 -1803
- microlens_submit-0.12.2/microlens_submit/dossier.py +0 -1443
- microlens_submit-0.12.2/microlens_submit.egg-info/SOURCES.txt +0 -20
- microlens_submit-0.12.2/tests/test_api.py +0 -496
- microlens_submit-0.12.2/tests/test_cli.py +0 -1179
- microlens_submit-0.12.2/tests/test_dossier_generation.py +0 -212
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/LICENSE +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit/assets/github-desktop_logo.png +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit/assets/rges-pit_logo.png +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit.egg-info/dependency_links.txt +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit.egg-info/entry_points.txt +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/microlens_submit.egg-info/top_level.txt +0 -0
- {microlens_submit-0.12.2 → microlens_submit-0.16.1}/setup.cfg +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microlens-submit
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: A
|
|
3
|
+
Version: 0.16.1
|
|
4
|
+
Summary: A tool for managing and submitting microlensing solutions
|
|
5
|
+
Home-page: https://github.com/AmberLee2427/microlens-submit
|
|
6
|
+
Author: Amber Malpas
|
|
5
7
|
Author-email: Amber Malpas <malpas.1@osu.edu>, Roman Science Platform Team <roman-science-platform@stsci.edu>
|
|
6
8
|
License: MIT
|
|
7
9
|
Project-URL: Homepage, https://github.com/AmberLee2427/microlens-submit
|
|
@@ -27,6 +29,7 @@ Requires-Dist: typer[all]>=0.9.0
|
|
|
27
29
|
Requires-Dist: rich>=13.0.0
|
|
28
30
|
Requires-Dist: pyyaml>=6.0
|
|
29
31
|
Requires-Dist: markdown>=3.4.0
|
|
32
|
+
Requires-Dist: importlib_resources>=1.0.0; python_version < "3.9"
|
|
30
33
|
Provides-Extra: dev
|
|
31
34
|
Requires-Dist: pytest; extra == "dev"
|
|
32
35
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -37,7 +40,11 @@ Requires-Dist: black; extra == "dev"
|
|
|
37
40
|
Requires-Dist: isort; extra == "dev"
|
|
38
41
|
Requires-Dist: sphinx; extra == "dev"
|
|
39
42
|
Requires-Dist: sphinx_rtd_theme; extra == "dev"
|
|
43
|
+
Requires-Dist: importlib_resources; extra == "dev"
|
|
44
|
+
Dynamic: author
|
|
45
|
+
Dynamic: home-page
|
|
40
46
|
Dynamic: license-file
|
|
47
|
+
Dynamic: requires-python
|
|
41
48
|
|
|
42
49
|
<p align="center">
|
|
43
50
|
<a href="https://github.com/AmberLee2427/microlens-submit">
|
|
@@ -49,15 +56,13 @@ Dynamic: license-file
|
|
|
49
56
|
|
|
50
57
|
*A stateful submission toolkit for the RGES-PIT Microlensing Data Challenge.*
|
|
51
58
|
|
|
52
|
-
[](https://github.com/AmberLee2427/microlens-submit/actions/workflows/ci.yml)
|
|
54
|
-
[](https://opensource.org/licenses/MIT)
|
|
59
|
+
[](https://pypi.org/project/microlens-submit/)[](https://microlens-submit.readthedocs.io/en/latest/?badge=latest)[](https://github.com/AmberLee2427/microlens-submit/actions/workflows/ci.yml)[](https://pypi.org/project/microlens-submit/)[](https://opensource.org/licenses/MIT)
|
|
55
60
|
|
|
56
61
|
<br>
|
|
57
62
|
|
|
58
63
|
`microlens-submit` provides a robust, version-controlled workflow for managing, validating, and packaging your challenge submission over a long period. It supports both a programmatic Python API and a full-featured Command Line Interface (CLI) for language-agnostic use.
|
|
59
64
|
|
|
60
|
-
Full documentation is hosted on [Read the Docs](https://microlens-submit.readthedocs.io/en/latest/). A comprehensive tutorial notebook is available at `docs/Submission_Tool_Tutorial.ipynb`. Challenge participants who prefer not to use this tool can consult [
|
|
65
|
+
Full documentation is hosted on [Read the Docs](https://microlens-submit.readthedocs.io/en/latest/). A comprehensive tutorial notebook is available at `docs/Submission_Tool_Tutorial.ipynb`. Challenge participants who prefer not to use this tool can consult the [Submission Manual](https://microlens-submit.readthedocs.io/en/latest/submission_manual.html) for the manual submission format.
|
|
61
66
|
|
|
62
67
|
## Key Features
|
|
63
68
|
|
|
@@ -72,10 +77,11 @@ Full documentation is hosted on [Read the Docs](https://microlens-submit.readthe
|
|
|
72
77
|
* **Environment Capture:** Automatically records your Python dependencies for each specific model fit, ensuring reproducibility.
|
|
73
78
|
* **Optional Posterior Storage:** Record the path to posterior samples for any solution.
|
|
74
79
|
* **Simple Export:** Packages all your active solutions into a clean, standardized `.zip` archive for final submission.
|
|
80
|
+
* **Bulk Import:** Import multiple solutions at once from a CSV file using the `import-solutions` CLI command. Supports column mapping, alias handling, duplicate handling, notes, dry-run, and validation options.
|
|
75
81
|
|
|
76
82
|
## Installation
|
|
77
83
|
|
|
78
|
-
The package is
|
|
84
|
+
The package is available on PyPI:
|
|
79
85
|
|
|
80
86
|
```bash
|
|
81
87
|
pip install microlens-submit
|
|
@@ -87,8 +93,21 @@ The CLI is the recommended way to interact with your submission project.
|
|
|
87
93
|
|
|
88
94
|
You can pass ``--no-color`` to any command if your terminal does not support ANSI colors.
|
|
89
95
|
|
|
90
|
-
1. Initialize your project:
|
|
96
|
+
1. Initialize your project:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
microlens-submit init --team-name "Planet Pounders" --tier "advanced"
|
|
100
|
+
# if a project directory was provided to `init`, you should now `cd` into that project
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To pass validation, you need to have provided a `repo_url` and `hardware_info` to the project and have a git project initialized in your sumission-project directory.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
microlens-submit set-repo-url <url> ./
|
|
107
|
+
microlens-submit set-hardware-info --cpu-details "intel i7 xxx" --ram-gb 32 ./
|
|
108
|
+
```
|
|
91
109
|
2. Add a new solution to an event:
|
|
110
|
+
|
|
92
111
|
```bash
|
|
93
112
|
microlens-submit add-solution ogle-2025-blg-0042 1S2L \
|
|
94
113
|
--param t0=555.5 \
|
|
@@ -96,14 +115,29 @@ You can pass ``--no-color`` to any command if your terminal does not support ANS
|
|
|
96
115
|
--param tE=25.0 \
|
|
97
116
|
--notes "This is a great fit!"
|
|
98
117
|
```
|
|
118
|
+
|
|
99
119
|
Model types must be one of `1S1L`, `1S2L`, `2S1L`, `2S2L`, `1S3L`, `2S3L`, or `other`.
|
|
100
120
|
This will create a new solution and print its unique `solution_id`.
|
|
121
|
+
|
|
101
122
|
You can run the same command with `--dry-run` first to verify the
|
|
102
123
|
parsed input without saving anything.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
|
|
125
|
+
3. **Bulk import multiple solutions from a CSV file:**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
microlens-submit import-solutions tests/data/test_import.csv --dry-run
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
See the file `tests/data/test_import.csv` for a comprehensive example covering all features and edge cases.
|
|
132
|
+
You can use this file as a template for your own imports.
|
|
133
|
+
|
|
134
|
+
4. Deactivate a solution that didn't work out: `microlens-submit deactivate <solution_id>`
|
|
135
|
+
|
|
136
|
+
5. List all solutions for an event: `microlens-submit list-solutions ogle-2025-blg-0042`
|
|
137
|
+
|
|
138
|
+
6. Validate solutions and check for issues: `microlens-submit validate-solution <solution_id>`
|
|
139
|
+
|
|
140
|
+
7. Export your final submission: `microlens-submit export final_submission.zip`
|
|
107
141
|
|
|
108
142
|
**Note:** When you add a solution, it's automatically validated and any warnings are displayed. Use `--dry-run` to check validation without saving.
|
|
109
143
|
|
|
@@ -139,7 +173,8 @@ sub.export("final_submission.zip")
|
|
|
139
173
|
|
|
140
174
|
The full development plan can be found in agents.md. Contributions are welcome!
|
|
141
175
|
|
|
142
|
-
To build and test this project, the development
|
|
176
|
+
To build and test this project, install the development dependencies using either `pip install -e .[dev]` or `pip install -r requirements-dev.txt`. These packages are required to run the test suite and are listed in `requirements-dev.txt`.
|
|
177
|
+
After installing the dependencies, run `pre-commit install` to set up the Git hooks for automatic formatting and linting. The development environment needs the following Python libraries.
|
|
143
178
|
|
|
144
179
|
### Core Dependencies:
|
|
145
180
|
* **`typer[all]`**: For building the powerful command-line interface. The `[all]` extra ensures shell completion support is included.
|
|
@@ -153,9 +188,12 @@ To build and test this project, the development environment needs the following
|
|
|
153
188
|
* **`build`**: For building the package from the `pyproject.toml` file.
|
|
154
189
|
* **`twine`**: For uploading the final package to PyPI.
|
|
155
190
|
|
|
191
|
+
### Test Data
|
|
192
|
+
|
|
193
|
+
A comprehensive test CSV file is provided at `tests/data/test_import.csv`. This file is used in the test suite and can be copied or adapted for your own bulk imports or for development/testing purposes.
|
|
194
|
+
|
|
156
195
|
## Citation
|
|
157
196
|
|
|
158
197
|
If you use **microlens-submit** in your research, please cite the project using
|
|
159
198
|
the metadata provided in the `CITATION.cff` file. Most reference managers can
|
|
160
199
|
import this file directly.
|
|
161
|
-
|
|
@@ -8,15 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
*A stateful submission toolkit for the RGES-PIT Microlensing Data Challenge.*
|
|
10
10
|
|
|
11
|
-
[](https://github.com/AmberLee2427/microlens-submit/actions/workflows/ci.yml)
|
|
13
|
-
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://pypi.org/project/microlens-submit/)[](https://microlens-submit.readthedocs.io/en/latest/?badge=latest)[](https://github.com/AmberLee2427/microlens-submit/actions/workflows/ci.yml)[](https://pypi.org/project/microlens-submit/)[](https://opensource.org/licenses/MIT)
|
|
14
12
|
|
|
15
13
|
<br>
|
|
16
14
|
|
|
17
15
|
`microlens-submit` provides a robust, version-controlled workflow for managing, validating, and packaging your challenge submission over a long period. It supports both a programmatic Python API and a full-featured Command Line Interface (CLI) for language-agnostic use.
|
|
18
16
|
|
|
19
|
-
Full documentation is hosted on [Read the Docs](https://microlens-submit.readthedocs.io/en/latest/). A comprehensive tutorial notebook is available at `docs/Submission_Tool_Tutorial.ipynb`. Challenge participants who prefer not to use this tool can consult [
|
|
17
|
+
Full documentation is hosted on [Read the Docs](https://microlens-submit.readthedocs.io/en/latest/). A comprehensive tutorial notebook is available at `docs/Submission_Tool_Tutorial.ipynb`. Challenge participants who prefer not to use this tool can consult the [Submission Manual](https://microlens-submit.readthedocs.io/en/latest/submission_manual.html) for the manual submission format.
|
|
20
18
|
|
|
21
19
|
## Key Features
|
|
22
20
|
|
|
@@ -31,10 +29,11 @@ Full documentation is hosted on [Read the Docs](https://microlens-submit.readthe
|
|
|
31
29
|
* **Environment Capture:** Automatically records your Python dependencies for each specific model fit, ensuring reproducibility.
|
|
32
30
|
* **Optional Posterior Storage:** Record the path to posterior samples for any solution.
|
|
33
31
|
* **Simple Export:** Packages all your active solutions into a clean, standardized `.zip` archive for final submission.
|
|
32
|
+
* **Bulk Import:** Import multiple solutions at once from a CSV file using the `import-solutions` CLI command. Supports column mapping, alias handling, duplicate handling, notes, dry-run, and validation options.
|
|
34
33
|
|
|
35
34
|
## Installation
|
|
36
35
|
|
|
37
|
-
The package is
|
|
36
|
+
The package is available on PyPI:
|
|
38
37
|
|
|
39
38
|
```bash
|
|
40
39
|
pip install microlens-submit
|
|
@@ -46,8 +45,21 @@ The CLI is the recommended way to interact with your submission project.
|
|
|
46
45
|
|
|
47
46
|
You can pass ``--no-color`` to any command if your terminal does not support ANSI colors.
|
|
48
47
|
|
|
49
|
-
1. Initialize your project:
|
|
48
|
+
1. Initialize your project:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
microlens-submit init --team-name "Planet Pounders" --tier "advanced"
|
|
52
|
+
# if a project directory was provided to `init`, you should now `cd` into that project
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To pass validation, you need to have provided a `repo_url` and `hardware_info` to the project and have a git project initialized in your sumission-project directory.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
microlens-submit set-repo-url <url> ./
|
|
59
|
+
microlens-submit set-hardware-info --cpu-details "intel i7 xxx" --ram-gb 32 ./
|
|
60
|
+
```
|
|
50
61
|
2. Add a new solution to an event:
|
|
62
|
+
|
|
51
63
|
```bash
|
|
52
64
|
microlens-submit add-solution ogle-2025-blg-0042 1S2L \
|
|
53
65
|
--param t0=555.5 \
|
|
@@ -55,14 +67,29 @@ You can pass ``--no-color`` to any command if your terminal does not support ANS
|
|
|
55
67
|
--param tE=25.0 \
|
|
56
68
|
--notes "This is a great fit!"
|
|
57
69
|
```
|
|
70
|
+
|
|
58
71
|
Model types must be one of `1S1L`, `1S2L`, `2S1L`, `2S2L`, `1S3L`, `2S3L`, or `other`.
|
|
59
72
|
This will create a new solution and print its unique `solution_id`.
|
|
73
|
+
|
|
60
74
|
You can run the same command with `--dry-run` first to verify the
|
|
61
75
|
parsed input without saving anything.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
|
|
77
|
+
3. **Bulk import multiple solutions from a CSV file:**
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
microlens-submit import-solutions tests/data/test_import.csv --dry-run
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
See the file `tests/data/test_import.csv` for a comprehensive example covering all features and edge cases.
|
|
84
|
+
You can use this file as a template for your own imports.
|
|
85
|
+
|
|
86
|
+
4. Deactivate a solution that didn't work out: `microlens-submit deactivate <solution_id>`
|
|
87
|
+
|
|
88
|
+
5. List all solutions for an event: `microlens-submit list-solutions ogle-2025-blg-0042`
|
|
89
|
+
|
|
90
|
+
6. Validate solutions and check for issues: `microlens-submit validate-solution <solution_id>`
|
|
91
|
+
|
|
92
|
+
7. Export your final submission: `microlens-submit export final_submission.zip`
|
|
66
93
|
|
|
67
94
|
**Note:** When you add a solution, it's automatically validated and any warnings are displayed. Use `--dry-run` to check validation without saving.
|
|
68
95
|
|
|
@@ -98,7 +125,8 @@ sub.export("final_submission.zip")
|
|
|
98
125
|
|
|
99
126
|
The full development plan can be found in agents.md. Contributions are welcome!
|
|
100
127
|
|
|
101
|
-
To build and test this project, the development
|
|
128
|
+
To build and test this project, install the development dependencies using either `pip install -e .[dev]` or `pip install -r requirements-dev.txt`. These packages are required to run the test suite and are listed in `requirements-dev.txt`.
|
|
129
|
+
After installing the dependencies, run `pre-commit install` to set up the Git hooks for automatic formatting and linting. The development environment needs the following Python libraries.
|
|
102
130
|
|
|
103
131
|
### Core Dependencies:
|
|
104
132
|
* **`typer[all]`**: For building the powerful command-line interface. The `[all]` extra ensures shell completion support is included.
|
|
@@ -112,9 +140,12 @@ To build and test this project, the development environment needs the following
|
|
|
112
140
|
* **`build`**: For building the package from the `pyproject.toml` file.
|
|
113
141
|
* **`twine`**: For uploading the final package to PyPI.
|
|
114
142
|
|
|
143
|
+
### Test Data
|
|
144
|
+
|
|
145
|
+
A comprehensive test CSV file is provided at `tests/data/test_import.csv`. This file is used in the test suite and can be copied or adapted for your own bulk imports or for development/testing purposes.
|
|
146
|
+
|
|
115
147
|
## Citation
|
|
116
148
|
|
|
117
149
|
If you use **microlens-submit** in your research, please cite the project using
|
|
118
150
|
the metadata provided in the `CITATION.cff` file. Most reference managers can
|
|
119
151
|
import this file directly.
|
|
120
|
-
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Stateful tools for Microlensing Data Challenge submissions.
|
|
2
|
+
|
|
3
|
+
``microlens-submit`` manages events and solutions on disk so you can build,
|
|
4
|
+
validate, and export a challenge submission using either the Python API or
|
|
5
|
+
the command line interface.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.16.1"
|
|
9
|
+
|
|
10
|
+
from .models import Event, Solution, Submission
|
|
11
|
+
from .utils import load
|
|
12
|
+
|
|
13
|
+
__all__ = ["Event", "Solution", "Submission", "load"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""CLI commands package for microlens-submit."""
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Dossier generation commands for microlens-submit CLI."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
|
|
10
|
+
from microlens_submit.dossier import generate_dashboard_html, generate_event_page, generate_solution_page
|
|
11
|
+
from microlens_submit.dossier.full_report import generate_full_dossier_report_html
|
|
12
|
+
from microlens_submit.utils import load
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def generate_dossier(
|
|
18
|
+
project_path: Path = typer.Argument(Path("."), help="Project directory"),
|
|
19
|
+
event_id: Optional[str] = typer.Option(
|
|
20
|
+
None,
|
|
21
|
+
"--event-id",
|
|
22
|
+
help="Generate dossier for a specific event only (omit for full dossier)",
|
|
23
|
+
),
|
|
24
|
+
solution_id: Optional[str] = typer.Option(
|
|
25
|
+
None,
|
|
26
|
+
"--solution-id",
|
|
27
|
+
help="Generate dossier for a specific solution only (omit for full dossier)",
|
|
28
|
+
),
|
|
29
|
+
open: bool = typer.Option(
|
|
30
|
+
False,
|
|
31
|
+
"--open",
|
|
32
|
+
help="Open the generated dossier in your web browser after generation.",
|
|
33
|
+
),
|
|
34
|
+
) -> None:
|
|
35
|
+
"""Generate an HTML dossier for the submission.
|
|
36
|
+
|
|
37
|
+
Use --open to automatically open the main dossier page in your browser after generation.
|
|
38
|
+
"""
|
|
39
|
+
sub = load(str(project_path))
|
|
40
|
+
output_dir = Path(project_path) / "dossier"
|
|
41
|
+
|
|
42
|
+
if solution_id:
|
|
43
|
+
# Find the solution across all events (same pattern as other CLI commands)
|
|
44
|
+
solution = None
|
|
45
|
+
containing_event_id = None
|
|
46
|
+
for eid, event in sub.events.items():
|
|
47
|
+
if solution_id in event.solutions:
|
|
48
|
+
solution = event.solutions[solution_id]
|
|
49
|
+
containing_event_id = eid
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
if solution is None:
|
|
53
|
+
console.print(f"Solution {solution_id} not found", style="bold red")
|
|
54
|
+
raise typer.Exit(1)
|
|
55
|
+
|
|
56
|
+
# Create output directory and assets subdirectory
|
|
57
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
(output_dir / "assets").mkdir(exist_ok=True)
|
|
59
|
+
|
|
60
|
+
# Generate only the specific solution page
|
|
61
|
+
event = sub.events[containing_event_id]
|
|
62
|
+
console.print(
|
|
63
|
+
Panel(
|
|
64
|
+
f"Generating dossier for solution {solution_id} in event {containing_event_id}...",
|
|
65
|
+
style="cyan",
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
generate_solution_page(solution, event, sub, output_dir)
|
|
69
|
+
if open:
|
|
70
|
+
import webbrowser
|
|
71
|
+
|
|
72
|
+
solution_path = output_dir / f"{solution_id}.html"
|
|
73
|
+
if solution_path.exists():
|
|
74
|
+
webbrowser.open(solution_path.resolve().as_uri())
|
|
75
|
+
|
|
76
|
+
elif event_id:
|
|
77
|
+
# Generate only the specific event page
|
|
78
|
+
if event_id not in sub.events:
|
|
79
|
+
console.print(f"Event {event_id} not found", style="bold red")
|
|
80
|
+
raise typer.Exit(1)
|
|
81
|
+
|
|
82
|
+
# Create output directory and assets subdirectory
|
|
83
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
(output_dir / "assets").mkdir(exist_ok=True)
|
|
85
|
+
|
|
86
|
+
event = sub.events[event_id]
|
|
87
|
+
console.print(Panel(f"Generating dossier for event {event_id}...", style="cyan"))
|
|
88
|
+
generate_event_page(event, sub, output_dir)
|
|
89
|
+
if open:
|
|
90
|
+
import webbrowser
|
|
91
|
+
|
|
92
|
+
event_path = output_dir / f"{event_id}.html"
|
|
93
|
+
if event_path.exists():
|
|
94
|
+
webbrowser.open(event_path.resolve().as_uri())
|
|
95
|
+
|
|
96
|
+
else:
|
|
97
|
+
# Generate full dossier (all events and solutions)
|
|
98
|
+
console.print(
|
|
99
|
+
Panel(
|
|
100
|
+
"Generating comprehensive dossier for all events and solutions...",
|
|
101
|
+
style="cyan",
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
generate_dashboard_html(sub, output_dir)
|
|
105
|
+
|
|
106
|
+
# Generate comprehensive printable dossier
|
|
107
|
+
console.print(Panel("Generating comprehensive printable dossier...", style="cyan"))
|
|
108
|
+
generate_full_dossier_report_html(sub, output_dir)
|
|
109
|
+
|
|
110
|
+
# Replace placeholder in index.html with the real link
|
|
111
|
+
dashboard_path = output_dir / "index.html"
|
|
112
|
+
if dashboard_path.exists():
|
|
113
|
+
with dashboard_path.open("r", encoding="utf-8") as f:
|
|
114
|
+
dashboard_html = f.read()
|
|
115
|
+
dashboard_html = dashboard_html.replace(
|
|
116
|
+
"<!--FULL_DOSSIER_LINK_PLACEHOLDER-->",
|
|
117
|
+
'<div class="text-center">'
|
|
118
|
+
'<a href="./full_dossier_report.html" '
|
|
119
|
+
'class="inline-block bg-rtd-accent text-white py-3 px-6 '
|
|
120
|
+
"rounded-lg shadow-md hover:bg-rtd-secondary "
|
|
121
|
+
'transition-colors duration-200 text-lg font-semibold mt-8">'
|
|
122
|
+
"View Full Comprehensive Dossier (Printable)</a></div>",
|
|
123
|
+
)
|
|
124
|
+
with dashboard_path.open("w", encoding="utf-8") as f:
|
|
125
|
+
f.write(dashboard_html)
|
|
126
|
+
console.print(Panel("Comprehensive dossier generated!", style="bold green"))
|
|
127
|
+
|
|
128
|
+
# Open the main dashboard if requested
|
|
129
|
+
if open:
|
|
130
|
+
import webbrowser
|
|
131
|
+
|
|
132
|
+
webbrowser.open(dashboard_path.resolve().as_uri())
|
|
133
|
+
|
|
134
|
+
console.print(
|
|
135
|
+
Panel(
|
|
136
|
+
f"Dossier generated successfully at {output_dir / 'index.html'}",
|
|
137
|
+
style="bold green",
|
|
138
|
+
)
|
|
139
|
+
)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Export commands for microlens-submit CLI."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
|
|
10
|
+
from microlens_submit.utils import load
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def export(
|
|
16
|
+
output_path: Path,
|
|
17
|
+
project_path: Path = typer.Argument(Path("."), help="Project directory"),
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Generate a zip archive containing all active solutions.
|
|
20
|
+
|
|
21
|
+
This command creates a submission-ready archive. Unlike save operations,
|
|
22
|
+
export requires all validation checks to pass (complete team info,
|
|
23
|
+
hardware info, valid parameters, etc.) since this is for actual submission.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
output_path: Path for the output zip file
|
|
27
|
+
project_path: Directory containing the submission project
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
# Export for submission (requires complete submission)
|
|
31
|
+
microlens-submit export submission.zip ./my_project
|
|
32
|
+
|
|
33
|
+
Note:
|
|
34
|
+
Export is strict and requires complete submissions. Use save operations
|
|
35
|
+
for saving incomplete work during development.
|
|
36
|
+
"""
|
|
37
|
+
sub = load(str(project_path))
|
|
38
|
+
sub.export(str(output_path))
|
|
39
|
+
console.print(Panel(f"Exported submission to {output_path}", style="bold green"))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def remove_event(
|
|
43
|
+
event_id: str,
|
|
44
|
+
force: bool = typer.Option(False, "--force", help="Force removal even if event has saved solutions"),
|
|
45
|
+
project_path: Path = typer.Argument(Path("."), help="Project directory"),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Remove an entire event and all its solutions from the submission."""
|
|
48
|
+
submission = load(str(project_path))
|
|
49
|
+
|
|
50
|
+
if event_id not in submission.events:
|
|
51
|
+
typer.echo(f"❌ Event '{event_id}' not found in submission")
|
|
52
|
+
raise typer.Exit(1)
|
|
53
|
+
|
|
54
|
+
event = submission.events[event_id]
|
|
55
|
+
solution_count = len(event.solutions)
|
|
56
|
+
|
|
57
|
+
if not force:
|
|
58
|
+
typer.echo(f"⚠️ This will permanently remove event '{event_id}' " f"and all {solution_count} solutions.")
|
|
59
|
+
typer.echo(" This action cannot be undone.")
|
|
60
|
+
confirm = typer.confirm("Are you sure you want to continue?")
|
|
61
|
+
if not confirm:
|
|
62
|
+
typer.echo("❌ Operation cancelled")
|
|
63
|
+
raise typer.Exit(0)
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
removed = submission.remove_event(event_id, force=force)
|
|
67
|
+
if removed:
|
|
68
|
+
typer.echo(f"✅ Removed event '{event_id}' and all {solution_count} solutions")
|
|
69
|
+
submission.save()
|
|
70
|
+
else:
|
|
71
|
+
typer.echo(f"❌ Failed to remove event '{event_id}'")
|
|
72
|
+
raise typer.Exit(1)
|
|
73
|
+
except ValueError as e:
|
|
74
|
+
typer.echo(f"❌ Cannot remove event: {e}")
|
|
75
|
+
raise typer.Exit(1)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def set_repo_url(
|
|
79
|
+
repo_url: str = typer.Argument(..., help="GitHub repository URL (e.g. https://github.com/owner/repo)"),
|
|
80
|
+
project_path: Path = typer.Argument(Path("."), help="Project directory"),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Set or update the GitHub repository URL in the submission metadata."""
|
|
83
|
+
sub = load(str(project_path))
|
|
84
|
+
sub.repo_url = repo_url
|
|
85
|
+
sub.save()
|
|
86
|
+
console.print(
|
|
87
|
+
Panel(
|
|
88
|
+
f"Set repo_url to {repo_url} in {project_path}/submission.json",
|
|
89
|
+
style="bold green",
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def set_hardware_info(
|
|
95
|
+
cpu: Optional[str] = typer.Option(None, "--cpu", help="CPU model/description"),
|
|
96
|
+
cpu_details: Optional[str] = typer.Option(None, "--cpu-details", help="Detailed CPU information"),
|
|
97
|
+
memory_gb: Optional[float] = typer.Option(None, "--memory-gb", help="Memory in GB"),
|
|
98
|
+
ram_gb: Optional[float] = typer.Option(None, "--ram-gb", help="RAM in GB (alternative to --memory-gb)"),
|
|
99
|
+
platform: Optional[str] = typer.Option(
|
|
100
|
+
None,
|
|
101
|
+
"--platform",
|
|
102
|
+
help="Platform description (e.g., 'Local Analysis', 'Roman Nexus')",
|
|
103
|
+
),
|
|
104
|
+
nexus_image: Optional[str] = typer.Option(None, "--nexus-image", help="Roman Nexus image identifier"),
|
|
105
|
+
clear: bool = typer.Option(False, "--clear", help="Clear all existing hardware info"),
|
|
106
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be changed without saving"),
|
|
107
|
+
project_path: Path = typer.Argument(Path("."), help="Project directory"),
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Set or update hardware information in the submission metadata."""
|
|
110
|
+
sub = load(str(project_path))
|
|
111
|
+
|
|
112
|
+
# Initialize hardware_info if it doesn't exist
|
|
113
|
+
if sub.hardware_info is None:
|
|
114
|
+
sub.hardware_info = {}
|
|
115
|
+
|
|
116
|
+
changes = []
|
|
117
|
+
|
|
118
|
+
# Clear existing info if requested
|
|
119
|
+
if clear:
|
|
120
|
+
if sub.hardware_info:
|
|
121
|
+
changes.append("Clear all existing hardware info")
|
|
122
|
+
sub.hardware_info = {}
|
|
123
|
+
|
|
124
|
+
# Set new values
|
|
125
|
+
if cpu_details is not None:
|
|
126
|
+
if sub.hardware_info.get("cpu_details") != cpu_details:
|
|
127
|
+
changes.append(f"Set cpu_details: {cpu_details}")
|
|
128
|
+
sub.hardware_info["cpu_details"] = cpu_details
|
|
129
|
+
elif cpu is not None:
|
|
130
|
+
if sub.hardware_info.get("cpu") != cpu:
|
|
131
|
+
changes.append(f"Set cpu: {cpu}")
|
|
132
|
+
sub.hardware_info["cpu"] = cpu
|
|
133
|
+
|
|
134
|
+
if memory_gb is not None:
|
|
135
|
+
if sub.hardware_info.get("memory_gb") != memory_gb:
|
|
136
|
+
changes.append(f"Set memory_gb: {memory_gb}")
|
|
137
|
+
sub.hardware_info["memory_gb"] = memory_gb
|
|
138
|
+
elif ram_gb is not None:
|
|
139
|
+
if sub.hardware_info.get("ram_gb") != ram_gb:
|
|
140
|
+
changes.append(f"Set ram_gb: {ram_gb}")
|
|
141
|
+
sub.hardware_info["ram_gb"] = ram_gb
|
|
142
|
+
|
|
143
|
+
if platform is not None:
|
|
144
|
+
if sub.hardware_info.get("platform") != platform:
|
|
145
|
+
changes.append(f"Set platform: {platform}")
|
|
146
|
+
sub.hardware_info["platform"] = platform
|
|
147
|
+
|
|
148
|
+
if nexus_image is not None:
|
|
149
|
+
if sub.hardware_info.get("nexus_image") != nexus_image:
|
|
150
|
+
changes.append(f"Set nexus_image: {nexus_image}")
|
|
151
|
+
sub.hardware_info["nexus_image"] = nexus_image
|
|
152
|
+
|
|
153
|
+
# Show dry run results
|
|
154
|
+
if dry_run:
|
|
155
|
+
if changes:
|
|
156
|
+
console.print(Panel("Hardware info changes (dry run):", style="cyan"))
|
|
157
|
+
for change in changes:
|
|
158
|
+
console.print(f" • {change}")
|
|
159
|
+
console.print(f"\nNew hardware_info: {sub.hardware_info}")
|
|
160
|
+
else:
|
|
161
|
+
console.print(Panel("No changes would be made", style="yellow"))
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
# Apply changes
|
|
165
|
+
if changes:
|
|
166
|
+
sub.save()
|
|
167
|
+
console.print(
|
|
168
|
+
Panel(
|
|
169
|
+
f"Updated hardware info in {project_path}/submission.json",
|
|
170
|
+
style="bold green",
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
for change in changes:
|
|
174
|
+
console.print(f" • {change}")
|
|
175
|
+
console.print(f"\nCurrent hardware_info: {sub.hardware_info}")
|
|
176
|
+
else:
|
|
177
|
+
console.print(Panel("No changes made", style="yellow"))
|