microlens-submit 0.16.4__py3-none-any.whl → 0.16.5__py3-none-any.whl
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/__init__.py +1 -1
- microlens_submit/dossier/event_page.py +20 -4
- microlens_submit/dossier/full_report.py +42 -3
- microlens_submit/dossier/solution_page.py +44 -5
- microlens_submit/dossier/utils.py +63 -0
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/METADATA +5 -1
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/RECORD +11 -11
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/WHEEL +1 -1
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/entry_points.txt +0 -0
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/licenses/LICENSE +0 -0
- {microlens_submit-0.16.4.dist-info → microlens_submit-0.16.5.dist-info}/top_level.txt +0 -0
microlens_submit/__init__.py
CHANGED
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from .. import __version__
|
|
13
13
|
from ..models import Event, Submission
|
|
14
14
|
from .solution_page import generate_solution_page
|
|
15
|
+
from .utils import resolve_dossier_asset_path
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def generate_event_page(event: Event, submission: Submission, output_dir: Path) -> None:
|
|
@@ -50,7 +51,17 @@ def generate_event_page(event: Event, submission: Submission, output_dir: Path)
|
|
|
50
51
|
to individual solution pages.
|
|
51
52
|
"""
|
|
52
53
|
# Prepare output directory (already created)
|
|
53
|
-
|
|
54
|
+
project_root = Path(submission.project_path)
|
|
55
|
+
event_data_link = ""
|
|
56
|
+
if hasattr(event, "event_data_path") and event.event_data_path:
|
|
57
|
+
event_data_link = resolve_dossier_asset_path(
|
|
58
|
+
event.event_data_path,
|
|
59
|
+
project_root,
|
|
60
|
+
output_dir,
|
|
61
|
+
subdir="event-data",
|
|
62
|
+
prefix=f"{event.event_id}_event_data",
|
|
63
|
+
)
|
|
64
|
+
html = _generate_event_page_content(event, submission, event_data_link=event_data_link)
|
|
54
65
|
with (output_dir / f"{event.event_id}.html").open("w", encoding="utf-8") as f:
|
|
55
66
|
f.write(html)
|
|
56
67
|
|
|
@@ -59,7 +70,12 @@ def generate_event_page(event: Event, submission: Submission, output_dir: Path)
|
|
|
59
70
|
generate_solution_page(sol, event, submission, output_dir)
|
|
60
71
|
|
|
61
72
|
|
|
62
|
-
def _generate_event_page_content(
|
|
73
|
+
def _generate_event_page_content(
|
|
74
|
+
event: Event,
|
|
75
|
+
submission: Submission,
|
|
76
|
+
*,
|
|
77
|
+
event_data_link: str = "",
|
|
78
|
+
) -> str:
|
|
63
79
|
"""Generate the HTML content for an event dossier page.
|
|
64
80
|
|
|
65
81
|
Creates the complete HTML content for a single event page, including
|
|
@@ -163,10 +179,10 @@ def _generate_event_page_content(event: Event, submission: Submission) -> str:
|
|
|
163
179
|
)
|
|
164
180
|
# Optional raw data link
|
|
165
181
|
raw_data_html = ""
|
|
166
|
-
if
|
|
182
|
+
if event_data_link:
|
|
167
183
|
raw_data_html = (
|
|
168
184
|
f'<p class="text-rtd-text">Raw Event Data: '
|
|
169
|
-
f'<a href="{
|
|
185
|
+
f'<a href="{event_data_link}" '
|
|
170
186
|
f'class="text-rtd-accent hover:underline">Download Data</a></p>'
|
|
171
187
|
)
|
|
172
188
|
# HTML content
|
|
@@ -15,6 +15,7 @@ from ..models.solution import Solution
|
|
|
15
15
|
from .dashboard import _generate_dashboard_content
|
|
16
16
|
from .event_page import _generate_event_page_content
|
|
17
17
|
from .solution_page import _generate_solution_page_content
|
|
18
|
+
from .utils import resolve_dossier_asset_path
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def generate_full_dossier_report_html(submission: Submission, output_dir: Path) -> None:
|
|
@@ -63,19 +64,57 @@ def generate_full_dossier_report_html(submission: Submission, output_dir: Path)
|
|
|
63
64
|
all_html_sections.append('<hr class="my-8 border-t-2 border-rtd-accent">') # Divider after dashboard
|
|
64
65
|
|
|
65
66
|
# Events and solutions
|
|
67
|
+
project_root = Path(submission.project_path)
|
|
66
68
|
for event in submission.events.values():
|
|
67
|
-
|
|
69
|
+
event_data_link = ""
|
|
70
|
+
if hasattr(event, "event_data_path") and event.event_data_path:
|
|
71
|
+
event_data_link = resolve_dossier_asset_path(
|
|
72
|
+
event.event_data_path,
|
|
73
|
+
project_root,
|
|
74
|
+
output_dir,
|
|
75
|
+
subdir="event-data",
|
|
76
|
+
prefix=f"{event.event_id}_event_data",
|
|
77
|
+
)
|
|
78
|
+
event_html = _generate_event_page_content(event, submission, event_data_link=event_data_link)
|
|
68
79
|
event_body = extract_main_content_body(event_html, section_type="event", section_id=event.event_id)
|
|
69
80
|
all_html_sections.append(event_body)
|
|
70
81
|
all_html_sections.append('<hr class="my-8 border-t-2 border-rtd-accent">') # Divider after event
|
|
71
82
|
|
|
72
83
|
for sol in event.get_active_solutions():
|
|
73
|
-
|
|
84
|
+
lc_plot = resolve_dossier_asset_path(
|
|
85
|
+
sol.lightcurve_plot_path,
|
|
86
|
+
project_root,
|
|
87
|
+
output_dir,
|
|
88
|
+
subdir="plots",
|
|
89
|
+
prefix=f"{event.event_id}_{sol.solution_id}_lightcurve",
|
|
90
|
+
)
|
|
91
|
+
lens_plot = resolve_dossier_asset_path(
|
|
92
|
+
sol.lens_plane_plot_path,
|
|
93
|
+
project_root,
|
|
94
|
+
output_dir,
|
|
95
|
+
subdir="plots",
|
|
96
|
+
prefix=f"{event.event_id}_{sol.solution_id}_lens",
|
|
97
|
+
)
|
|
98
|
+
posterior = resolve_dossier_asset_path(
|
|
99
|
+
sol.posterior_path,
|
|
100
|
+
project_root,
|
|
101
|
+
output_dir,
|
|
102
|
+
subdir="posteriors",
|
|
103
|
+
prefix=f"{event.event_id}_{sol.solution_id}_posterior",
|
|
104
|
+
)
|
|
105
|
+
sol_html = _generate_solution_page_content(
|
|
106
|
+
sol,
|
|
107
|
+
event,
|
|
108
|
+
submission,
|
|
109
|
+
lc_plot=lc_plot,
|
|
110
|
+
lens_plot=lens_plot,
|
|
111
|
+
posterior=posterior,
|
|
112
|
+
)
|
|
74
113
|
sol_body = extract_main_content_body(
|
|
75
114
|
sol_html,
|
|
76
115
|
section_type="solution",
|
|
77
116
|
section_id=sol.solution_id,
|
|
78
|
-
project_root=
|
|
117
|
+
project_root=project_root,
|
|
79
118
|
solution=sol,
|
|
80
119
|
)
|
|
81
120
|
all_html_sections.append(sol_body)
|
|
@@ -8,6 +8,7 @@ notes rendering, and evaluator-only sections.
|
|
|
8
8
|
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from pathlib import Path
|
|
11
|
+
from typing import Optional
|
|
11
12
|
|
|
12
13
|
import markdown
|
|
13
14
|
|
|
@@ -15,6 +16,7 @@ from .. import __version__
|
|
|
15
16
|
from ..models.event import Event
|
|
16
17
|
from ..models.solution import Solution
|
|
17
18
|
from ..models.submission import Submission
|
|
19
|
+
from .utils import resolve_dossier_asset_path
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
def generate_solution_page(solution: Solution, event: Event, submission: Submission, output_dir: Path) -> None:
|
|
@@ -55,12 +57,49 @@ def generate_solution_page(solution: Solution, event: Event, submission: Submiss
|
|
|
55
57
|
Notes are rendered with syntax highlighting for code blocks.
|
|
56
58
|
"""
|
|
57
59
|
# Prepare output directory (already created)
|
|
58
|
-
|
|
60
|
+
project_root = Path(submission.project_path)
|
|
61
|
+
lc_plot = resolve_dossier_asset_path(
|
|
62
|
+
solution.lightcurve_plot_path,
|
|
63
|
+
project_root,
|
|
64
|
+
output_dir,
|
|
65
|
+
subdir="plots",
|
|
66
|
+
prefix=f"{event.event_id}_{solution.solution_id}_lightcurve",
|
|
67
|
+
)
|
|
68
|
+
lens_plot = resolve_dossier_asset_path(
|
|
69
|
+
solution.lens_plane_plot_path,
|
|
70
|
+
project_root,
|
|
71
|
+
output_dir,
|
|
72
|
+
subdir="plots",
|
|
73
|
+
prefix=f"{event.event_id}_{solution.solution_id}_lens",
|
|
74
|
+
)
|
|
75
|
+
posterior = resolve_dossier_asset_path(
|
|
76
|
+
solution.posterior_path,
|
|
77
|
+
project_root,
|
|
78
|
+
output_dir,
|
|
79
|
+
subdir="posteriors",
|
|
80
|
+
prefix=f"{event.event_id}_{solution.solution_id}_posterior",
|
|
81
|
+
)
|
|
82
|
+
html = _generate_solution_page_content(
|
|
83
|
+
solution,
|
|
84
|
+
event,
|
|
85
|
+
submission,
|
|
86
|
+
lc_plot=lc_plot,
|
|
87
|
+
lens_plot=lens_plot,
|
|
88
|
+
posterior=posterior,
|
|
89
|
+
)
|
|
59
90
|
with (output_dir / f"{solution.solution_id}.html").open("w", encoding="utf-8") as f:
|
|
60
91
|
f.write(html)
|
|
61
92
|
|
|
62
93
|
|
|
63
|
-
def _generate_solution_page_content(
|
|
94
|
+
def _generate_solution_page_content(
|
|
95
|
+
solution: Solution,
|
|
96
|
+
event: Event,
|
|
97
|
+
submission: Submission,
|
|
98
|
+
*,
|
|
99
|
+
lc_plot: Optional[str] = None,
|
|
100
|
+
lens_plot: Optional[str] = None,
|
|
101
|
+
posterior: Optional[str] = None,
|
|
102
|
+
) -> str:
|
|
64
103
|
"""Generate the HTML content for a solution dossier page.
|
|
65
104
|
|
|
66
105
|
Creates the complete HTML content for a single solution page, including
|
|
@@ -138,9 +177,9 @@ def _generate_solution_page_content(solution: Solution, event: Event, submission
|
|
|
138
177
|
# Higher-order effects
|
|
139
178
|
hoe_str = ", ".join(solution.higher_order_effects) if solution.higher_order_effects else "None"
|
|
140
179
|
# Plot paths (relative to solution page)
|
|
141
|
-
lc_plot = solution.lightcurve_plot_path or ""
|
|
142
|
-
lens_plot = solution.lens_plane_plot_path or ""
|
|
143
|
-
posterior = solution.posterior_path or ""
|
|
180
|
+
lc_plot = lc_plot if lc_plot is not None else (solution.lightcurve_plot_path or "")
|
|
181
|
+
lens_plot = lens_plot if lens_plot is not None else (solution.lens_plane_plot_path or "")
|
|
182
|
+
posterior = posterior if posterior is not None else (solution.posterior_path or "")
|
|
144
183
|
# Physical parameters table
|
|
145
184
|
phys_rows = []
|
|
146
185
|
phys = solution.physical_parameters or {}
|
|
@@ -6,7 +6,11 @@ generation package, including hardware formatting, GitHub URL parsing,
|
|
|
6
6
|
and other helper functions.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import hashlib
|
|
10
|
+
import shutil
|
|
11
|
+
from pathlib import Path
|
|
9
12
|
from typing import Any, Dict, Optional
|
|
13
|
+
from urllib.parse import quote, urlparse
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
def format_hardware_info(hardware_info: Optional[Dict[str, Any]]) -> str:
|
|
@@ -109,3 +113,62 @@ def extract_github_repo_name(repo_url: str) -> str:
|
|
|
109
113
|
return f"{parts[-2]}/{parts[-1]}"
|
|
110
114
|
|
|
111
115
|
return None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def resolve_dossier_asset_path(
|
|
119
|
+
path_value: Optional[str],
|
|
120
|
+
project_root: Path,
|
|
121
|
+
output_dir: Path,
|
|
122
|
+
*,
|
|
123
|
+
subdir: str,
|
|
124
|
+
prefix: Optional[str] = None,
|
|
125
|
+
) -> str:
|
|
126
|
+
"""Resolve and copy a local asset into the dossier assets folder.
|
|
127
|
+
|
|
128
|
+
If the input path is a URL, it is returned unchanged. If it is a local
|
|
129
|
+
filesystem path, it is resolved relative to the project root, copied into
|
|
130
|
+
the dossier assets folder, and returned as a URL-encoded relative path.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
path_value: The original path or URL string.
|
|
134
|
+
project_root: Root directory of the submission project.
|
|
135
|
+
output_dir: Dossier output directory containing the HTML files.
|
|
136
|
+
subdir: Subdirectory under assets/ for the copied file.
|
|
137
|
+
prefix: Optional prefix for the copied file name to avoid collisions.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
str: A URL or a relative path suitable for HTML src/href attributes.
|
|
141
|
+
"""
|
|
142
|
+
if not path_value:
|
|
143
|
+
return ""
|
|
144
|
+
|
|
145
|
+
parsed = urlparse(path_value)
|
|
146
|
+
if parsed.scheme in {"http", "https", "data"}:
|
|
147
|
+
return path_value
|
|
148
|
+
|
|
149
|
+
if parsed.scheme == "file":
|
|
150
|
+
source_path = Path(parsed.path)
|
|
151
|
+
else:
|
|
152
|
+
source_path = Path(path_value).expanduser()
|
|
153
|
+
|
|
154
|
+
if not source_path.is_absolute():
|
|
155
|
+
source_path = (project_root / source_path).resolve()
|
|
156
|
+
else:
|
|
157
|
+
source_path = source_path.resolve()
|
|
158
|
+
|
|
159
|
+
if not source_path.exists():
|
|
160
|
+
return path_value
|
|
161
|
+
|
|
162
|
+
assets_dir = output_dir / "assets" / subdir
|
|
163
|
+
assets_dir.mkdir(parents=True, exist_ok=True)
|
|
164
|
+
|
|
165
|
+
digest = hashlib.sha1(str(source_path).encode("utf-8")).hexdigest()[:8]
|
|
166
|
+
safe_prefix = prefix or "asset"
|
|
167
|
+
dest_name = f"{safe_prefix}_{digest}_{source_path.name}"
|
|
168
|
+
dest_path = assets_dir / dest_name
|
|
169
|
+
|
|
170
|
+
if not dest_path.exists():
|
|
171
|
+
shutil.copy2(source_path, dest_path)
|
|
172
|
+
|
|
173
|
+
rel_path = dest_path.relative_to(output_dir).as_posix()
|
|
174
|
+
return quote(rel_path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: microlens-submit
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.5
|
|
4
4
|
Summary: A tool for managing and submitting microlensing solutions
|
|
5
5
|
Home-page: https://github.com/AmberLee2427/microlens-submit
|
|
6
6
|
Author: Amber Malpas
|
|
@@ -95,6 +95,10 @@ The CLI is the recommended way to interact with your submission project.
|
|
|
95
95
|
|
|
96
96
|
You can pass ``--no-color`` to any command if your terminal does not support ANSI colors.
|
|
97
97
|
|
|
98
|
+
**Windows note:** If ``microlens-submit`` is not found after ``pip install``, your Python Scripts folder is likely missing from PATH.
|
|
99
|
+
Try ``py -m pip install microlens-submit`` and run ``py -m microlens_submit.cli --help``, or add the Scripts path shown by
|
|
100
|
+
``py -m pip show -f microlens-submit`` to PATH.
|
|
101
|
+
|
|
98
102
|
1. Initialize your project:
|
|
99
103
|
|
|
100
104
|
```bash
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
microlens_submit/__init__.py,sha256=
|
|
1
|
+
microlens_submit/__init__.py,sha256=fyqDCZ_UClGfQ7zkhWJC8HFJqh2RQDudEXw2LwhLIYs,399
|
|
2
2
|
microlens_submit/error_messages.py,sha256=8Wzx1NQiAF7hUOjlt-uGhtPC7akknv_PDkokoxhWquk,10411
|
|
3
3
|
microlens_submit/text_symbols.py,sha256=PbQSkqF_FwTBs45TkUL0zZl74IYDz7L4xVxy8eKxQsU,3146
|
|
4
4
|
microlens_submit/tier_validation.py,sha256=FbVHQwItqQnrCeKhkQSgQmMT6dgreTGOptRRYf-AYVE,6649
|
|
@@ -17,17 +17,17 @@ microlens_submit/cli/commands/solutions.py,sha256=GvbAiiTaCaqcDRHOAReaMY-gDLlahR
|
|
|
17
17
|
microlens_submit/cli/commands/validation.py,sha256=1M8mYSNopsA30u3S-yFBd3iJZxsDoNa0vhwo9brJ1VQ,9028
|
|
18
18
|
microlens_submit/dossier/__init__.py,sha256=INAacbrY0Wi5ueH8c7b156bGzelyUFcynbE7_YRiku0,1948
|
|
19
19
|
microlens_submit/dossier/dashboard.py,sha256=4OvTUCxIC4LbAqKwimIFhi65fNo5MMJswiQ5OWtyWFA,19907
|
|
20
|
-
microlens_submit/dossier/event_page.py,sha256=
|
|
21
|
-
microlens_submit/dossier/full_report.py,sha256=
|
|
22
|
-
microlens_submit/dossier/solution_page.py,sha256
|
|
23
|
-
microlens_submit/dossier/utils.py,sha256
|
|
20
|
+
microlens_submit/dossier/event_page.py,sha256=7740o3tpW9Urv7GSzYdp2TiphvDi6U7XnjlLZYipvLw,14878
|
|
21
|
+
microlens_submit/dossier/full_report.py,sha256=cNkaUML93oRnARp4VnLkbRMudrByWyj06ohvmH4Qcq0,14310
|
|
22
|
+
microlens_submit/dossier/solution_page.py,sha256=-5kgkOZ9ziNRNAFpVeT_9-6aCcQRL4vv9APopKDFeAw,24748
|
|
23
|
+
microlens_submit/dossier/utils.py,sha256=-DbWByBMsEeQZ-eUyRT74O_3lakE1vHKUD62jPj1_t4,5839
|
|
24
24
|
microlens_submit/models/__init__.py,sha256=1sHFjAWyFtGgQBRSo8lBYiPzToo4tIoHP3uBjtgJSPY,861
|
|
25
25
|
microlens_submit/models/event.py,sha256=ifQqE7d7PJTTI9lGylwWV3EGxgyyNGiJtHbm_DLmuys,17105
|
|
26
26
|
microlens_submit/models/solution.py,sha256=ollTpKv8zMSEqIL2Q9gXJTbaX0fWZt6rg76edBmYOWQ,23629
|
|
27
27
|
microlens_submit/models/submission.py,sha256=f_ewUFhXghnh-pn077bkfBg_6jVbcN_jRhy2wVdKUgk,27941
|
|
28
|
-
microlens_submit-0.16.
|
|
29
|
-
microlens_submit-0.16.
|
|
30
|
-
microlens_submit-0.16.
|
|
31
|
-
microlens_submit-0.16.
|
|
32
|
-
microlens_submit-0.16.
|
|
33
|
-
microlens_submit-0.16.
|
|
28
|
+
microlens_submit-0.16.5.dist-info/licenses/LICENSE,sha256=cy1qkVR-kGxD6FXVsparmU2vHJXYeoyAAHv6SgT67sw,1069
|
|
29
|
+
microlens_submit-0.16.5.dist-info/METADATA,sha256=4mSk_0rksMNxU7NOl2dEA7J73Zvb1SwJ-DKGW00WPkM,10673
|
|
30
|
+
microlens_submit-0.16.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
31
|
+
microlens_submit-0.16.5.dist-info/entry_points.txt,sha256=kA85yhxYrpQnUvVZCRS2giz52gaf1ZOfZFjY4RHIZ2s,62
|
|
32
|
+
microlens_submit-0.16.5.dist-info/top_level.txt,sha256=uJ9_bADYRySlhEpP-8vTm90ZLV2SrKEzutAaRx8WF0k,17
|
|
33
|
+
microlens_submit-0.16.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|