Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 28 additions & 36 deletions snakemake/config.smk
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ workflow configs.
import os
import sys
import yaml
from augur.config import resolve_filepath
from collections.abc import Callable
from typing import Optional
from textwrap import dedent, indent


# Set search paths for Augur
# Set search paths
if "AUGUR_SEARCH_PATHS" in os.environ:
print(dedent(f"""\
Using existing search paths in AUGUR_SEARCH_PATHS:
Expand Down Expand Up @@ -46,27 +47,23 @@ else:

search_paths = [path.resolve() for path in search_paths if path.is_dir()]

# For simplicity, ensure search paths are unique (e.g. often the CWD == workflow.basedir)
search_paths = [p for idx,p in enumerate(search_paths) if search_paths.index(p)==idx]

os.environ["AUGUR_SEARCH_PATHS"] = ":".join(map(str, search_paths))


class InvalidConfigError(Exception):
pass


def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callable:
def resolve_config_path(path: str) -> Callable:
"""
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.
Returns the path for the first existing file found relative to directories
defined by the AUGUR_SEARCH_PATHS environment variable.
"""
global workflow

Expand All @@ -88,31 +85,26 @@ def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callab
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))
search_paths = [Path(p) for p in os.environ["AUGUR_SEARCH_PATHS"].split(":")]
try:
return str(resolve_filepath(Path(expanded_path), search_paths))
except Exception as error:
raise InvalidConfigError(
indent(
dedent(f"""
Unable to resolve the config-provided path {path!r},
expanded to {expanded_path!r} after filling in wildcards.

""")
+ str(error)
+ dedent(f"""

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

Expand Down
Loading