microlens-submit 0.12.2__py3-none-any.whl → 0.16.1__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.
Files changed (34) hide show
  1. microlens_submit/__init__.py +7 -157
  2. microlens_submit/cli/__init__.py +5 -0
  3. microlens_submit/cli/__main__.py +6 -0
  4. microlens_submit/cli/commands/__init__.py +1 -0
  5. microlens_submit/cli/commands/dossier.py +139 -0
  6. microlens_submit/cli/commands/export.py +177 -0
  7. microlens_submit/cli/commands/init.py +172 -0
  8. microlens_submit/cli/commands/solutions.py +722 -0
  9. microlens_submit/cli/commands/validation.py +241 -0
  10. microlens_submit/cli/main.py +120 -0
  11. microlens_submit/dossier/__init__.py +51 -0
  12. microlens_submit/dossier/dashboard.py +503 -0
  13. microlens_submit/dossier/event_page.py +370 -0
  14. microlens_submit/dossier/full_report.py +330 -0
  15. microlens_submit/dossier/solution_page.py +534 -0
  16. microlens_submit/dossier/utils.py +111 -0
  17. microlens_submit/error_messages.py +283 -0
  18. microlens_submit/models/__init__.py +28 -0
  19. microlens_submit/models/event.py +406 -0
  20. microlens_submit/models/solution.py +569 -0
  21. microlens_submit/models/submission.py +569 -0
  22. microlens_submit/tier_validation.py +208 -0
  23. microlens_submit/utils.py +373 -0
  24. microlens_submit/validate_parameters.py +478 -180
  25. {microlens_submit-0.12.2.dist-info → microlens_submit-0.16.1.dist-info}/METADATA +52 -14
  26. microlens_submit-0.16.1.dist-info/RECORD +32 -0
  27. microlens_submit/api.py +0 -1257
  28. microlens_submit/cli.py +0 -1803
  29. microlens_submit/dossier.py +0 -1443
  30. microlens_submit-0.12.2.dist-info/RECORD +0 -13
  31. {microlens_submit-0.12.2.dist-info → microlens_submit-0.16.1.dist-info}/WHEEL +0 -0
  32. {microlens_submit-0.12.2.dist-info → microlens_submit-0.16.1.dist-info}/entry_points.txt +0 -0
  33. {microlens_submit-0.12.2.dist-info → microlens_submit-0.16.1.dist-info}/licenses/LICENSE +0 -0
  34. {microlens_submit-0.12.2.dist-info → microlens_submit-0.16.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,283 @@
1
+ """
2
+ Enhanced error messaging for microlens-submit.
3
+
4
+ This module provides improved error messages with suggestions and context
5
+ to help users understand and fix issues more easily.
6
+ """
7
+
8
+ import re
9
+ from typing import Dict, List, Optional
10
+
11
+
12
+ def get_model_type_suggestions(invalid_type: str) -> List[str]:
13
+ """Get suggestions for model type corrections."""
14
+ valid_types = ["1S1L", "1S2L", "2S1L", "2S2L", "1S3L", "2S3L", "other"]
15
+
16
+ # Common typos and their corrections
17
+ common_typos = {
18
+ "1s1l": "1S1L",
19
+ "1s2l": "1S2L",
20
+ "2s1l": "2S1L",
21
+ "2s2l": "2S2L",
22
+ "1s3l": "1S3L",
23
+ "2s3l": "2S3L",
24
+ "1S1l": "1S1L",
25
+ "1S2l": "1S2L",
26
+ "2S1l": "2S1L",
27
+ "2S2l": "2S2L",
28
+ "1S3l": "1S3L",
29
+ "2S3l": "2S3L",
30
+ "1sl1": "1S1L",
31
+ "1sl2": "1S2L",
32
+ "2sl1": "2S1L",
33
+ "2sl2": "2S2L",
34
+ "1sl3": "1S3L",
35
+ "2sl3": "2S3L",
36
+ }
37
+
38
+ suggestions = []
39
+
40
+ # Check for exact typo match
41
+ if invalid_type in common_typos:
42
+ suggestions.append(f"Did you mean '{common_typos[invalid_type]}'?")
43
+
44
+ # Check for similar patterns
45
+ if invalid_type.upper() in valid_types:
46
+ suggestions.append(f"Model types are case-sensitive. Try '{invalid_type.upper()}'")
47
+
48
+ # Check for partial matches
49
+ for valid_type in valid_types:
50
+ if valid_type.lower() in invalid_type.lower() or invalid_type.lower() in valid_type.lower():
51
+ if valid_type not in suggestions:
52
+ suggestions.append(f"Did you mean '{valid_type}'?")
53
+
54
+ return suggestions
55
+
56
+
57
+ def get_parameter_suggestions(model_type: str, user_param: str) -> List[str]:
58
+ """Get suggestions for missing parameter corrections."""
59
+ # Common parameter typos and their corrections
60
+ common_typos = {
61
+ "t0": ["t_0", "T0", "T_0"],
62
+ "u0": ["u_0", "U0", "U_0"],
63
+ "tE": ["te", "TE", "t_e", "T_E", "einstein_time"],
64
+ "s": ["sep", "separation", "S"],
65
+ "q": ["mass_ratio", "Q", "ratio"],
66
+ "alpha": ["angle", "ANGLE", "ALPHA"],
67
+ "piEN": ["pien", "PIEN", "pi_en", "PI_EN"],
68
+ "piEE": ["piee", "PIEE", "pi_ee", "PI_EE"],
69
+ }
70
+
71
+ suggestions = []
72
+ # If the user_param matches a typo for any canonical param,
73
+ # suggest the canonical param
74
+ for canonical, typos in common_typos.items():
75
+ for typo in typos:
76
+ if user_param.lower() == typo.lower():
77
+ suggestions.append(f"Did you mean '{canonical}' instead of '{user_param}'?")
78
+ # Also suggest case sensitivity if relevant
79
+ for canonical in common_typos.keys():
80
+ if user_param.lower() == canonical.lower() and user_param != canonical:
81
+ suggestions.append(f"Parameter names are case-sensitive. Try '{canonical}'")
82
+ return suggestions
83
+
84
+
85
+ def get_higher_order_effect_suggestions(invalid_effect: str) -> List[str]:
86
+ """Get suggestions for higher-order effect corrections."""
87
+ valid_effects = [
88
+ "parallax",
89
+ "finite-source",
90
+ "lens-orbital-motion",
91
+ "xallarap",
92
+ "gaussian-process",
93
+ "stellar-rotation",
94
+ "fitted-limb-darkening",
95
+ ]
96
+
97
+ # Common typos and their corrections
98
+ common_typos = {
99
+ "parallax": ["paralax", "parallax", "PARALLAX"],
100
+ "finite-source": [
101
+ "finite_source",
102
+ "finite source",
103
+ "finite-source",
104
+ "FINITE-SOURCE",
105
+ ],
106
+ "lens-orbital-motion": [
107
+ "lens_orbital_motion",
108
+ "lens orbital motion",
109
+ "LENS-ORBITAL-MOTION",
110
+ ],
111
+ "xallarap": ["xallarap", "XALLARAP", "xallarap"],
112
+ "gaussian-process": [
113
+ "gaussian_process",
114
+ "gaussian process",
115
+ "GAUSSIAN-PROCESS",
116
+ ],
117
+ "stellar-rotation": [
118
+ "stellar_rotation",
119
+ "stellar rotation",
120
+ "STELLAR-ROTATION",
121
+ ],
122
+ "fitted-limb-darkening": [
123
+ "fitted_limb_darkening",
124
+ "fitted limb darkening",
125
+ "FITTED-LIMB-DARKENING",
126
+ ],
127
+ }
128
+
129
+ suggestions = []
130
+
131
+ # Check for exact typo match
132
+ if invalid_effect in common_typos:
133
+ for typo in common_typos[invalid_effect]:
134
+ suggestions.append(f"Did you mean '{typo}' instead of '{invalid_effect}'?")
135
+
136
+ # Check for case variations
137
+ if invalid_effect.lower() in [e.lower() for e in valid_effects]:
138
+ for effect in valid_effects:
139
+ if effect.lower() == invalid_effect.lower():
140
+ suggestions.append(f"Effect names are case-sensitive. Try '{effect}'")
141
+ break
142
+
143
+ # Check for partial matches
144
+ for valid_effect in valid_effects:
145
+ if valid_effect.lower() in invalid_effect.lower() or invalid_effect.lower() in valid_effect.lower():
146
+ if valid_effect not in suggestions:
147
+ suggestions.append(f"Did you mean '{valid_effect}'?")
148
+
149
+ return suggestions
150
+
151
+
152
+ def format_validation_message(message: str, suggestions: Optional[List[str]] = None) -> str:
153
+ """Format a validation message with optional suggestions."""
154
+ if not suggestions:
155
+ return message
156
+
157
+ formatted = message
158
+ if len(suggestions) == 1:
159
+ formatted += f"\n💡 Suggestion: {suggestions[0]}"
160
+ else:
161
+ formatted += "\n💡 Suggestions:"
162
+ for suggestion in suggestions:
163
+ formatted += f"\n • {suggestion}"
164
+
165
+ return formatted
166
+
167
+
168
+ def enhance_validation_messages(messages: List[str], model_type: str, parameters: Dict) -> List[str]:
169
+ """Enhance validation messages with helpful suggestions."""
170
+ enhanced_messages = []
171
+
172
+ for message in messages:
173
+ suggestions = []
174
+
175
+ # Check for model type errors
176
+ if "Unknown model type:" in message:
177
+ # Extract the invalid model type from the message
178
+ match = re.search(r"Unknown model type: '([^']+)'", message)
179
+ if match:
180
+ invalid_type = match.group(1)
181
+ suggestions = get_model_type_suggestions(invalid_type)
182
+
183
+ # Check for missing parameter errors
184
+ elif "Missing required core parameter" in message:
185
+ # Extract the missing parameter from the message
186
+ match = re.search(r"Missing required core parameter '([^']+)'", message)
187
+ if match:
188
+ missing_param = match.group(1)
189
+ suggestions = get_parameter_suggestions(model_type, missing_param)
190
+
191
+ # Check for missing higher-order effect parameters
192
+ elif "Missing required parameter" in message and "for effect" in message:
193
+ # Extract the missing parameter and effect from the message
194
+ match = re.search(r"Missing required parameter '([^']+)' for effect '([^']+)'", message)
195
+ if match:
196
+ missing_param = match.group(1)
197
+ suggestions = get_parameter_suggestions(model_type, missing_param)
198
+
199
+ # Check for unknown higher-order effect errors
200
+ elif "Unknown higher-order effect:" in message:
201
+ # Extract the invalid effect from the message
202
+ match = re.search(r"Unknown higher-order effect: '([^']+)'", message)
203
+ if match:
204
+ invalid_effect = match.group(1)
205
+ suggestions = get_higher_order_effect_suggestions(invalid_effect)
206
+
207
+ # Check for unrecognized parameter warnings
208
+ elif "Parameter" in message and "not recognized" in message:
209
+ # Extract the unrecognized parameter from the message
210
+ match = re.search(r"Parameter '([^']+)' not recognized", message)
211
+ if not match:
212
+ # Try with "Warning:" prefix
213
+ match = re.search(r"Warning: Parameter '([^']+)' not recognized", message)
214
+ if match:
215
+ unrecognized_param = match.group(1)
216
+ suggestions = get_parameter_suggestions(model_type, unrecognized_param)
217
+
218
+ enhanced_messages.append(format_validation_message(message, suggestions))
219
+
220
+ return enhanced_messages
221
+
222
+
223
+ def get_quick_fix_suggestions(model_type: str, missing_params: List[str]) -> List[str]:
224
+ """Get quick fix suggestions for common missing parameters."""
225
+ suggestions = []
226
+
227
+ # Common parameter examples for each model type
228
+ model_examples = {
229
+ "1S1L": {"t0": "2459123.5", "u0": "0.1", "tE": "20.0"},
230
+ "1S2L": {
231
+ "t0": "2459123.5",
232
+ "u0": "0.1",
233
+ "tE": "20.0",
234
+ "s": "1.2",
235
+ "q": "0.001",
236
+ "alpha": "45.0",
237
+ },
238
+ "2S1L": {
239
+ "t0": "2459123.5",
240
+ "u0": "0.1",
241
+ "tE": "20.0",
242
+ "q_flux": "0.5",
243
+ "t_star": "0.1",
244
+ },
245
+ }
246
+
247
+ if model_type in model_examples:
248
+ examples = model_examples[model_type]
249
+ for param in missing_params:
250
+ if param in examples:
251
+ suggestions.append(f"Add --param {param}={examples[param]}")
252
+
253
+ return suggestions
254
+
255
+
256
+ def format_cli_error_with_suggestions(error_message: str, context: Dict) -> str:
257
+ """Format CLI errors with contextual suggestions."""
258
+ enhanced = error_message
259
+
260
+ # Add context-specific suggestions
261
+ if "model_type must be one of" in error_message:
262
+ enhanced += "\n\n💡 Quick Start Examples:"
263
+ enhanced += (
264
+ "\n microlens-submit add-solution EVENT123 1S1L " "--param t0=2459123.5 --param u0=0.1 --param tE=20.0"
265
+ )
266
+ enhanced += (
267
+ "\n microlens-submit add-solution EVENT123 1S2L "
268
+ "--param t0=2459123.5 --param u0=0.1 --param tE=20.0 "
269
+ "--param s=1.2 --param q=0.001 --param alpha=45.0"
270
+ )
271
+
272
+ elif "Invalid parameter format" in error_message:
273
+ enhanced += "\n\n�� Parameter Format:"
274
+ enhanced += "\n Use --param name=value (e.g., --param t0=2459123.5)"
275
+ enhanced += "\n Multiple parameters: --param t0=2459123.5 " "--param u0=0.1 --param tE=20.0"
276
+
277
+ elif "Cannot use --param with --params-file" in error_message:
278
+ enhanced += "\n\n💡 Parameter Options:"
279
+ enhanced += "\n Use --param for individual parameters on command line"
280
+ enhanced += "\n Use --params-file for parameters from a JSON/YAML file"
281
+ enhanced += "\n Choose one method, not both"
282
+
283
+ return enhanced
@@ -0,0 +1,28 @@
1
+ """
2
+ Data models for microlens-submit.
3
+
4
+ This package contains the core data models for managing
5
+ microlensing challenge submissions:
6
+ - Solution: Individual model fit with parameters and metadata
7
+ - Event: Container for solutions to a single microlensing event
8
+ - Submission: Top-level container for a submission project
9
+
10
+ Example:
11
+ >>> from microlens_submit.models import Solution, Event, Submission
12
+ >>>
13
+ >>> # Create a submission
14
+ >>> submission = Submission()
15
+ >>> submission.team_name = "Team Alpha"
16
+ >>>
17
+ >>> # Add an event and solution
18
+ >>> event = submission.get_event("EVENT001")
19
+ >>> solution = event.add_solution("1S1L", {"t0": 2459123.5, "u0": 0.1, "tE": 20.0})
20
+ """
21
+
22
+ from .event import Event
23
+ from .solution import Solution
24
+ from .submission import Submission
25
+
26
+ Event.model_rebuild()
27
+
28
+ __all__ = ["Solution", "Event", "Submission"]