-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathconfig.smk
More file actions
77 lines (60 loc) · 3.16 KB
/
Copy pathconfig.smk
File metadata and controls
77 lines (60 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""
Shared functions to be used within a Snakemake workflow for parsing
workflow configs.
"""
import os.path
from collections.abc import Callable
from snakemake.io import Wildcards
from typing import Optional
from textwrap import dedent, indent
class InvalidConfigError(Exception):
pass
def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callable[[Wildcards], str]:
"""
Resolve a relative *path* given in a configuration value. Will always try to
resolve *path* after expanding wildcards with Snakemake's `expand` functionality.
Returns the path for the first existing file, checked in the following order:
1. relative to the analysis directory or workdir, usually given by ``--directory`` (``-d``)
2. relative to *defaults_dir* if it's provided
3. relative to the workflow's ``defaults/`` directory if *defaults_dir* is _not_ provided
This behaviour allows a default configuration value to point to a default
auxiliary file while also letting the file used be overridden either by
setting an alternate file path in the configuration or by creating a file
with the conventional name in the workflow's analysis directory.
"""
global workflow
def _resolve_config_path(wildcards):
try:
expanded_path = expand(path, **wildcards)[0]
except snakemake.exceptions.WildcardError as e:
available_wildcards = "\n".join(f" - {wildcard}" for wildcard in wildcards)
raise snakemake.exceptions.WildcardError(indent(dedent(f"""\
{str(e)}
However, resolve_config_path({{path}}) requires the wildcard.
Wildcards available for this path are:
{{available_wildcards}}
Hint: Check that the config path value does not misspell the wildcard name
and that the rule actually uses the wildcard name.
""".lstrip("\n").rstrip()).format(path=repr(path), available_wildcards=available_wildcards), " " * 4))
if os.path.exists(expanded_path):
return expanded_path
if defaults_dir:
defaults_path = os.path.join(defaults_dir, expanded_path)
else:
# Special-case defaults/… for backwards compatibility with older
# configs. We could achieve the same behaviour with a symlink
# (defaults/defaults → .) but that seems less clear.
if path.startswith("defaults/"):
defaults_path = os.path.join(workflow.basedir, expanded_path)
else:
defaults_path = os.path.join(workflow.basedir, "defaults", expanded_path)
if os.path.exists(defaults_path):
return defaults_path
raise InvalidConfigError(indent(dedent(f"""\
Unable to resolve the config-provided path {path!r},
expanded to {expanded_path!r} after filling in wildcards.
The workflow does not include the default file {defaults_path!r}.
Hint: Check that the file {expanded_path!r} exists in your analysis
directory or remove the config param to use the workflow defaults.
"""), " " * 4))
return _resolve_config_path