Skip to content

Commit 100396d

Browse files
authored
Merge branch 'main' into fix/resource_parsing
2 parents 37aaa0b + 270d240 commit 100396d

File tree

7 files changed

+71
-26
lines changed

7 files changed

+71
-26
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
# Changelog
22

33

4+
## [9.1.4](https://github.com/snakemake/snakemake/compare/v9.1.3...v9.1.4) (2025-04-01)
5+
6+
7+
### Bug Fixes
8+
9+
* Fix map call in report creation ([#3503](https://github.com/snakemake/snakemake/issues/3503)) ([44754cc](https://github.com/snakemake/snakemake/commit/44754ccbafaf94d30b9e507b81e8fb5f38409e3d))
10+
* in the report, do not render toggle labels if there is more than one label eligible for a toggle ([#3502](https://github.com/snakemake/snakemake/issues/3502)) ([3be8ca9](https://github.com/snakemake/snakemake/commit/3be8ca9308df72494cbca4d6f572486c8486418a))
11+
* only inform about storage cleanup in case of --verbose mode ([#3494](https://github.com/snakemake/snakemake/issues/3494)) ([62bbbf5](https://github.com/snakemake/snakemake/commit/62bbbf5129b2fe9ed125245fd90b69d53db8b6ce))
12+
* provide causing rule to workflow error during checkpoint handling ([#3499](https://github.com/snakemake/snakemake/issues/3499)) ([b4cbe5d](https://github.com/snakemake/snakemake/commit/b4cbe5d2e9d5d985466a5dac4c985caa66efb5ad))
13+
* rerun-trigger regression ([#3492](https://github.com/snakemake/snakemake/issues/3492)) ([811742d](https://github.com/snakemake/snakemake/commit/811742d5db425219a3018f04190a99f53b3b742d))
14+
15+
16+
### Documentation
17+
18+
* note about parameter inheritance when using the "use rule with" pattern ([#3500](https://github.com/snakemake/snakemake/issues/3500)) ([8f6a8eb](https://github.com/snakemake/snakemake/commit/8f6a8eb783bf003dbf804df737a2adfbfa9818ef))
19+
420
## [9.1.3](https://github.com/snakemake/snakemake/compare/v9.1.2...v9.1.3) (2025-03-26)
521

622

docs/snakefiles/rules.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2931,6 +2931,12 @@ In reality, one will often change more.
29312931
Analogously to the ``use rule`` from external modules, any properties of the rule (``input``, ``output``, ``log``, ``params``, ``benchmark``, ``threads``, ``resources``, etc.) can be modified, except the actual execution step (``shell``, ``notebook``, ``script``, ``cwl``, or ``run``).
29322932
All unmodified properties are inherited from the parent rule.
29332933

2934+
.. note::
2935+
Modification of `params` allows the replacement of single keyword arguments.
2936+
Keyword `params` arguments of the original rule that are not defined after `with` are inherited.
2937+
Positional `params` arguments of the original rule are overwritten, if positional `params` arguments are given after `with`.
2938+
All other properties (``input``, ``output``, ...) are entirely overwritten with the values specified after `with`.
2939+
29342940
.. _snakefiles-aux_source_files:
29352941

29362942
Accessing auxiliary source files

src/snakemake/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ def get_argument_parser(profiles=None):
721721
"--rerun-triggers",
722722
nargs="+",
723723
choices=RerunTrigger.choices(),
724-
default=RerunTrigger.choices(),
724+
default=RerunTrigger.all(),
725725
parse_func=RerunTrigger.parse_choices_set,
726726
help="Define what triggers the rerunning of a job. By default, "
727727
"all triggers are used, which guarantees that results are "

src/snakemake/dag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ async def cleanup_storage_objects(self):
506506
and f not in cleaned
507507
and not f.should_keep_local
508508
):
509-
logger.info(
509+
logger.debug(
510510
"Cleaning up local remainders of "
511511
f"{f.storage_object.print_query}"
512512
)

src/snakemake/report/__init__.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
__email__ = "[email protected]"
44
__license__ = "MIT"
55

6+
from asyncio import TaskGroup
67
from dataclasses import InitVar, dataclass, field
78
import os
89
import sys
@@ -13,12 +14,9 @@
1314
import io
1415
from typing import List, Optional
1516
import uuid
16-
import json
17-
import time
1817
import itertools
1918
from collections import defaultdict
2019
import hashlib
21-
from zipfile import ZipFile, ZIP_DEFLATED
2220
from pathlib import Path
2321
import numbers
2422

@@ -113,7 +111,7 @@ def report(
113111
if outmime != "text/html":
114112
raise ValueError("Path to report output has to be an HTML file.")
115113
definitions = textwrap.dedent(
116-
"""
114+
"""[]
117115
.. role:: raw-html(raw)
118116
:format: html
119117
@@ -187,11 +185,21 @@ def report(
187185
)
188186

189187

190-
def expand_report_argument(item, wildcards, job):
188+
async def expand_report_argument(item, wildcards, job):
191189
if is_callable(item):
192190
aux_params = get_input_function_aux_params(
193191
item, {"params": job.params, "input": job.input, "output": job.output}
194192
)
193+
io_items = ["input", "output"]
194+
if any(io_item in aux_params for io_item in io_items):
195+
# retrieve all input or output files from storage before evaluating function
196+
async with TaskGroup() as tg:
197+
for io_item in io_items:
198+
if io_item in aux_params:
199+
for f in aux_params[io_item]:
200+
if f.is_storage:
201+
tg.create_task(f.retrieve_from_storage())
202+
195203
try:
196204
item = item(wildcards, **aux_params)
197205
except Exception as e:
@@ -209,15 +217,11 @@ def expand_report_argument(item, wildcards, job):
209217

210218
@dataclass(slots=True)
211219
class Category(CategoryInterface):
212-
wildcards: InitVar
213-
job: InitVar
214220
name: Optional[str]
215221
is_other: bool = field(init=False)
216222
id: str = field(init=False)
217223

218-
def __post_init__(self, wildcards, job):
219-
if self.name is not None:
220-
self.name = expand_report_argument(self.name, wildcards, job)
224+
def __post_init__(self):
221225
if self.name is None:
222226
self.name = "Other"
223227

@@ -447,10 +451,10 @@ def workflow(self):
447451
return self.job.rule.workflow
448452

449453

450-
def expand_labels(labels, wildcards, job):
454+
async def expand_labels(labels, wildcards, job):
451455
if labels is None:
452456
return None
453-
labels = expand_report_argument(labels, wildcards, job)
457+
labels = await expand_report_argument(labels, wildcards, job)
454458

455459
if labels is None:
456460
return None
@@ -469,7 +473,7 @@ def expand_labels(labels, wildcards, job):
469473
rule=job.rule,
470474
)
471475
return {
472-
name: expand_report_argument(col, wildcards, job)
476+
name: await expand_report_argument(col, wildcards, job)
473477
for name, col in labels.items()
474478
}
475479

@@ -541,21 +545,32 @@ def get_time(rectime, metatime, sel_func):
541545
)
542546
report_obj = get_flag_value(f, "report")
543547

544-
def register_file(
548+
async def register_file(
545549
f,
546550
parent_path=None,
547551
wildcards_overwrite=None,
548552
aux_files=None,
549553
name_overwrite=None,
550554
):
551555
wildcards = wildcards_overwrite or job.wildcards
556+
557+
async def expand_cat_name(cat_name, wildcards, job):
558+
if cat_name is not None:
559+
return await expand_report_argument(
560+
cat_name, wildcards, job
561+
)
562+
else:
563+
return cat_name
564+
552565
category = Category(
553-
name=report_obj.category, wildcards=wildcards, job=job
566+
name=await expand_cat_name(report_obj.category, wildcards, job),
554567
)
555568
subcategory = Category(
556-
name=report_obj.subcategory, wildcards=wildcards, job=job
569+
name=await expand_cat_name(
570+
report_obj.subcategory, wildcards, job
571+
),
557572
)
558-
labels = expand_labels(report_obj.labels, wildcards, job)
573+
labels = await expand_labels(report_obj.labels, wildcards, job)
559574

560575
results[category][subcategory].append(
561576
FileRecord(
@@ -577,7 +592,7 @@ def register_file(
577592
if f.is_storage:
578593
await f.retrieve_from_storage()
579594
if os.path.isfile(f):
580-
register_file(f)
595+
await register_file(f)
581596
elif os.path.isdir(f):
582597
if report_obj.htmlindex:
583598
aux_files = []
@@ -598,7 +613,7 @@ def register_file(
598613
"Given htmlindex {} not found in directory "
599614
"marked for report".format(report_obj.htmlindex)
600615
)
601-
register_file(
616+
await register_file(
602617
os.path.join(f, report_obj.htmlindex),
603618
aux_files=aux_files,
604619
name_overwrite=f"{os.path.basename(f)}.html",
@@ -621,7 +636,7 @@ def register_file(
621636
w.update(job.wildcards_dict)
622637
w = Wildcards(fromdict=w)
623638
subfile = apply_wildcards(pattern, w)
624-
register_file(
639+
await register_file(
625640
subfile, parent_path=f, wildcards_overwrite=w
626641
)
627642
if not found_something:

src/snakemake/report/html_reporter/template/components/abstract_results.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class AbstractResults extends React.Component {
9898
return { data: data, toggles };
9999
}, function () {
100100
if (_this.state.data.resultPathsToEntryLabels.has(_this.props.app.state.resultPath)) {
101-
let toggleLabels = Array.from(data.toggleLabels.keys().map((label) => _this.state.toggles.get(label)));
101+
let toggleLabels = Array.from(data.toggleLabels.keys()).map((label) => _this.state.toggles.get(label));
102102
let entryLabels = _this.state.data.resultPathsToEntryLabels.get(_this.props.app.state.resultPath);
103103
let targetPath = _this.state.data.entries.get(arrayKey(entryLabels)).get(arrayKey(toggleLabels));
104104
_this.toggleViewManager.handleSelectedResult(targetPath);
@@ -190,6 +190,10 @@ class AbstractResults extends React.Component {
190190
}
191191
});
192192
}
193+
// Only allow one toggle label for now, in order to avoid confusion in the UI
194+
if (toggleLabels.size > 1) {
195+
toggleLabels = new Map();
196+
}
193197

194198
let entries = new Map();
195199
let entryLabelValues = [];
@@ -318,4 +322,4 @@ class AbstractResults extends React.Component {
318322
];
319323
});
320324
}
321-
}
325+
}

src/snakemake/rules.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,12 @@ def handle_incomplete_checkpoint(exception):
937937
return TBDString()
938938
else:
939939
raise WorkflowError(
940-
"Rule parameter depends on checkpoint but checkpoint output is not defined as input file for the rule. "
941-
"Please add the output of the respective checkpoint to the rule inputs."
940+
"Rule parameter depends on checkpoint but checkpoint output is not "
941+
"defined as input file for the rule. Please add the output of the "
942+
"respective checkpoint to the rule inputs. "
943+
f"Input: {','.join(input)} "
944+
f"Checkpoint file: {exception.targetfile}",
945+
rule=self,
942946
)
943947

944948
# We make sure that resources are only evaluated if a param function

0 commit comments

Comments
 (0)