looper 2.0.0a1__py3-none-any.whl → 2.0.0a2__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/_version.py +1 -1
- looper/cli_divvy.py +10 -6
- looper/cli_pydantic.py +40 -33
- looper/command_models/arguments.py +9 -0
- looper/command_models/commands.py +1 -0
- looper/conductor.py +1 -0
- looper/divvy.py +9 -2
- looper/exceptions.py +1 -1
- looper/utils.py +82 -76
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/METADATA +13 -14
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/RECORD +15 -15
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/WHEEL +1 -1
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/entry_points.txt +1 -1
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/LICENSE.txt +0 -0
- {looper-2.0.0a1.dist-info → looper-2.0.0a2.dist-info}/top_level.txt +0 -0
looper/_version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "2.0.
|
1
|
+
__version__ = "2.0.0a2"
|
2
2
|
# You must change the version in parser = pydantic_argparse.ArgumentParser in cli_pydantic.py!!!
|
looper/cli_divvy.py
CHANGED
@@ -53,10 +53,10 @@ def build_argparser():
|
|
53
53
|
|
54
54
|
for sp in [sps["list"], sps["write"], sps["submit"], sps["inspect"]]:
|
55
55
|
sp.add_argument(
|
56
|
-
"config", nargs="?", default=None, help="Divvy configuration file."
|
56
|
+
"--config", nargs="?", default=None, help="Divvy configuration file."
|
57
57
|
)
|
58
58
|
|
59
|
-
sps["init"].add_argument("config", default=None, help="Divvy configuration file.")
|
59
|
+
sps["init"].add_argument("--config", default=None, help="Divvy configuration file.")
|
60
60
|
|
61
61
|
for sp in [sps["inspect"]]:
|
62
62
|
sp.add_argument(
|
@@ -124,9 +124,11 @@ def main():
|
|
124
124
|
sys.exit(0)
|
125
125
|
|
126
126
|
_LOGGER.debug("Divvy config: {}".format(args.config))
|
127
|
+
|
127
128
|
divcfg = select_divvy_config(args.config)
|
129
|
+
|
128
130
|
_LOGGER.info("Using divvy config: {}".format(divcfg))
|
129
|
-
dcc = ComputingConfiguration(filepath=divcfg)
|
131
|
+
dcc = ComputingConfiguration.from_yaml_file(filepath=divcfg)
|
130
132
|
|
131
133
|
if args.command == "list":
|
132
134
|
# Output header via logger and content via print so the user can
|
@@ -142,11 +144,13 @@ def main():
|
|
142
144
|
for pkg_name, pkg in dcc.compute_packages.items():
|
143
145
|
if pkg_name == args.package:
|
144
146
|
found = True
|
145
|
-
with open(pkg
|
147
|
+
with open(pkg["submission_template"], "r") as f:
|
146
148
|
print(f.read())
|
147
|
-
_LOGGER.info(
|
149
|
+
_LOGGER.info(
|
150
|
+
"Submission command is: " + pkg["submission_command"] + "\n"
|
151
|
+
)
|
148
152
|
if pkg_name == "docker":
|
149
|
-
print("Docker args are: " + pkg
|
153
|
+
print("Docker args are: " + pkg["docker_args"])
|
150
154
|
|
151
155
|
if not found:
|
152
156
|
_LOGGER.info("Package not found. Use 'divvy list' to see list of packages.")
|
looper/cli_pydantic.py
CHANGED
@@ -26,8 +26,6 @@ from eido import inspect_project
|
|
26
26
|
from pephubclient import PEPHubClient
|
27
27
|
from pydantic_argparse.argparse.parser import ArgumentParser
|
28
28
|
|
29
|
-
from divvy import select_divvy_config
|
30
|
-
|
31
29
|
from . import __version__
|
32
30
|
|
33
31
|
from .command_models.arguments import ArgumentEnum
|
@@ -128,15 +126,8 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
|
|
128
126
|
console = Console()
|
129
127
|
console.clear()
|
130
128
|
console.rule(f"\n[magenta]Looper initialization[/magenta]")
|
131
|
-
|
132
|
-
|
133
|
-
)
|
134
|
-
|
135
|
-
selection = None
|
136
|
-
while selection not in ["y", "n"]:
|
137
|
-
selection = console.input("\nSelection: ").lower().strip()
|
138
|
-
|
139
|
-
if selection == "n":
|
129
|
+
selection = subcommand_args.generic
|
130
|
+
if selection is True:
|
140
131
|
console.clear()
|
141
132
|
return int(
|
142
133
|
not initiate_looper_config(
|
@@ -172,11 +163,14 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
|
|
172
163
|
else:
|
173
164
|
setattr(subcommand_args, looper_config_key, looper_config_item)
|
174
165
|
|
175
|
-
except OSError:
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
166
|
+
except OSError as e:
|
167
|
+
if subcommand_args.config:
|
168
|
+
_LOGGER.warning(
|
169
|
+
f"\nLooper config file does not exist at given path {subcommand_args.config}. Use looper init to create one at {looper_cfg_path}."
|
170
|
+
)
|
171
|
+
else:
|
172
|
+
_LOGGER.warning(e)
|
173
|
+
|
180
174
|
sys.exit(1)
|
181
175
|
|
182
176
|
subcommand_args = enrich_args_via_cfg(
|
@@ -225,7 +219,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
|
|
225
219
|
amendments=subcommand_args.amend,
|
226
220
|
divcfg_path=divcfg,
|
227
221
|
runp=subcommand_name == "runp",
|
228
|
-
project_dict=PEPHubClient().
|
222
|
+
project_dict=PEPHubClient().load_raw_pep(
|
229
223
|
registry_path=subcommand_args.pep_config
|
230
224
|
),
|
231
225
|
**{
|
@@ -340,13 +334,13 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
|
|
340
334
|
_LOGGER.warning("No looper configuration was supplied.")
|
341
335
|
|
342
336
|
|
343
|
-
def main(test_args=None) ->
|
337
|
+
def main(test_args=None) -> dict:
|
344
338
|
parser = pydantic_argparse.ArgumentParser(
|
345
339
|
model=TopLevelParser,
|
346
340
|
prog="looper",
|
347
341
|
description="Looper: A job submitter for Portable Encapsulated Projects",
|
348
342
|
add_help=True,
|
349
|
-
version="2.0.
|
343
|
+
version="2.0.0a2",
|
350
344
|
)
|
351
345
|
|
352
346
|
parser = add_short_arguments(parser, ArgumentEnum)
|
@@ -359,6 +353,10 @@ def main(test_args=None) -> None:
|
|
359
353
|
return run_looper(args, parser, test_args=test_args)
|
360
354
|
|
361
355
|
|
356
|
+
def main_cli() -> None:
|
357
|
+
main()
|
358
|
+
|
359
|
+
|
362
360
|
def _proc_resources_spec(args):
|
363
361
|
"""
|
364
362
|
Process CLI-sources compute setting specification. There are two sources
|
@@ -385,20 +383,29 @@ def _proc_resources_spec(args):
|
|
385
383
|
settings_data = {}
|
386
384
|
if not spec:
|
387
385
|
return settings_data
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
386
|
+
if isinstance(
|
387
|
+
spec, str
|
388
|
+
): # compute: "partition=standard time='01-00:00:00' cores='32' mem='32000'"
|
389
|
+
spec = spec.split(sep=" ")
|
390
|
+
if isinstance(spec, list):
|
391
|
+
pairs = [(kv, kv.split("=")) for kv in spec]
|
392
|
+
bads = []
|
393
|
+
for orig, pair in pairs:
|
394
|
+
try:
|
395
|
+
k, v = pair
|
396
|
+
except ValueError:
|
397
|
+
bads.append(orig)
|
398
|
+
else:
|
399
|
+
settings_data[k] = v
|
400
|
+
if bads:
|
401
|
+
raise ValueError(
|
402
|
+
"Could not correctly parse itemized compute specification. "
|
403
|
+
"Correct format: " + EXAMPLE_COMPUTE_SPEC_FMT
|
404
|
+
)
|
405
|
+
elif isinstance(spec, dict):
|
406
|
+
for key, value in spec.items():
|
407
|
+
settings_data[key] = value
|
408
|
+
|
402
409
|
return settings_data
|
403
410
|
|
404
411
|
|
@@ -184,6 +184,14 @@ class ArgumentEnum(enum.Enum):
|
|
184
184
|
default=(str, None),
|
185
185
|
description="Output directory",
|
186
186
|
)
|
187
|
+
|
188
|
+
GENERIC = Argument(
|
189
|
+
name="generic",
|
190
|
+
alias="-g",
|
191
|
+
default=(bool, False),
|
192
|
+
description="Use generic looper config?",
|
193
|
+
)
|
194
|
+
|
187
195
|
SAMPLE_PIPELINE_INTERFACES = Argument(
|
188
196
|
name="sample_pipeline_interfaces",
|
189
197
|
alias="-S",
|
@@ -228,6 +236,7 @@ class ArgumentEnum(enum.Enum):
|
|
228
236
|
)
|
229
237
|
PACKAGE = Argument(
|
230
238
|
name="package",
|
239
|
+
alias="-p",
|
231
240
|
default=(str, None),
|
232
241
|
description="Name of computing resource package to use",
|
233
242
|
)
|
looper/conductor.py
CHANGED
@@ -661,6 +661,7 @@ class SubmissionConductor(object):
|
|
661
661
|
"record_identifier": psm.record_identifier,
|
662
662
|
"config_file": psm.config_path,
|
663
663
|
"output_schema": psm.cfg["_schema_path"],
|
664
|
+
"pephub_path": psm.cfg["pephub_path"],
|
664
665
|
}
|
665
666
|
filtered_namespace = {k: v for k, v in full_namespace.items() if v}
|
666
667
|
return YAMLConfigManager(filtered_namespace)
|
looper/divvy.py
CHANGED
@@ -200,6 +200,11 @@ class ComputingConfiguration(YAMLConfigManager):
|
|
200
200
|
"""
|
201
201
|
return self.compute
|
202
202
|
|
203
|
+
@property
|
204
|
+
def compute_packages(self):
|
205
|
+
|
206
|
+
return self["compute_packages"]
|
207
|
+
|
203
208
|
def list_compute_packages(self):
|
204
209
|
"""
|
205
210
|
Returns a list of available compute packages.
|
@@ -396,11 +401,13 @@ def divvy_init(config_path, template_config_path):
|
|
396
401
|
_LOGGER.error("You must specify a template config file path.")
|
397
402
|
return
|
398
403
|
|
404
|
+
if not os.path.isabs(config_path):
|
405
|
+
config_path = os.path.abspath(config_path)
|
406
|
+
|
399
407
|
if config_path and not os.path.exists(config_path):
|
400
|
-
# dcc.write(config_path)
|
401
408
|
# Init should *also* write the templates.
|
402
409
|
dest_folder = os.path.dirname(config_path)
|
403
|
-
copytree(os.path.dirname(template_config_path), dest_folder)
|
410
|
+
copytree(os.path.dirname(template_config_path), dest_folder, dirs_exist_ok=True)
|
404
411
|
template_subfolder = os.path.join(dest_folder, "divvy_templates")
|
405
412
|
_LOGGER.info("Wrote divvy templates to folder: {}".format(template_subfolder))
|
406
413
|
new_template = os.path.join(
|
looper/exceptions.py
CHANGED
@@ -31,7 +31,7 @@ class SampleFailedException(LooperError):
|
|
31
31
|
|
32
32
|
|
33
33
|
class MisconfigurationException(LooperError):
|
34
|
-
"""
|
34
|
+
"""Looper not properly configured"""
|
35
35
|
|
36
36
|
def __init__(self, key):
|
37
37
|
super(MisconfigurationException, self).__init__(key)
|
looper/utils.py
CHANGED
@@ -17,6 +17,7 @@ from ubiquerg import convert_value, expandpath, parse_registry_path, deep_update
|
|
17
17
|
from pephubclient.constants import RegistryPath
|
18
18
|
from pydantic import ValidationError
|
19
19
|
from yacman import load_yaml
|
20
|
+
from yaml.parser import ParserError
|
20
21
|
|
21
22
|
from .const import *
|
22
23
|
from .command_models.commands import SUPPORTED_COMMANDS
|
@@ -263,31 +264,29 @@ def enrich_args_via_cfg(
|
|
263
264
|
cli_modifiers=None,
|
264
265
|
):
|
265
266
|
"""
|
266
|
-
Read in a looper dotfile and set arguments.
|
267
|
+
Read in a looper dotfile, pep config and set arguments.
|
267
268
|
|
268
|
-
Priority order: CLI > dotfile/config > parser default
|
269
|
+
Priority order: CLI > dotfile/config > pep_config > parser default
|
269
270
|
|
270
271
|
:param subcommand name: the name of the command used
|
271
272
|
:param argparse.Namespace parser_args: parsed args by the original parser
|
272
|
-
:param argparse.Namespace aux_parser: parsed args by the
|
273
|
+
:param argparse.Namespace aux_parser: parsed args by the argument parser
|
273
274
|
with defaults suppressed
|
275
|
+
:param dict test_args: dict of args used for pytesting
|
276
|
+
:param dict cli_modifiers: dict of args existing if user supplied cli args in looper config file
|
274
277
|
:return argparse.Namespace: selected argument values
|
275
278
|
"""
|
279
|
+
|
280
|
+
# Did the user provide arguments in the PEP config?
|
276
281
|
cfg_args_all = (
|
277
282
|
_get_subcommand_args(subcommand_name, parser_args)
|
278
283
|
if os.path.exists(parser_args.pep_config)
|
279
284
|
else dict()
|
280
285
|
)
|
281
|
-
|
282
|
-
# If user provided project-level modifiers in the looper config, they are prioritized
|
283
|
-
if cfg_args_all:
|
284
|
-
for key, value in cfg_args_all.items():
|
285
|
-
if getattr(parser_args, key, None):
|
286
|
-
new_value = getattr(parser_args, key)
|
287
|
-
cfg_args_all[key] = new_value
|
288
|
-
else:
|
286
|
+
if not cfg_args_all:
|
289
287
|
cfg_args_all = {}
|
290
288
|
|
289
|
+
# Did the user provide arguments/modifiers in the looper config file?
|
291
290
|
looper_config_cli_modifiers = None
|
292
291
|
if cli_modifiers:
|
293
292
|
if str(subcommand_name) in cli_modifiers:
|
@@ -312,6 +311,13 @@ def enrich_args_via_cfg(
|
|
312
311
|
else:
|
313
312
|
cli_args, _ = aux_parser.parse_known_args()
|
314
313
|
|
314
|
+
# If any CLI args were provided, make sure they take priority
|
315
|
+
if cli_args:
|
316
|
+
r = getattr(cli_args, subcommand_name)
|
317
|
+
for k, v in cfg_args_all.items():
|
318
|
+
if k in r:
|
319
|
+
cfg_args_all[k] = getattr(r, k)
|
320
|
+
|
315
321
|
def set_single_arg(argname, default_source_namespace, result_namespace):
|
316
322
|
if argname not in POSITIONAL or not hasattr(result, argname):
|
317
323
|
if argname in cli_args:
|
@@ -324,6 +330,8 @@ def enrich_args_via_cfg(
|
|
324
330
|
elif cfg_args_all is not None and argname in cfg_args_all:
|
325
331
|
if isinstance(cfg_args_all[argname], list):
|
326
332
|
r = [convert_value(i) for i in cfg_args_all[argname]]
|
333
|
+
elif isinstance(cfg_args_all[argname], dict):
|
334
|
+
r = cfg_args_all[argname]
|
327
335
|
else:
|
328
336
|
r = convert_value(cfg_args_all[argname])
|
329
337
|
else:
|
@@ -432,9 +440,8 @@ def init_generic_pipeline(pipelinepath: Optional[str] = None):
|
|
432
440
|
generic_pipeline_dict = {
|
433
441
|
"pipeline_name": "default_pipeline_name",
|
434
442
|
"output_schema": "output_schema.yaml",
|
435
|
-
"var_templates": {"pipeline": "{looper.piface_dir}/count_lines.sh"},
|
436
443
|
"sample_interface": {
|
437
|
-
"command_template": "{
|
444
|
+
"command_template": "{looper.piface_dir}/count_lines.sh {sample.file} "
|
438
445
|
"--output-parent {looper.sample_output_folder}"
|
439
446
|
},
|
440
447
|
}
|
@@ -627,8 +634,6 @@ def looper_config_tutorial():
|
|
627
634
|
console.print("Use [yellow]`looper run`[/yellow] afterwards to run the pipeline.")
|
628
635
|
console.print("Press [yellow]^C[/yellow] at any time to quit.\n")
|
629
636
|
|
630
|
-
console.input("> ... ")
|
631
|
-
|
632
637
|
DEFAULTS = { # What you get if you just press enter
|
633
638
|
"pep_config": "databio/example",
|
634
639
|
"output_dir": "results",
|
@@ -636,73 +641,58 @@ def looper_config_tutorial():
|
|
636
641
|
"project_name": os.path.basename(os.getcwd()),
|
637
642
|
}
|
638
643
|
|
639
|
-
|
644
|
+
cfg["project_name"] = (
|
645
|
+
console.input(f"Project name: [yellow]({DEFAULTS['project_name']})[/yellow] >")
|
646
|
+
or DEFAULTS["project_name"]
|
647
|
+
)
|
640
648
|
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
f"Project name: [yellow]({DEFAULTS['project_name']})[/yellow] >"
|
645
|
-
)
|
646
|
-
or DEFAULTS["project_name"]
|
649
|
+
cfg["pep_config"] = (
|
650
|
+
console.input(
|
651
|
+
f"Registry path or file path to PEP: [yellow]({DEFAULTS['pep_config']})[/yellow] >"
|
647
652
|
)
|
653
|
+
or DEFAULTS["pep_config"]
|
654
|
+
)
|
648
655
|
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
656
|
+
if not os.path.exists(cfg["pep_config"]) and not is_pephub_registry_path(
|
657
|
+
cfg["pep_config"]
|
658
|
+
):
|
659
|
+
console.print(
|
660
|
+
f"Warning: PEP file does not exist at [yellow]'{cfg['pep_config']}[/yellow]'"
|
654
661
|
)
|
655
662
|
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
663
|
+
cfg["output_dir"] = (
|
664
|
+
console.input(
|
665
|
+
f"Path to output directory: [yellow]({DEFAULTS['output_dir']})[/yellow] >"
|
666
|
+
)
|
667
|
+
or DEFAULTS["output_dir"]
|
668
|
+
)
|
660
669
|
|
661
|
-
|
670
|
+
add_more_pifaces = True
|
671
|
+
piface_paths = []
|
672
|
+
while add_more_pifaces:
|
673
|
+
piface_path = (
|
662
674
|
console.input(
|
663
|
-
|
675
|
+
"Add each path to a pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >"
|
664
676
|
)
|
665
|
-
or
|
677
|
+
or None
|
666
678
|
)
|
679
|
+
if piface_path is None:
|
680
|
+
if piface_paths == []:
|
681
|
+
piface_paths.append(DEFAULTS["piface_path"])
|
682
|
+
add_more_pifaces = False
|
683
|
+
else:
|
684
|
+
piface_paths.append(piface_path)
|
667
685
|
|
668
|
-
|
669
|
-
piface_paths = []
|
670
|
-
while add_more_pifaces:
|
671
|
-
piface_path = (
|
672
|
-
console.input(
|
673
|
-
"Add each path to a pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >"
|
674
|
-
)
|
675
|
-
or None
|
676
|
-
)
|
677
|
-
if piface_path is None:
|
678
|
-
if piface_paths == []:
|
679
|
-
piface_paths.append(DEFAULTS["piface_path"])
|
680
|
-
add_more_pifaces = False
|
681
|
-
else:
|
682
|
-
piface_paths.append(piface_path)
|
683
|
-
|
684
|
-
console.print("\n")
|
685
|
-
|
686
|
-
console.print(
|
687
|
-
f"""\
|
688
|
-
[yellow]pep_config:[/yellow] {cfg['pep_config']}
|
689
|
-
[yellow]output_dir:[/yellow] {cfg['output_dir']}
|
690
|
-
[yellow]pipeline_interfaces:[/yellow]
|
691
|
-
- {piface_paths}
|
692
|
-
"""
|
693
|
-
)
|
686
|
+
console.print("\n")
|
694
687
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
pass
|
704
|
-
if selection == "y":
|
705
|
-
creating = False
|
688
|
+
console.print(
|
689
|
+
f"""\
|
690
|
+
[yellow]pep_config:[/yellow] {cfg['pep_config']}
|
691
|
+
[yellow]output_dir:[/yellow] {cfg['output_dir']}
|
692
|
+
[yellow]pipeline_interfaces:[/yellow]
|
693
|
+
- {piface_paths}
|
694
|
+
"""
|
695
|
+
)
|
706
696
|
|
707
697
|
for piface_path in piface_paths:
|
708
698
|
if not os.path.exists(piface_path):
|
@@ -727,7 +717,7 @@ def looper_config_tutorial():
|
|
727
717
|
looper_config_dict = {}
|
728
718
|
looper_config_dict["pep_config"] = cfg["pep_config"]
|
729
719
|
looper_config_dict["output_dir"] = cfg["output_dir"]
|
730
|
-
looper_config_dict["pipeline_interfaces"] =
|
720
|
+
looper_config_dict["pipeline_interfaces"] = piface_paths
|
731
721
|
|
732
722
|
with open(looper_cfg_path, "w") as fp:
|
733
723
|
yaml.dump(looper_config_dict, fp)
|
@@ -747,7 +737,15 @@ def determine_pipeline_type(piface_path: str, looper_config_path: str):
|
|
747
737
|
|
748
738
|
if piface_path is None:
|
749
739
|
return None, None
|
750
|
-
|
740
|
+
try:
|
741
|
+
piface_path = expandpath(piface_path)
|
742
|
+
except TypeError as e:
|
743
|
+
_LOGGER.warning(
|
744
|
+
f"Pipeline interface not found at given path: {piface_path}. Type Error: "
|
745
|
+
+ str(e)
|
746
|
+
)
|
747
|
+
return None, None
|
748
|
+
|
751
749
|
if not os.path.isabs(piface_path):
|
752
750
|
piface_path = os.path.realpath(
|
753
751
|
os.path.join(os.path.dirname(looper_config_path), piface_path)
|
@@ -755,6 +753,7 @@ def determine_pipeline_type(piface_path: str, looper_config_path: str):
|
|
755
753
|
try:
|
756
754
|
piface_dict = load_yaml(piface_path)
|
757
755
|
except FileNotFoundError:
|
756
|
+
_LOGGER.warning(f"Pipeline interface not found at given path: {piface_path}")
|
758
757
|
return None, None
|
759
758
|
|
760
759
|
pipeline_types = []
|
@@ -783,12 +782,18 @@ def read_looper_config_file(looper_config_path: str) -> dict:
|
|
783
782
|
:raise MisconfigurationException: incorrect configuration.
|
784
783
|
"""
|
785
784
|
return_dict = {}
|
786
|
-
|
787
|
-
|
785
|
+
|
786
|
+
try:
|
787
|
+
with open(looper_config_path, "r") as dotfile:
|
788
|
+
dp_data = yaml.safe_load(dotfile)
|
789
|
+
except ParserError as e:
|
790
|
+
_LOGGER.warning(
|
791
|
+
"Could not load looper config file due to the following exception"
|
792
|
+
)
|
793
|
+
raise ParserError(context=str(e))
|
788
794
|
|
789
795
|
if PEP_CONFIG_KEY in dp_data:
|
790
796
|
return_dict[PEP_CONFIG_KEY] = dp_data[PEP_CONFIG_KEY]
|
791
|
-
|
792
797
|
else:
|
793
798
|
raise MisconfigurationException(
|
794
799
|
f"Looper dotfile ({looper_config_path}) is missing '{PEP_CONFIG_KEY}' key"
|
@@ -846,6 +851,7 @@ def read_looper_config_file(looper_config_path: str) -> dict:
|
|
846
851
|
for k, v in return_dict.items():
|
847
852
|
if k == SAMPLE_PL_ARG or k == PROJECT_PL_ARG:
|
848
853
|
# Pipeline interfaces are resolved at a later point. Do it there only to maintain consistency. #474
|
854
|
+
|
849
855
|
pass
|
850
856
|
if isinstance(v, str):
|
851
857
|
v = expandpath(v)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: looper
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.0a2
|
4
4
|
Summary: A pipeline submission engine that parses sample inputs and submits pipelines for each sample.
|
5
5
|
Home-page: https://github.com/pepkit/looper
|
6
6
|
Author: Nathan Sheffield, Vince Reuter, Michal Stolarczyk, Johanna Klughammer, Andre Rendeiro
|
@@ -15,20 +15,19 @@ Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
16
16
|
Description-Content-Type: text/markdown
|
17
17
|
License-File: LICENSE.txt
|
18
|
-
Requires-Dist: colorama
|
19
|
-
Requires-Dist:
|
20
|
-
Requires-Dist: eido >=0.2.1
|
18
|
+
Requires-Dist: colorama>=0.3.9
|
19
|
+
Requires-Dist: eido>=0.2.3
|
21
20
|
Requires-Dist: jinja2
|
22
|
-
Requires-Dist: logmuse
|
23
|
-
Requires-Dist: pandas
|
24
|
-
Requires-Dist: pephubclient
|
25
|
-
Requires-Dist: pipestat
|
26
|
-
Requires-Dist: peppy
|
27
|
-
Requires-Dist: pyyaml
|
28
|
-
Requires-Dist: rich
|
29
|
-
Requires-Dist: ubiquerg
|
30
|
-
Requires-Dist: yacman
|
31
|
-
Requires-Dist: pydantic-argparse
|
21
|
+
Requires-Dist: logmuse>=0.2.0
|
22
|
+
Requires-Dist: pandas>=2.0.2
|
23
|
+
Requires-Dist: pephubclient>=0.4.0
|
24
|
+
Requires-Dist: pipestat>=0.10.2
|
25
|
+
Requires-Dist: peppy>=0.40.6
|
26
|
+
Requires-Dist: pyyaml>=3.12
|
27
|
+
Requires-Dist: rich>=9.10.0
|
28
|
+
Requires-Dist: ubiquerg>=0.8.1a1
|
29
|
+
Requires-Dist: yacman==0.9.3
|
30
|
+
Requires-Dist: pydantic-argparse>=0.9.0
|
32
31
|
Requires-Dist: psutil
|
33
32
|
|
34
33
|
# <img src="docs/img/looper_logo.svg" alt="looper logo" height="70">
|
@@ -1,24 +1,24 @@
|
|
1
1
|
looper/__init__.py,sha256=f_z9YY4ibOk7eyWoaViH_VaCXMlPQeiftbnibSFj-3E,1333
|
2
2
|
looper/__main__.py,sha256=OOCmI-dPUvInnJHkHNMf54cblNJ3Yl9ELOwZcfOXmD8,240
|
3
|
-
looper/_version.py,sha256=
|
4
|
-
looper/cli_divvy.py,sha256=
|
5
|
-
looper/cli_pydantic.py,sha256=
|
6
|
-
looper/conductor.py,sha256=
|
3
|
+
looper/_version.py,sha256=mX3fglKqsJRTjP938X3Xm2eAJT9fve28fdydFnJFimc,121
|
4
|
+
looper/cli_divvy.py,sha256=_VGbOFLkXtKdkZA6omlzgXbXkuUM5aLQ50aTTtbTrVI,5975
|
5
|
+
looper/cli_pydantic.py,sha256=uysPJfTrfG7-k7u6oDpaLG-3hD6U8YVrDiOW54ySniI,14425
|
6
|
+
looper/conductor.py,sha256=lzY6Gzsb8oX-KLzLkRa0XrYWSxLeiy6jRmmD15WNAkw,35116
|
7
7
|
looper/const.py,sha256=OscEELQsyLKlSrmwuXfyLRwpAUJUEpGD2UxBeLJDXgw,8703
|
8
|
-
looper/divvy.py,sha256=
|
9
|
-
looper/exceptions.py,sha256=
|
8
|
+
looper/divvy.py,sha256=eiYhcp8ZgQ0uzlk0c5yJp0QaiVrQYfSeEtmQBJiScOM,15417
|
9
|
+
looper/exceptions.py,sha256=AxYCTLxKb_fJFgU9VBnPYaRX2lGhmMEYaCbJOi-27Wk,3384
|
10
10
|
looper/looper.py,sha256=ZWTulMz6NobnYFUjev513TJwXqknrb4_gZrV-a_fT9g,30041
|
11
11
|
looper/parser_types.py,sha256=d3FHt54f9jo9VZMr5SQkbghcAdABqiYZW2JBGO5EBnw,2327
|
12
12
|
looper/pipeline_interface.py,sha256=mN4-XICyZzuVLTOq3b0ijppYe6ib_Ljlyf6KxZCJh2A,14537
|
13
13
|
looper/plugins.py,sha256=MaMdPmK9U_4FkNJE5kccohBbY1i2qj1NTEucubFOJek,5747
|
14
14
|
looper/processed_project.py,sha256=jZxoMYafvr-OHFxylc5ivGty1VwXBZhl0kgoFkY-174,9837
|
15
15
|
looper/project.py,sha256=SFHdi58eRBWtye5lUFhwzBcG7ejrMurmDzmkrC3XAic,34339
|
16
|
-
looper/utils.py,sha256
|
16
|
+
looper/utils.py,sha256=-4QlScIB7eewIbmEJdAv2d0ZE0qr_q9acm2XUOiMEek,39769
|
17
17
|
looper/command_models/DEVELOPER.md,sha256=eRxnrO-vqNJjExzamXKEq5wr_-Zw6PQEwkS9RPinYrk,2775
|
18
18
|
looper/command_models/README.md,sha256=3RGegeZlTZYnhcHXRu6bdI_81WZom2q7QYMV-KGYY7U,588
|
19
19
|
looper/command_models/__init__.py,sha256=6QWC2TewowEL7dATli5YpMmFWuXaLEPktofJCXkYUBI,187
|
20
|
-
looper/command_models/arguments.py,sha256=
|
21
|
-
looper/command_models/commands.py,sha256=
|
20
|
+
looper/command_models/arguments.py,sha256=wGGc5tleHC31F0etbiYaumHwP5xlJsSXapJ10lhltHg,8830
|
21
|
+
looper/command_models/commands.py,sha256=RMTiHg0txBGDb_fHfhTWujP3VnnB6ROCHqByiwgMS4c,9716
|
22
22
|
looper/default_config/divvy_config.yaml,sha256=wK5kLDGBV2wwoyqg2rl3X8SXjds4x0mwBUjUzF1Ln7g,1705
|
23
23
|
looper/default_config/divvy_templates/localhost_bulker_template.sub,sha256=yn5VB9Brt7Hck9LT17hD2o8Kn-76gYJQk_A-8C1Gr4k,164
|
24
24
|
looper/default_config/divvy_templates/localhost_docker_template.sub,sha256=XRr7AlR7-TP1L3hyBMfka_RgWRL9vzOlS5Kd1xSNwT0,183
|
@@ -60,9 +60,9 @@ looper/schemas/divvy_config_schema.yaml,sha256=7GJfKLc3VX4RGjHnOE1zxwsHXhj_ur9za
|
|
60
60
|
looper/schemas/pipeline_interface_schema_generic.yaml,sha256=3YfKFyRUIwxG41FEidR1dXe9IU6ye51LSUBfSpmMuss,1773
|
61
61
|
looper/schemas/pipeline_interface_schema_project.yaml,sha256=-ZWyA0lKXWik3obuLNVk3IsAZYfbLVbCDvJnD-Fcluo,1567
|
62
62
|
looper/schemas/pipeline_interface_schema_sample.yaml,sha256=x0OwVnijJpvm50DscvvJujdK4UAI7d71pqVemQS-D-0,1564
|
63
|
-
looper-2.0.
|
64
|
-
looper-2.0.
|
65
|
-
looper-2.0.
|
66
|
-
looper-2.0.
|
67
|
-
looper-2.0.
|
68
|
-
looper-2.0.
|
63
|
+
looper-2.0.0a2.dist-info/LICENSE.txt,sha256=oB6ZGDa4kcznznJKJsLLFFcOZyi8Y6e2Jv0rJozgp-I,1269
|
64
|
+
looper-2.0.0a2.dist-info/METADATA,sha256=s4IlCgd597EhgR8H0LIB-3Qz02absf63sudpuFG1rKM,1760
|
65
|
+
looper-2.0.0a2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
66
|
+
looper-2.0.0a2.dist-info/entry_points.txt,sha256=iHltI2_Jdved27vccmWhvmcHWUZ7Mf6CfDV6QkY1Lc8,91
|
67
|
+
looper-2.0.0a2.dist-info/top_level.txt,sha256=I0Yf7djsoQAMzwHBbDiQi9hGtq4Z41_Ma5CX8qXG8Y8,7
|
68
|
+
looper-2.0.0a2.dist-info/RECORD,,
|
File without changes
|
File without changes
|