Skip to content

Commit

Permalink
Merge pull request #410 from MannLabs/change_config_handling
Browse files Browse the repository at this point in the history
Change config handling
  • Loading branch information
mschwoer authored Jan 9, 2025
2 parents 23bd169 + c23115d commit 8f32e51
Show file tree
Hide file tree
Showing 20 changed files with 274 additions and 262 deletions.
74 changes: 35 additions & 39 deletions alphadia/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@

import alphadia
from alphadia import utils
from alphadia.constants.keys import ConfigKeys
from alphadia.exceptions import CustomError
from alphadia.search_plan import SearchPlan
from alphadia.workflow import reporting

logger = logging.getLogger()

epilog = "Parameters passed via CLI will overwrite parameters from config file (except for '--file': will be merged)."

parser = argparse.ArgumentParser(description="Search DIA experiments with alphaDIA")
parser = argparse.ArgumentParser(
description="Search DIA experiments with alphaDIA", epilog=epilog
)
parser.add_argument(
"--version",
"-v",
Expand All @@ -32,17 +36,19 @@
)
parser.add_argument(
"--output",
"--output-directory",
"-o",
type=str,
help="Output directory",
help="Output directory.",
nargs="?",
default=None,
)
parser.add_argument(
"--file",
"--raw-path",
"-f",
type=str,
help="Raw data input files.",
help="Path to raw data input file. Can be passed multiple times.",
action="append",
default=[],
)
Expand All @@ -58,43 +64,46 @@
"--regex",
"-r",
type=str,
help="Regex to match raw files in directory.",
help="Regex to match raw files in 'directory'.",
nargs="?",
default=".*",
)
parser.add_argument(
"--library",
"--library-path",
"-l",
type=str,
help="Spectral library.",
help="Path to spectral library file.",
nargs="?",
default=None,
)
parser.add_argument(
"--fasta",
help="Fasta file(s) used to generate or annotate the spectral library.",
"--fasta-path",
help="Path to fasta file used to generate or annotate the spectral library. Can be passed multiple times.",
action="append",
default=[],
)
parser.add_argument(
"--config",
"-c",
type=str,
help="Config yaml which will be used to update the default config.",
help="Path to config yaml file which will be used to update the default config.",
nargs="?",
default=None,
)
parser.add_argument(
"--config-dict",
type=str,
help="Python Dict which will be used to update the default config.",
help="Python dictionary which will be used to update the default config.",
nargs="?",
default="{}",
)
parser.add_argument(
"--quant-dir",
"--quant-dir", # TODO deprecate
"--quant-directory",
type=str,
help="Directory to save the quantification results (psm & frag parquet files) to be reused in a distributed search",
help="Directory to save the quantification results (psm & frag parquet files) to be reused in a distributed search.",
nargs="?",
default=None,
)
Expand Down Expand Up @@ -148,7 +157,7 @@ def _get_raw_path_list_from_args_and_config(
list: a list of file paths that match the specified regex pattern.
"""

raw_path_list = config.get("raw_path_list", [])
raw_path_list = config.get(ConfigKeys.RAW_PATHS, [])
raw_path_list += args.file

if (config_directory := config.get("directory")) is not None:
Expand All @@ -172,17 +181,6 @@ def _get_raw_path_list_from_args_and_config(
return raw_path_list


def _get_fasta_list_from_args_and_config(
args: argparse.Namespace, config: dict
) -> list:
"""Parse fasta file list from command line arguments and config file, merging them if both are given."""

fasta_path_list = config.get("fasta_list", [])
fasta_path_list += args.fasta

return fasta_path_list


def run(*args, **kwargs):
# parse command line arguments
args, unknown = parser.parse_known_args()
Expand All @@ -203,33 +201,31 @@ def run(*args, **kwargs):
)
if output_directory is None:
parser.print_help()
print("No output directory specified.")

print("No output directory specified. Please do so via CL-argument or config.")
return
reporting.init_logging(output_directory)

quant_dir = _get_from_args_or_config(
args, user_config, args_key="quant_dir", config_key="quant_dir"
)
raw_path_list = _get_raw_path_list_from_args_and_config(args, user_config)
library_path = _get_from_args_or_config(
args, user_config, args_key="library", config_key="library"
)
fasta_path_list = _get_fasta_list_from_args_and_config(args, user_config)
# TODO revisit the multiple sources of raw files (cli, config, regex, ...)
raw_paths = _get_raw_path_list_from_args_and_config(args, user_config)
cli_params_config = {
**({ConfigKeys.RAW_PATHS: raw_paths} if raw_paths else {}),
**({ConfigKeys.LIBRARY_PATH: args.library} if args.library is not None else {}),
**({ConfigKeys.FASTA_PATHS: args.library} if args.fasta else {}),
**(
{ConfigKeys.QUANT_DIRECTORY: args.library}
if args.quant_dir is not None
else {}
),
}

# TODO rename all output_directory, output_folder => output_path, quant_dir->quant_path (except cli parameter)

# important to suppress matplotlib output
matplotlib.use("Agg")

try:
SearchPlan(
output_directory,
raw_path_list=raw_path_list,
library_path=library_path,
fasta_path_list=fasta_path_list,
config=user_config,
quant_path=quant_dir,
).run_plan()
SearchPlan(output_directory, user_config, cli_params_config).run_plan()

except Exception as e:
if isinstance(e, CustomError):
Expand Down
22 changes: 12 additions & 10 deletions alphadia/constants/default.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# configuration for the extraction plan
version: 1

library: null
# These values are typically filled via CLI parameters
output_directory: null
raw_path_list: []
output: null
library_path: null
raw_paths: []
fasta_paths: []
quant_directory: null

general:
thread_count: 10
Expand Down Expand Up @@ -63,31 +65,31 @@ library_prediction:
# composition: H(-2)2H(8)13C(2)
custom_modifications:
# Dimethyl @K channel decoy
Dimethyl:d12@K:
- name: Dimethyl:d12@K
composition: H(-2)2H(8)13C(2)

# Dimethyl @Any_N-term channel decoy
Dimethyl:d12@Any_N-term:
- name: Dimethyl:d12@Any_N-term
composition: H(-2)2H(8)13C(2)

# Dimethyl @Protein_N-term channel decoy
Dimethyl:d12@Protein_N-term:
- name: Dimethyl:d12@Protein_N-term
composition: H(-2)2H(8)13C(2)

# mTRAQ @K channel decoy
mTRAQ:d12@K:
- name: mTRAQ:d12@K
composition: H(12)C(1)13C(10)15N(2)O(1)

# mTRAQ @Any_N-term channel decoy
mTRAQ:d12@Any_N-term:
- name: mTRAQ:d12@Any_N-term
composition: H(12)C(1)13C(14)15N(2)O(1)

# mTRAQ @Protein_N-term channel decoy
mTRAQ:d12@Protein_N-term:
- name: mTRAQ:d12@Protein_N-term
composition: H(12)C(1)13C(14)15N(2)O(1)

# SILAC heavy @K channel decoy
Label:13C(12)@K:
- name: Label:13C(12)@K
composition: C(12)

search:
Expand Down
10 changes: 10 additions & 0 deletions alphadia/constants/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,13 @@ class StatOutputKeys(metaclass=ConstantsClass):
MS2_ERROR = "ms2_error"
RT_ERROR = "rt_error"
MOBILITY_ERROR = "mobility_error"


class ConfigKeys(metaclass=ConstantsClass):
"""String constants for accessing the config."""

OUTPUT_DIRECTORY = "output_directory"
LIBRARY_PATH = "library_path"
RAW_PATHS = "raw_paths"
FASTA_PATHS = "fasta_paths"
QUANT_DIRECTORY = "quant_directory"
3 changes: 3 additions & 0 deletions alphadia/constants/multistep.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ transfer:
enabled: True

# override settings that could have been set by the user:
quant_directory: null
general:
save_library: False
reuse_quant: False
Expand All @@ -23,6 +24,7 @@ library:
# predict: True

# override settings that could have been set by the user:
quant_directory: null
general:
save_library: False
reuse_quant: False
Expand All @@ -37,6 +39,7 @@ mbr:
search:
target_num_candidates: 5
# override settings that could have been set by the user:
quant_directory: null
general:
reuse_quant: False
library_prediction:
Expand Down
33 changes: 33 additions & 0 deletions alphadia/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def msg(self):
def detail_msg(self):
return self._detail_msg

def __str__(self):
return f"{self._error_code}: {self._msg} {self._detail_msg}"


class BusinessError(CustomError):
"""Custom error class for 'business' errors.
Expand Down Expand Up @@ -59,3 +62,33 @@ class NotDiaDataError(BusinessError):
_error_code = "NOT_DIA_DATA"

_msg = "Could not find cycle shape. Please check if this is a valid DIA data set."


class ConfigError(BusinessError):
"""Raise when something is wrong with the provided configuration."""

_error_code = "CONFIG_ERROR"

_msg = "Malformed configuration file(s)."
_key = ""
_config_name = ""

def __init__(self, key: str, config_name: str):
self._key = key
self._config_name = config_name


class KeyAddedConfigError(ConfigError):
"""Raise when a key should be added to a config."""

def __init__(self, key: str, config_name: str):
super().__init__(key, config_name)
self._detail_msg = f"Defining new keys is not allowed when updating a config: key='{self._key}', config_name='{self._config_name}'"


class TypeMismatchConfigError(ConfigError):
"""Raise when the type of a value does not match the default type."""

def __init__(self, key: str, config_name: str, extra_msg: str):
super().__init__(key, config_name)
self._detail_msg = f"Types of values must match default config: key='{self._key}', config_name='{self._config_name}', types='{extra_msg}'"
4 changes: 2 additions & 2 deletions alphadia/libtransform.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ def __call__(self, *args: typing.Any) -> typing.Any:
return self.forward(*args)
else:
logger.critical(
f"Input {input} failed validation for {self.__class__.__name__}"
f"Input {args} failed validation for {self.__class__.__name__}"
)
raise ValueError(
f"Input {input} failed validation for {self.__class__.__name__}"
f"Input {args} failed validation for {self.__class__.__name__}"
)

def validate(self, *args: typing.Any) -> bool:
Expand Down
Loading

0 comments on commit 8f32e51

Please sign in to comment.