Skip to content

Commit 6ee297b

Browse files
Address review comments: fix logging, remove unused imports, fix error message, fix needs init, add html escaping, fix img tags, add tests
Co-authored-by: transientlunatic <4365778+transientlunatic@users.noreply.github.com>
1 parent 3c62aa2 commit 6ee297b

File tree

6 files changed

+94
-18
lines changed

6 files changed

+94
-18
lines changed

asimov/analysis.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"""
2525

2626
import os
27+
import html
2728
import configparser
2829
from copy import deepcopy
2930
import pathlib
@@ -1361,7 +1362,9 @@ def __init__(self, name, pipeline, ledger=None, **kwargs):
13611362
# except KeyError:
13621363
self.logger.warning(f"The pipeline {pipeline} could not be found.")
13631364

1364-
needs_value = self.meta.pop("needs", None)
1365+
# Read 'needs' from kwargs before it gets merged into self.meta so we
1366+
# don't accidentally mutate the class-level meta_defaults dict.
1367+
needs_value = kwargs.pop("needs", None)
13651368
self._needs = cast(List[Any], needs_value) if needs_value is not None else []
13661369

13671370
if "comment" in kwargs:
@@ -1662,14 +1665,15 @@ def html(self):
16621665
# Status badge mapping
16631666
status_badge = status_map.get(self.status, "secondary")
16641667

1668+
safe_name = html.escape(self.name)
16651669
card = f"""
1666-
<div class='project-analysis-card card event-data' id='project-{self.name}'>
1670+
<div class='project-analysis-card card event-data' id='project-{safe_name}'>
16671671
<div class='card-header'>
1668-
<h3 class='card-title'>{self.name}</h3>
1672+
<h3 class='card-title'>{safe_name}</h3>
16691673
"""
16701674

16711675
if self.comment:
1672-
card += f" <p class='text-muted'>{self.comment}</p>\n"
1676+
card += f" <p class='text-muted'>{html.escape(self.comment)}</p>\n"
16731677

16741678
# Status badge
16751679
card += f""" <span class='badge badge-{status_badge}'>{self.status}</span>

