Skip to content
Merged
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
68 changes: 0 additions & 68 deletions snakemake/config.smk
Original file line number Diff line number Diff line change
Expand Up @@ -54,74 +54,6 @@ class InvalidConfigError(Exception):
pass


def resolve_filepaths(filepaths):
"""
Update filepaths in-place by passing them through resolve_config_path().

`filepaths` must be a list of key tuples representing filepaths in config.
Use "*" as a a key-expansion placeholder: it means "iterate over all keys at
this level".
"""
global config

for keys in filepaths:
_traverse(config, keys, traversed_keys=[])


def _traverse(config_section, keys, traversed_keys):
"""
Recursively walk through the config following a list of keys.

When the final key is reached, the value is updated in place.
"""
key = keys[0]
remaining_keys = keys[1:]

if key == "*":
for key in config_section:
if len(remaining_keys) == 0:
_update_value_inplace(config_section, key, traversed_keys=traversed_keys + [f'* ({key})'])
else:
if isinstance(config_section[key], dict):
_traverse(config_section[key], remaining_keys, traversed_keys=traversed_keys + [f'* ({key})'])
else:
# Value for key is not a dict
# Leave as-is - this may be valid config value.
continue
elif key in config_section:
if len(remaining_keys) == 0:
_update_value_inplace(config_section, key, traversed_keys=traversed_keys + [key])
else:
_traverse(config_section[key], remaining_keys, traversed_keys=traversed_keys + [key])
else:
# Key not present in config section
# Ignore - this may be an optional parameter.
return


def _update_value_inplace(config_section, key, traversed_keys):
"""
Update the value at 'config_section[key]' with resolve_config_path().

resolve_config_path() returns a callable which has the ability to replace
{var} in filepath strings. This was originally designed to support Snakemake
wildcards, but those are not applicable here since this code is not running
in the context of a Snakemake rule. It is unused here - the callable is
given an empty dict.
"""
value = config_section[key]
traversed = ' → '.join(repr(key) for key in traversed_keys)
if isinstance(value, list):
for path in value:
assert isinstance(path, str), f"ERROR: Expected string but got {type(path).__name__} at {traversed}."
new_value = [resolve_config_path(path)({}) for path in value]
else:
assert isinstance(value, str), f"ERROR: Expected string but got {type(value).__name__} at {traversed}."
new_value = resolve_config_path(value)({})
config_section[key] = new_value
print(f"Resolved {value!r} to {new_value!r}.", file=sys.stderr)


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
Expand Down
Loading