looper 1.7.0__py3-none-any.whl → 2.0.0__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.
- looper/__main__.py +1 -1
- looper/_version.py +2 -1
- looper/cli_divvy.py +10 -6
- looper/cli_pydantic.py +413 -0
- looper/command_models/DEVELOPER.md +85 -0
- looper/command_models/README.md +4 -0
- looper/command_models/__init__.py +6 -0
- looper/command_models/arguments.py +293 -0
- looper/command_models/commands.py +335 -0
- looper/conductor.py +147 -28
- looper/const.py +9 -0
- looper/divvy.py +56 -47
- looper/exceptions.py +9 -1
- looper/looper.py +196 -169
- looper/pipeline_interface.py +2 -12
- looper/project.py +154 -176
- looper/schemas/pipeline_interface_schema_generic.yaml +14 -6
- looper/utils.py +450 -78
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/METADATA +24 -14
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/RECORD +24 -19
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/WHEEL +1 -1
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/entry_points.txt +1 -1
- looper/cli_looper.py +0 -796
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/LICENSE.txt +0 -0
- {looper-1.7.0.dist-info → looper-2.0.0.dist-info}/top_level.txt +0 -0
looper/looper.py
CHANGED
@@ -6,6 +6,7 @@ Looper: a pipeline submission engine. https://github.com/pepkit/looper
|
|
6
6
|
import abc
|
7
7
|
import argparse
|
8
8
|
import csv
|
9
|
+
import glob
|
9
10
|
import logging
|
10
11
|
import subprocess
|
11
12
|
import yaml
|
@@ -15,6 +16,8 @@ import pandas as _pd
|
|
15
16
|
# Need specific sequence of actions for colorama imports?
|
16
17
|
from colorama import init
|
17
18
|
|
19
|
+
from .const import PipelineLevel
|
20
|
+
|
18
21
|
init()
|
19
22
|
from shutil import rmtree
|
20
23
|
|
@@ -30,14 +33,12 @@ from rich.color import Color
|
|
30
33
|
from rich.console import Console
|
31
34
|
from rich.table import Table
|
32
35
|
from ubiquerg.cli_tools import query_yes_no
|
33
|
-
from ubiquerg.collection import uniqify
|
34
36
|
|
35
37
|
|
36
38
|
from .conductor import SubmissionConductor
|
37
39
|
|
38
40
|
from .exceptions import *
|
39
41
|
from .const import *
|
40
|
-
from .pipeline_interface import PipelineInterface
|
41
42
|
from .project import Project
|
42
43
|
from .utils import (
|
43
44
|
desired_samples_range_skipped,
|
@@ -45,7 +46,7 @@ from .utils import (
|
|
45
46
|
sample_folder,
|
46
47
|
)
|
47
48
|
from pipestat.reports import get_file_for_table
|
48
|
-
from pipestat.
|
49
|
+
from pipestat.exceptions import PipestatSummarizeError
|
49
50
|
|
50
51
|
_PKGNAME = "looper"
|
51
52
|
_LOGGER = logging.getLogger(_PKGNAME)
|
@@ -88,21 +89,37 @@ class Checker(Executor):
|
|
88
89
|
|
89
90
|
# aggregate pipeline status data
|
90
91
|
status = {}
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
92
|
+
|
93
|
+
psms = {}
|
94
|
+
if getattr(args, "project", None):
|
95
|
+
|
96
|
+
for piface in self.prj.project_pipeline_interfaces:
|
97
|
+
if piface.psm.pipeline_type == PipelineLevel.PROJECT.value:
|
98
|
+
if piface.psm.pipeline_name not in psms:
|
99
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
100
|
+
for pl_name, psm in psms.items():
|
101
|
+
all_project_level_records = psm.select_records()
|
102
|
+
for record in all_project_level_records["records"]:
|
103
|
+
s = piface.psm.get_status(
|
104
|
+
record_identifier=record["record_identifier"]
|
105
|
+
)
|
106
|
+
status.setdefault(piface.psm.pipeline_name, {})
|
107
|
+
status[piface.psm.pipeline_name][record["record_identifier"]] = s
|
108
|
+
_LOGGER.debug(
|
109
|
+
f"{self.prj.name} ({record['record_identifier']}): {s}"
|
110
|
+
)
|
111
|
+
|
98
112
|
else:
|
99
113
|
for sample in self.prj.samples:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
114
|
+
for piface in sample.project.pipeline_interfaces:
|
115
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
116
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
117
|
+
s = piface.psm.get_status(record_identifier=sample.sample_name)
|
118
|
+
status.setdefault(piface.psm.pipeline_name, {})
|
119
|
+
status[piface.psm.pipeline_name][sample.sample_name] = s
|
120
|
+
_LOGGER.debug(
|
121
|
+
f"{sample.sample_name} ({piface.psm.pipeline_name}): {s}"
|
122
|
+
)
|
106
123
|
|
107
124
|
console = Console()
|
108
125
|
|
@@ -116,14 +133,14 @@ class Checker(Executor):
|
|
116
133
|
)
|
117
134
|
table.add_column(f"Status", justify="center")
|
118
135
|
table.add_column("Jobs count/total jobs", justify="center")
|
119
|
-
for status_id in
|
136
|
+
for status_id in psms[pipeline_name].status_schema.keys():
|
120
137
|
status_list = list(pipeline_status.values())
|
121
138
|
if status_id in status_list:
|
122
139
|
status_count = status_list.count(status_id)
|
123
140
|
table.add_row(status_id, f"{status_count}/{len(status_list)}")
|
124
141
|
console.print(table)
|
125
142
|
|
126
|
-
if args
|
143
|
+
if getattr(args, "itemized", None):
|
127
144
|
for pipeline_name, pipeline_status in status.items():
|
128
145
|
table_title = f"Pipeline: '{pipeline_name}'"
|
129
146
|
table = Table(
|
@@ -141,7 +158,7 @@ class Checker(Executor):
|
|
141
158
|
for name, status_id in pipeline_status.items():
|
142
159
|
try:
|
143
160
|
color = Color.from_rgb(
|
144
|
-
*
|
161
|
+
*psms[pipeline_name].status_schema[status_id]["color"]
|
145
162
|
).name
|
146
163
|
except KeyError:
|
147
164
|
color = "#bcbcbc"
|
@@ -150,16 +167,17 @@ class Checker(Executor):
|
|
150
167
|
console.print(table)
|
151
168
|
|
152
169
|
if args.describe_codes:
|
170
|
+
# TODO this needs to be redone because it only takes the last psm in the list and gets status code and descriptions
|
153
171
|
table = Table(
|
154
172
|
show_header=True,
|
155
173
|
header_style="bold magenta",
|
156
174
|
title=f"Status codes description",
|
157
|
-
width=len(
|
158
|
-
caption=f"Descriptions source: {
|
175
|
+
width=len(psms[pipeline_name].status_schema_source) + 20,
|
176
|
+
caption=f"Descriptions source: {psms[pipeline_name].status_schema_source}",
|
159
177
|
)
|
160
178
|
table.add_column("Status code", justify="center")
|
161
179
|
table.add_column("Description", justify="left")
|
162
|
-
for status, status_obj in
|
180
|
+
for status, status_obj in psms[pipeline_name].status_schema.items():
|
163
181
|
if "description" in status_obj:
|
164
182
|
desc = status_obj["description"]
|
165
183
|
else:
|
@@ -199,10 +217,10 @@ class Cleaner(Executor):
|
|
199
217
|
if not preview_flag:
|
200
218
|
_LOGGER.info("Clean complete.")
|
201
219
|
return 0
|
202
|
-
if args
|
220
|
+
if getattr(args, "dry_run", None):
|
203
221
|
_LOGGER.info("Dry run. No files cleaned.")
|
204
222
|
return 0
|
205
|
-
if not args
|
223
|
+
if not getattr(args, "force_yes", None) and not query_yes_no(
|
206
224
|
"Are you sure you want to permanently delete all "
|
207
225
|
"intermediate pipeline results for this project?"
|
208
226
|
):
|
@@ -241,8 +259,22 @@ class Destroyer(Executor):
|
|
241
259
|
:param bool preview_flag: whether to halt before actually removing files
|
242
260
|
"""
|
243
261
|
|
244
|
-
|
262
|
+
use_pipestat = (
|
263
|
+
self.prj.pipestat_configured_project
|
264
|
+
if getattr(args, "project", None)
|
265
|
+
else self.prj.pipestat_configured
|
266
|
+
)
|
245
267
|
|
268
|
+
if use_pipestat:
|
269
|
+
_LOGGER.info("Removing summary:")
|
270
|
+
destroy_summary(
|
271
|
+
self.prj,
|
272
|
+
dry_run=preview_flag,
|
273
|
+
project_level=getattr(args, "project", None),
|
274
|
+
)
|
275
|
+
|
276
|
+
_LOGGER.info("Removing results:")
|
277
|
+
psms = {}
|
246
278
|
for sample in select_samples(prj=self.prj, args=args):
|
247
279
|
_LOGGER.info(self.counter.show(sample.sample_name))
|
248
280
|
sample_output_folder = sample_folder(self.prj, sample)
|
@@ -250,30 +282,26 @@ class Destroyer(Executor):
|
|
250
282
|
# Preview: Don't actually delete, just show files.
|
251
283
|
_LOGGER.info(str(sample_output_folder))
|
252
284
|
else:
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
else:
|
264
|
-
_LOGGER.warning(
|
265
|
-
"Pipestat must be configured to destroy any created summaries."
|
266
|
-
)
|
285
|
+
if use_pipestat:
|
286
|
+
for piface in sample.project.pipeline_interfaces:
|
287
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
288
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
289
|
+
for pipeline_name, psm in psms.items():
|
290
|
+
psm.backend.remove_record(
|
291
|
+
record_identifier=sample.sample_name, rm_record=True
|
292
|
+
)
|
293
|
+
else:
|
294
|
+
_remove_or_dry_run(sample_output_folder, args.dry_run)
|
267
295
|
|
268
296
|
if not preview_flag:
|
269
297
|
_LOGGER.info("Destroy complete.")
|
270
298
|
return 0
|
271
299
|
|
272
|
-
if args
|
300
|
+
if getattr(args, "dry_run", None):
|
273
301
|
_LOGGER.info("Dry run. No files destroyed.")
|
274
302
|
return 0
|
275
303
|
|
276
|
-
if not args
|
304
|
+
if not getattr(args, "force_yes", None) and not query_yes_no(
|
277
305
|
"Are you sure you want to permanently delete all pipeline "
|
278
306
|
"results for this project?"
|
279
307
|
):
|
@@ -308,7 +336,7 @@ class Collator(Executor):
|
|
308
336
|
"""
|
309
337
|
jobs = 0
|
310
338
|
self.debug = {}
|
311
|
-
project_pifaces = self.prj.
|
339
|
+
project_pifaces = self.prj.project_pipeline_interfaces
|
312
340
|
if not project_pifaces:
|
313
341
|
raise MisconfigurationException(
|
314
342
|
"Looper requires a pointer to at least one project pipeline. "
|
@@ -318,36 +346,26 @@ class Collator(Executor):
|
|
318
346
|
)
|
319
347
|
self.counter = LooperCounter(len(project_pifaces))
|
320
348
|
for project_piface in project_pifaces:
|
321
|
-
try:
|
322
|
-
project_piface_object = PipelineInterface(
|
323
|
-
project_piface, pipeline_type="project"
|
324
|
-
)
|
325
|
-
except (IOError, ValidationError) as e:
|
326
|
-
_LOGGER.warning(
|
327
|
-
"Ignoring invalid pipeline interface source: {}. "
|
328
|
-
"Caught exception: {}".format(
|
329
|
-
project_piface, getattr(e, "message", repr(e))
|
330
|
-
)
|
331
|
-
)
|
332
|
-
continue
|
333
349
|
_LOGGER.info(
|
334
350
|
self.counter.show(
|
335
351
|
name=self.prj.name,
|
336
352
|
type="project",
|
337
|
-
pipeline_name=
|
353
|
+
pipeline_name=project_piface.pipeline_name,
|
338
354
|
)
|
339
355
|
)
|
340
356
|
conductor = SubmissionConductor(
|
341
|
-
pipeline_interface=
|
357
|
+
pipeline_interface=project_piface,
|
342
358
|
prj=self.prj,
|
343
359
|
compute_variables=compute_kwargs,
|
344
|
-
delay=args
|
345
|
-
extra_args=args
|
346
|
-
extra_args_override=args
|
347
|
-
ignore_flags=args
|
360
|
+
delay=getattr(args, "time_delay", None),
|
361
|
+
extra_args=getattr(args, "command_extra", None),
|
362
|
+
extra_args_override=getattr(args, "command_extra_override", None),
|
363
|
+
ignore_flags=getattr(args, "ignore_flags", None),
|
348
364
|
collate=True,
|
349
365
|
)
|
350
|
-
if conductor.is_project_submittable(
|
366
|
+
if conductor.is_project_submittable(
|
367
|
+
force=getattr(args, "ignore_flags", None)
|
368
|
+
):
|
351
369
|
conductor._pool = [None]
|
352
370
|
conductor.submit()
|
353
371
|
jobs += conductor.num_job_submissions
|
@@ -360,7 +378,7 @@ class Collator(Executor):
|
|
360
378
|
class Runner(Executor):
|
361
379
|
"""The true submitter of pipelines"""
|
362
380
|
|
363
|
-
def __call__(self, args, rerun=False, **compute_kwargs):
|
381
|
+
def __call__(self, args, top_level_args=None, rerun=False, **compute_kwargs):
|
364
382
|
"""
|
365
383
|
Do the Sample submission.
|
366
384
|
|
@@ -395,25 +413,24 @@ class Runner(Executor):
|
|
395
413
|
)
|
396
414
|
|
397
415
|
submission_conductors = {}
|
416
|
+
|
398
417
|
for piface in self.prj.pipeline_interfaces:
|
399
418
|
conductor = SubmissionConductor(
|
400
419
|
pipeline_interface=piface,
|
401
420
|
prj=self.prj,
|
402
421
|
compute_variables=comp_vars,
|
403
|
-
delay=args
|
404
|
-
extra_args=args
|
405
|
-
extra_args_override=args
|
406
|
-
ignore_flags=args
|
407
|
-
max_cmds=args
|
408
|
-
max_size=args
|
409
|
-
max_jobs=args
|
422
|
+
delay=getattr(args, "time_delay", None),
|
423
|
+
extra_args=getattr(args, "command_extra", None),
|
424
|
+
extra_args_override=getattr(args, "command_extra_override", None),
|
425
|
+
ignore_flags=getattr(args, "ignore_flags", None),
|
426
|
+
max_cmds=getattr(args, "lump_n", None),
|
427
|
+
max_size=getattr(args, "lump", None),
|
428
|
+
max_jobs=getattr(args, "lump_j", None),
|
410
429
|
)
|
411
430
|
submission_conductors[piface.pipe_iface_file] = conductor
|
412
431
|
|
413
|
-
_LOGGER.
|
414
|
-
self.debug["Pipestat compatible"] =
|
415
|
-
self.prj.pipestat_configured_project or self.prj.pipestat_configured
|
416
|
-
)
|
432
|
+
_LOGGER.debug(f"Pipestat compatible: {self.prj.pipestat_configured}")
|
433
|
+
self.debug["Pipestat compatible"] = self.prj.pipestat_configured
|
417
434
|
|
418
435
|
for sample in select_samples(prj=self.prj, args=args):
|
419
436
|
pl_fails = []
|
@@ -485,15 +502,15 @@ class Runner(Executor):
|
|
485
502
|
len(processed_samples), num_samples
|
486
503
|
)
|
487
504
|
)
|
488
|
-
_LOGGER.
|
505
|
+
_LOGGER.debug("Commands submitted: {} of {}".format(cmd_sub_total, max_cmds))
|
489
506
|
self.debug[DEBUG_COMMANDS] = "{} of {}".format(cmd_sub_total, max_cmds)
|
490
|
-
if args
|
507
|
+
if getattr(args, "dry_run", None):
|
491
508
|
job_sub_total_if_real = job_sub_total
|
492
509
|
job_sub_total = 0
|
493
510
|
_LOGGER.info(
|
494
511
|
f"Dry run. No jobs were actually submitted, but {job_sub_total_if_real} would have been."
|
495
512
|
)
|
496
|
-
_LOGGER.
|
513
|
+
_LOGGER.debug("Jobs submitted: {}".format(job_sub_total))
|
497
514
|
self.debug[DEBUG_JOBS] = job_sub_total
|
498
515
|
|
499
516
|
# Restructure sample/failure data for display.
|
@@ -545,37 +562,55 @@ class Reporter(Executor):
|
|
545
562
|
|
546
563
|
def __call__(self, args):
|
547
564
|
# initialize the report builder
|
565
|
+
self.debug = {}
|
548
566
|
p = self.prj
|
549
|
-
project_level = args
|
567
|
+
project_level = getattr(args, "project", None)
|
550
568
|
|
551
569
|
portable = args.portable
|
552
570
|
|
571
|
+
report_dir = getattr(args, "report_dir", None)
|
572
|
+
|
573
|
+
psms = {}
|
574
|
+
|
553
575
|
if project_level:
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
576
|
+
|
577
|
+
for piface in self.prj.project_pipeline_interfaces:
|
578
|
+
if piface.psm.pipeline_type == PipelineLevel.PROJECT.value:
|
579
|
+
if piface.psm.pipeline_name not in psms:
|
580
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
581
|
+
for pl_name, psm in psms.items():
|
582
|
+
try:
|
583
|
+
report_directory = psm.summarize(
|
584
|
+
looper_samples=self.prj.samples,
|
585
|
+
portable=portable,
|
586
|
+
output_dir=report_dir,
|
587
|
+
)
|
588
|
+
except PipestatSummarizeError as e:
|
589
|
+
raise LooperReportError(
|
590
|
+
f"Looper report error due to the following exception: {e}"
|
591
|
+
)
|
561
592
|
print(f"Report directory: {report_directory}")
|
593
|
+
self.debug["report_directory"] = report_directory
|
594
|
+
return self.debug
|
562
595
|
else:
|
563
|
-
for
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
psms = self.prj.get_pipestat_managers(
|
570
|
-
sample_name=first_sample_name, project_level=False
|
571
|
-
)
|
572
|
-
print(psms)
|
573
|
-
for name, psm in psms.items():
|
574
|
-
# Summarize will generate the static HTML Report Function
|
596
|
+
for piface in self.prj.pipeline_interfaces:
|
597
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
598
|
+
if piface.psm.pipeline_name not in psms:
|
599
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
600
|
+
for pl_name, psm in psms.items():
|
601
|
+
try:
|
575
602
|
report_directory = psm.summarize(
|
576
|
-
looper_samples=self.prj.samples,
|
603
|
+
looper_samples=self.prj.samples,
|
604
|
+
portable=portable,
|
605
|
+
output_dir=report_dir,
|
577
606
|
)
|
578
|
-
|
607
|
+
except PipestatSummarizeError as e:
|
608
|
+
raise LooperReportError(
|
609
|
+
f"Looper report error due to the following exception: {e}"
|
610
|
+
)
|
611
|
+
print(f"Report directory: {report_directory}")
|
612
|
+
self.debug["report_directory"] = report_directory
|
613
|
+
return self.debug
|
579
614
|
|
580
615
|
|
581
616
|
class Linker(Executor):
|
@@ -584,26 +619,22 @@ class Linker(Executor):
|
|
584
619
|
def __call__(self, args):
|
585
620
|
# initialize the report builder
|
586
621
|
p = self.prj
|
587
|
-
project_level = args
|
588
|
-
link_dir = args
|
622
|
+
project_level = getattr(args, "project", None)
|
623
|
+
link_dir = getattr(args, "output_dir", None)
|
624
|
+
|
625
|
+
psms = {}
|
589
626
|
|
590
627
|
if project_level:
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
628
|
+
for piface in self.prj.project_pipeline_interfaces:
|
629
|
+
if piface.psm.pipeline_type == PipelineLevel.PROJECT.value:
|
630
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
631
|
+
linked_results_path = piface.psm.link(link_dir=link_dir)
|
632
|
+
print(f"Linked directory: {linked_results_path}")
|
595
633
|
else:
|
596
|
-
for
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
# call the related pipestat manager object which will pull ALL samples when using psm.summarize
|
601
|
-
first_sample_name = list(piface_source_samples)[0]
|
602
|
-
psms = self.prj.get_pipestat_managers(
|
603
|
-
sample_name=first_sample_name, project_level=False
|
604
|
-
)
|
605
|
-
for name, psm in psms.items():
|
606
|
-
linked_results_path = psm.link(link_dir=link_dir)
|
634
|
+
for piface in self.prj.pipeline_interfaces:
|
635
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
636
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
637
|
+
linked_results_path = piface.psm.link(link_dir=link_dir)
|
607
638
|
print(f"Linked directory: {linked_results_path}")
|
608
639
|
|
609
640
|
|
@@ -615,24 +646,24 @@ class Tabulator(Executor):
|
|
615
646
|
|
616
647
|
def __call__(self, args):
|
617
648
|
# p = self.prj
|
618
|
-
project_level = args
|
649
|
+
project_level = getattr(args, "project", None)
|
650
|
+
report_dir = getattr(args, "report_dir", None)
|
619
651
|
results = []
|
652
|
+
psms = {}
|
620
653
|
if project_level:
|
621
|
-
|
622
|
-
|
623
|
-
|
654
|
+
for piface in self.prj.project_pipeline_interfaces:
|
655
|
+
if piface.psm.pipeline_type == PipelineLevel.PROJECT.value:
|
656
|
+
if piface.psm.pipeline_name not in psms:
|
657
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
658
|
+
for pl_name, psm in psms.items():
|
659
|
+
results = psm.table(output_dir=report_dir)
|
624
660
|
else:
|
625
|
-
for
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
psms = self.prj.get_pipestat_managers(
|
632
|
-
sample_name=first_sample_name, project_level=False
|
633
|
-
)
|
634
|
-
for name, psm in psms.items():
|
635
|
-
results = psm.table()
|
661
|
+
for piface in self.prj.pipeline_interfaces:
|
662
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
663
|
+
if piface.psm.pipeline_name not in psms:
|
664
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
665
|
+
for pl_name, psm in psms.items():
|
666
|
+
results = psm.table(output_dir=report_dir)
|
636
667
|
# Results contains paths to stats and object summaries.
|
637
668
|
return results
|
638
669
|
|
@@ -672,64 +703,60 @@ def destroy_summary(prj, dry_run=False, project_level=False):
|
|
672
703
|
This function is for use with pipestat configured projects.
|
673
704
|
"""
|
674
705
|
|
706
|
+
psms = {}
|
675
707
|
if project_level:
|
676
|
-
|
708
|
+
for piface in prj.pipeline_interfaces:
|
709
|
+
if piface.psm.pipeline_type == PipelineLevel.PROJECT.value:
|
710
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
711
|
+
|
677
712
|
for name, psm in psms.items():
|
678
713
|
_remove_or_dry_run(
|
679
714
|
[
|
680
|
-
|
681
|
-
psm,
|
682
|
-
pipeline_name=psm["_pipeline_name"],
|
683
|
-
directory="reports",
|
715
|
+
get_file_for_table(
|
716
|
+
psm, pipeline_name=psm.pipeline_name, directory="reports"
|
684
717
|
),
|
685
718
|
get_file_for_table(
|
686
719
|
psm,
|
687
|
-
pipeline_name=psm
|
720
|
+
pipeline_name=psm.pipeline_name,
|
688
721
|
appendix="stats_summary.tsv",
|
689
722
|
),
|
690
723
|
get_file_for_table(
|
691
724
|
psm,
|
692
|
-
pipeline_name=psm
|
725
|
+
pipeline_name=psm.pipeline_name,
|
693
726
|
appendix="objs_summary.yaml",
|
694
727
|
),
|
695
|
-
|
696
|
-
psm,
|
728
|
+
os.path.join(
|
729
|
+
os.path.dirname(psm.config_path), "aggregate_results.yaml"
|
697
730
|
),
|
698
731
|
],
|
699
732
|
dry_run,
|
700
733
|
)
|
701
734
|
else:
|
702
|
-
for
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
735
|
+
for piface in prj.pipeline_interfaces:
|
736
|
+
if piface.psm.pipeline_type == PipelineLevel.SAMPLE.value:
|
737
|
+
psms[piface.psm.pipeline_name] = piface.psm
|
738
|
+
for name, psm in psms.items():
|
739
|
+
_remove_or_dry_run(
|
740
|
+
[
|
741
|
+
get_file_for_table(
|
742
|
+
psm, pipeline_name=psm.pipeline_name, directory="reports"
|
743
|
+
),
|
744
|
+
get_file_for_table(
|
745
|
+
psm,
|
746
|
+
pipeline_name=psm.pipeline_name,
|
747
|
+
appendix="stats_summary.tsv",
|
748
|
+
),
|
749
|
+
get_file_for_table(
|
750
|
+
psm,
|
751
|
+
pipeline_name=psm.pipeline_name,
|
752
|
+
appendix="objs_summary.yaml",
|
753
|
+
),
|
754
|
+
os.path.join(
|
755
|
+
os.path.dirname(psm.config_path), "aggregate_results.yaml"
|
756
|
+
),
|
757
|
+
],
|
758
|
+
dry_run,
|
708
759
|
)
|
709
|
-
for name, psm in psms.items():
|
710
|
-
_remove_or_dry_run(
|
711
|
-
[
|
712
|
-
get_file_for_project(
|
713
|
-
psm,
|
714
|
-
pipeline_name=psm["_pipeline_name"],
|
715
|
-
directory="reports",
|
716
|
-
),
|
717
|
-
get_file_for_table(
|
718
|
-
psm,
|
719
|
-
pipeline_name=psm["_pipeline_name"],
|
720
|
-
appendix="stats_summary.tsv",
|
721
|
-
),
|
722
|
-
get_file_for_table(
|
723
|
-
psm,
|
724
|
-
pipeline_name=psm["_pipeline_name"],
|
725
|
-
appendix="objs_summary.yaml",
|
726
|
-
),
|
727
|
-
get_file_for_table(
|
728
|
-
psm, pipeline_name=psm["_pipeline_name"], appendix="reports"
|
729
|
-
),
|
730
|
-
],
|
731
|
-
dry_run,
|
732
|
-
)
|
733
760
|
|
734
761
|
|
735
762
|
class LooperCounter(object):
|
looper/pipeline_interface.py
CHANGED
@@ -17,7 +17,7 @@ from .exceptions import (
|
|
17
17
|
InvalidResourceSpecificationException,
|
18
18
|
PipelineInterfaceConfigError,
|
19
19
|
)
|
20
|
-
from .utils import
|
20
|
+
from .utils import render_nested_var_templates
|
21
21
|
|
22
22
|
__author__ = "Michal Stolarczyk"
|
23
23
|
__email__ = "michal@virginia.edu"
|
@@ -56,15 +56,6 @@ class PipelineInterface(YAMLConfigManager):
|
|
56
56
|
)
|
57
57
|
self.update(config)
|
58
58
|
self._validate(schema_src=PIFACE_SCHEMA_SRC)
|
59
|
-
if "path" in self:
|
60
|
-
warn(
|
61
|
-
message="'path' specification as a top-level pipeline "
|
62
|
-
"interface key is deprecated and will be removed with "
|
63
|
-
"the next release. Please use 'paths' section "
|
64
|
-
"from now on.",
|
65
|
-
category=DeprecationWarning,
|
66
|
-
)
|
67
|
-
self._expand_paths(["path"])
|
68
59
|
self._expand_paths(["compute", "dynamic_variables_script_path"])
|
69
60
|
|
70
61
|
@property
|
@@ -89,8 +80,7 @@ class PipelineInterface(YAMLConfigManager):
|
|
89
80
|
var_templates = {}
|
90
81
|
if curr_data:
|
91
82
|
var_templates.update(curr_data)
|
92
|
-
|
93
|
-
var_templates[k] = jinja_render_template_strictly(v, namespaces)
|
83
|
+
var_templates = render_nested_var_templates(var_templates, namespaces)
|
94
84
|
return var_templates
|
95
85
|
|
96
86
|
def get_pipeline_schemas(self, schema_key=INPUT_SCHEMA_KEY):
|