asimov/cli/application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def apply_page(file, event=None, ledger=None, update_page=False, name=None, iter
229229
except KeyError as e:
230230
click.echo(
231231
click.style("●", fg="red")
232-
+ f" Could not apply a production, couldn't find the event {event}"
232+
+ f" Could not apply a production, couldn't find the event {event_s}"
233233
)
234234
logger.exception(e)
235235
continue

asimov/event.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -678,16 +678,10 @@ def get_review_indicator(review_status):
678678
rundir = node.rundir if hasattr(node, 'rundir') and node.rundir else ''
679679
approximant = node.meta.get('approximant', '') if hasattr(node, 'meta') else ''
680680

681-
# Get webdir for results links
682-
webdir = ''
683-
if hasattr(node, 'event') and hasattr(node.event, 'webdir') and node.event.webdir:
684-
webdir = node.event.webdir
685-
686681
# Construct potential result page URLs based on pipeline
687682
result_pages = []
688683

689684
# Construct base URL using event name and analysis name
690-
import os
691685
base_url = f"{self.name}/{node.name}"
692686

693687
# Add common result page patterns for different pipelines
@@ -817,7 +811,6 @@ def get_review_indicator(review_status):
817811
rundir = node.rundir if hasattr(node, 'rundir') and node.rundir else ''
818812
approximant = node.meta.get('approximant', '') if hasattr(node, 'meta') else ''
819813

820-
import os
821814
base_url = f"{self.name}/{node.name}"
822815

823816
result_pages = []

asimov/pipelines/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import sys
23

34
if sys.version_info < (3, 10):
@@ -14,6 +15,8 @@
1415

1516
discovered_pipelines = entry_points(group="asimov.pipelines")
1617

18+
logger = logging.getLogger(__name__)
19+
1720

1821
known_pipelines = {
1922
"bayeswave": BayesWave,
@@ -27,6 +30,10 @@
2730
for pipeline in discovered_pipelines:
2831
try:
2932
known_pipelines[pipeline.name] = pipeline.load()
30-
except (ModuleNotFoundError, ImportError):
31-
# Skip pipelines that can't be imported (e.g., testing pipelines in production)
32-
pass
33+
except (ModuleNotFoundError, ImportError) as e:
34+
logger.warning(
35+
"Could not load pipeline entry point %r: %s. "
36+
"This pipeline will not be available.",
37+
pipeline.name,
38+
e,
39+
)

asimov/pipelines/pesummary.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,13 +602,13 @@ def html(self):
602602

603603
# Add common plot images that PESummary generates
604604
# Corner plot
605-
out += f"""<img height=200 src="{pages_dir}/plots/corner.png" alt="Corner plot"></src>"""
605+
out += f"""<img height=200 src="{pages_dir}/plots/corner.png" alt="Corner plot" />"""
606606

607607
# Skymap
608-
out += f"""<img height=200 src="{pages_dir}/plots/skymap.png" alt="Sky localization"></src>"""
608+
out += f"""<img height=200 src="{pages_dir}/plots/skymap.png" alt="Sky localization" />"""
609609

610610
# Waveform plots
611-
out += f"""<img height=200 src="{pages_dir}/plots/waveform_time_domain_H1L1.png" alt="Waveform"></src>"""
611+
out += f"""<img height=200 src="{pages_dir}/plots/waveform_time_domain_H1L1.png" alt="Waveform" />"""
612612

613613
out += """</div>"""
614614

tests/test_application.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,75 @@ def test_multi_parameter_strategy_matrix(self):
245245
self.assertEqual(prod.meta["sampler"]["sampler"], "dynesty")
246246
elif "emcee" in prod.name:
247247
self.assertEqual(prod.meta["sampler"]["sampler"], "emcee")
248+
249+
250+
class NameIterateTests(AsimovTestCase):
251+
"""
252+
Tests for the --name and --iterate options of apply_page.
253+
"""
254+
255+
def setUp(self):
256+
super().setUp()
257+
# Add the base event and a first analysis so we have an existing name
258+
apply_page(
259+
f"{self.cwd}/tests/test_data/test_event.yaml",
260+
ledger=self.ledger,
261+
)
262+
263+
def test_name_overrides_blueprint_name(self):
264+
"""--name should replace the name field in the blueprint."""
265+
apply_page(
266+
f"{self.cwd}/tests/test_data/test_analysis_S000000.yaml",
267+
event="S000000",
268+
ledger=self.ledger,
269+
name="my-custom-name",
270+
)
271+
event = self.ledger.get_event("S000000")[0]
272+
analysis_names = {prod.name for prod in event.productions}
273+
self.assertIn("my-custom-name", analysis_names)
274+
self.assertNotIn("bilby-IMRPhenomXPHM-QuickTest", analysis_names)
275+
276+
def test_iterate_increments_name_when_collision(self):
277+
"""--iterate should produce a -2 suffix when the base name is already taken."""
278+
# Apply the analysis once to register the base name
279+
apply_page(
280+
f"{self.cwd}/tests/test_data/test_analysis_S000000.yaml",
281+
event="S000000",
282+
ledger=self.ledger,
283+
)
284+
# Apply again with --iterate; a -2 suffix should be chosen
285+
apply_page(
286+
f"{self.cwd}/tests/test_data/test_analysis_S000000.yaml",
287+
event="S000000",
288+
ledger=self.ledger,
289+
iterate=True,
290+
)
291+
event = self.ledger.get_event("S000000")[0]
292+
analysis_names = {prod.name for prod in event.productions}
293+
self.assertIn("bilby-IMRPhenomXPHM-QuickTest", analysis_names)
294+
self.assertIn("bilby-IMRPhenomXPHM-QuickTest-2", analysis_names)
295+
296+
def test_iterate_increments_correctly_for_strategy(self):
297+
"""--iterate with a strategy should give deterministic -2, -3, ... names."""
298+
apply_page(
299+
f"{self.cwd}/tests/test_data/test_strategy_single.yaml",
300+
event="S000000",
301+
ledger=self.ledger,
302+
)
303+
# Apply the same strategy again with --iterate
304+
apply_page(
305+
f"{self.cwd}/tests/test_data/test_strategy_single.yaml",
306+
event="S000000",
307+
ledger=self.ledger,
308+
iterate=True,
309+
)
310+
event = self.ledger.get_event("S000000")[0]
311+
analysis_names = {prod.name for prod in event.productions}
312+
# First pass
313+
self.assertIn("bilby-IMRPhenomXPHM", analysis_names)
314+
self.assertIn("bilby-SEOBNRv4PHM", analysis_names)
315+
self.assertIn("bilby-IMRPhenomD", analysis_names)
316+
# Second pass - iterated names
317+
self.assertIn("bilby-IMRPhenomXPHM-2", analysis_names)
318+
self.assertIn("bilby-SEOBNRv4PHM-2", analysis_names)
319+
self.assertIn("bilby-IMRPhenomD-2", analysis_names)

0 commit comments

Comments
 (0)