-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: addition of proper logging functionality for the ViroConstrict…
…or package feat!: replace snakemake logging output through our own log handler for unified output fix: suppress snakemake logging output (workaround for snakemake/snakemake#2089) refactor!: Use a generic (`__main__.py`) top level entry-point instead of the named `ViroConstrictor.py` entrypoint refactor: re-structure argument parsing functionalities into its own class refactor: re-structure snakemake run-information and config functionalities into its own class refactor: remove old shell stdout-coloring method with the rich library refactor: simplify several functions to ensure a properly defined return refactor: Use f-strings more consistently for i.e. string concatenation with variables refactor: add type-hints to all functions fix: ensure `samples_df` and `samples_dict` always contain the same information
- Loading branch information
1 parent
f76d575
commit 20a952b
Showing
14 changed files
with
1,352 additions
and
1,030 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
""" | ||
Starting point of the ViroConstrictor pipeline and wrapper | ||
Copyright © 2021 RIVM | ||
https://github.com/RIVM-bioinformatics/ViroConstrictor | ||
""" | ||
|
||
# pylint: disable=C0103 | ||
|
||
import sys | ||
from typing import Literal, NoReturn | ||
|
||
import pandas as pd | ||
import snakemake | ||
|
||
import ViroConstrictor.logging | ||
from ViroConstrictor import __version__ | ||
from ViroConstrictor.logging import log | ||
from ViroConstrictor.parser import CLIparser | ||
from ViroConstrictor.runconfigs import GetSnakemakeRunDetails, WriteYaml | ||
from ViroConstrictor.runreport import WriteReport | ||
from ViroConstrictor.update import update | ||
|
||
|
||
def get_preset_warning_list( | ||
sample_info_df: pd.DataFrame, | ||
) -> tuple[list[str], list[str]]: | ||
"""Takes a dataframe with sample information and returns a tuple of two lists of warnings | ||
Parameters | ||
---------- | ||
sample_info_df : pd.DataFrame | ||
pd.DataFrame | ||
Returns | ||
------- | ||
A list of warnings. | ||
""" | ||
preset_fallback_warnings = preset_score_warnings = [] | ||
for s in sample_info_df.itertuples(): | ||
sample, preset, score, input_target = ( | ||
s.SAMPLE, | ||
s.PRESET, | ||
s.PRESET_SCORE, | ||
s.VIRUS, | ||
) | ||
if score == 0.0: | ||
warn = f"""[red]Sample '[bold underline]{sample}[/bold underline]' was given the following information as an input-target: '[bold underline]{input_target}[/bold underline]'. | ||
This information could however not be used to determine a preset. Because of this, the preset '[bold underline]{preset}[/bold underline]' was used instead.[/red] | ||
[yellow]Please check your input-target for any significant misspellings, or consider using an alias or a different abbreviation for your input-target to check whether this resolves the issue.[/yellow] | ||
It may be that your input-target does not yet have an associated preset in ViroConstrictor. | ||
If your suspect this to be the case, please open an issue on the ViroConstrictor GitHub page: [magenta underline]https://github.com/RIVM-bioinformatics/ViroConstrictor[/magenta underline]""" | ||
preset_fallback_warnings.append(warn) | ||
continue | ||
if score < 0.8: | ||
warn = f"""[red]Sample '[bold underline]{sample}[/bold underline]' was given the following information as an input-target: '[bold underline]{input_target}[/bold underline]'. | ||
As a result, the preset '{preset}' was chosen. But this was done with less than 80% certainty.[/red] | ||
[yellow]Certainty score: [bold]{score:.0%}[/bold][/yellow] | ||
Please check the input-target and try again if a different preset is required.""" | ||
preset_score_warnings.append(warn) | ||
continue | ||
return preset_fallback_warnings, preset_score_warnings | ||
|
||
|
||
def show_preset_warnings( | ||
warnings: list[str], fallbacks: list[str], disabled: bool | ||
) -> None: | ||
if warnings and not disabled: | ||
for w in warnings: | ||
log.warn(f"{w}") | ||
if fallbacks and not disabled: | ||
for w in fallbacks: | ||
log.warn(f"{w}") | ||
|
||
|
||
def main() -> NoReturn: | ||
""" | ||
ViroConstrictor starting point | ||
--> Fetch and parse arguments | ||
--> check validity | ||
--> Read (or write, if necessary) the user-config files | ||
--> Change working directories and make necessary local files for snakemake | ||
--> Run snakemake with appropriate settings | ||
""" | ||
|
||
parsed_input = CLIparser(input_args=sys.argv[1:]) | ||
|
||
preset_fallback_warnings, preset_score_warnings = get_preset_warning_list( | ||
parsed_input.samples_df | ||
) | ||
if not parsed_input.flags.skip_updates: | ||
update(sys.argv, parsed_input.user_config) | ||
|
||
snakemake_run_details = GetSnakemakeRunDetails(inputs_obj=parsed_input) | ||
|
||
log.info(f"{'='*20} [bold yellow] Starting Workflow [/bold yellow] {'='*20}") | ||
status: bool = False | ||
|
||
if parsed_input.user_config["COMPUTING"]["compmode"] == "local": | ||
status = snakemake.snakemake( | ||
snakefile=parsed_input.snakefile, | ||
workdir=parsed_input.workdir, | ||
cores=snakemake_run_details.snakemake_run_conf["cores"], | ||
use_conda=snakemake_run_details.snakemake_run_conf["use-conda"], | ||
conda_frontend="mamba", | ||
jobname=snakemake_run_details.snakemake_run_conf["jobname"], | ||
latency_wait=snakemake_run_details.snakemake_run_conf["latency-wait"], | ||
dryrun=snakemake_run_details.snakemake_run_conf["dryrun"], | ||
configfiles=[ | ||
WriteYaml( | ||
snakemake_run_details.snakemake_run_parameters, | ||
f"{parsed_input.workdir}/config/run_params.yaml", | ||
) | ||
], | ||
restart_times=3, | ||
keepgoing=True, | ||
quiet=["all"], # type: ignore | ||
log_handler=[ | ||
ViroConstrictor.logging.snakemake_logger(logfile=parsed_input.logfile) | ||
], | ||
printshellcmds=False, | ||
) | ||
if parsed_input.user_config["COMPUTING"]["compmode"] == "grid": | ||
status = snakemake.snakemake( | ||
snakefile=parsed_input.snakefile, | ||
workdir=parsed_input.workdir, | ||
cores=snakemake_run_details.snakemake_run_conf["cores"], | ||
nodes=snakemake_run_details.snakemake_run_conf["cores"], | ||
use_conda=snakemake_run_details.snakemake_run_conf["use-conda"], | ||
conda_frontend="mamba", | ||
jobname=snakemake_run_details.snakemake_run_conf["jobname"], | ||
latency_wait=snakemake_run_details.snakemake_run_conf["latency-wait"], | ||
drmaa=snakemake_run_details.snakemake_run_conf["drmaa"], | ||
drmaa_log_dir=snakemake_run_details.snakemake_run_conf["drmaa-log-dir"], | ||
dryrun=snakemake_run_details.snakemake_run_conf["dryrun"], | ||
configfiles=[ | ||
WriteYaml( | ||
snakemake_run_details.snakemake_run_parameters, | ||
f"{parsed_input.workdir}/config/run_params.yaml", | ||
) | ||
], | ||
restart_times=3, | ||
keepgoing=True, | ||
quiet=["all"], # type: ignore | ||
log_handler=[ | ||
ViroConstrictor.logging.snakemake_logger(logfile=parsed_input.logfile) | ||
], | ||
) | ||
|
||
if snakemake_run_details.snakemake_run_conf["dryrun"] is False and status is True: | ||
snakemake.snakemake( | ||
snakefile=parsed_input.snakefile, | ||
workdir=parsed_input.workdir, | ||
report="results/snakemake_report.html", | ||
configfiles=[ | ||
WriteYaml( | ||
snakemake_run_details.snakemake_run_parameters, | ||
f"{parsed_input.workdir}/config/run_params.yaml", | ||
) | ||
], | ||
quiet=["all"], # type: ignore | ||
log_handler=[ | ||
ViroConstrictor.logging.snakemake_logger(logfile=parsed_input.logfile) | ||
], | ||
) | ||
|
||
workflow_state: Literal["Failed", "Success"] = ( | ||
"Failed" if status is False else "Success" | ||
) | ||
|
||
WriteReport( | ||
parsed_input.workdir, | ||
parsed_input.input_path, | ||
parsed_input.exec_start_path, | ||
parsed_input.user_config, | ||
snakemake_run_details.snakemake_run_parameters, | ||
snakemake_run_details.snakemake_run_conf, | ||
workflow_state, | ||
) | ||
|
||
show_preset_warnings( | ||
preset_score_warnings, | ||
preset_fallback_warnings, | ||
parsed_input.flags.disable_presets, | ||
) | ||
|
||
if status is False: | ||
exit(1) | ||
exit(0) |
Oops, something went wrong.