def _run(args, base_dir, workflows_dir, config_path): """ Run a complete workflow. """ if not os.path.exists(config_path): sys.stdout.write( f"The config file: {config_path} does not exist.\nProvide a path to the config file with " f"--config or if you do not have a config file run:\n" f"seq2science init {args.workflow}\n") sys.exit(1) # parse the args parsed_args = { "snakefile": os.path.join(workflows_dir, args.workflow.replace("-", "_"), "Snakefile"), "use_conda": True, "conda_frontend": conda_frontend, "conda_prefix": os.path.join(base_dir, ".snakemake"), "dryrun": args.dryrun, "printreason": args.reason, "keepgoing": args.keep_going, "unlock": args.unlock, "force_incomplete": args.rerun_incomplete } # get the additional snakemake options snakemake_options = args.snakemakeOptions if args.snakemakeOptions is not None else dict( ) snakemake_options.setdefault("config", {}).update( {"rule_dir": os.path.join(base_dir, "rules")}) # parse the profile snakemake_options["configfiles"] = [config_path] if args.profile is not None: profile_file = snakemake.get_profile_file(args.profile, "config.yaml") if profile_file is None: print("Error: profile given but no config.yaml found.") sys.exit(1) snakemake_options["configfiles"] += [profile_file] parsed_args.update(snakemake_options) # cores if args.cores: # CLI parsed_args["cores"] = args.cores elif parsed_args.get("cores"): # profile parsed_args["cores"] = int(parsed_args["cores"]) elif parsed_args["dryrun"]: parsed_args["cores"] = 999 else: parsed_args["cores"] = 0 if parsed_args["cores"] < 2: # we need to raise an exception and catch it for a subjectively prettier message try: raise argparse.ArgumentError(core_arg, "specify at least two cores.") except argparse.ArgumentError as e: print() # empty line print(e) sys.exit(1) core_parser(parsed_args) # run snakemake exit_code = snakemake.snakemake(**parsed_args) sys.exit(0) if exit_code else sys.exit(1)
def _explain(args, base_dir, workflows_dir, config_path): """ Run a complete dryrun workflow, then return the explanations of each rule used. """ if not os.path.exists(config_path): sys.stdout.write( f"The config file: {config_path} does not exist.\nProvide a path to the config file with " f"--config or if you do not have a config file run:\n" f"seq2science init {args.workflow}\n") sys.exit(1) # parse the args parsed_args = { "snakefile": os.path.join(workflows_dir, args.workflow.replace("-", "_"), "Snakefile"), "dryrun": True, "forceall": True, "quiet": False } # get the additional snakemake options snakemake_options = args.snakemakeOptions if args.snakemakeOptions is not None else dict( ) snakemake_options.setdefault("config", {}).update( {"rule_dir": os.path.join(base_dir, "rules")}) # parse the profile snakemake_options["configfiles"] = [config_path] if args.profile is not None: profile_file = snakemake.get_profile_file(args.profile, "config.yaml") if profile_file is None: print("Error: profile given but no config.yaml found.") sys.exit(1) snakemake_options["configfiles"] += [profile_file] parsed_args.update(snakemake_options) # cores parsed_args["cores"] = 999 # starting message rules_used = { "start": f"\nPreprocessing of reads was done automatically with workflow tool " f"seq2science v{seq2science.__version__} (https://doi.org/10.5281/zenodo.3921913)." } def log_handler(log): if log["level"] == "job_info" and "msg" in log and log[ "msg"] is not None and log["name"] not in rules_used: rules_used[log["name"]] = log["msg"] parsed_args["log_handler"] = [log_handler] parsed_args["config"]["explain_rule"] = True # run snakemake (silently) with open(os.devnull, "w") as null: with contextlib.redirect_stdout(null), contextlib.redirect_stderr( null): exit_code = snakemake.snakemake(**parsed_args) print(" ".join(rules_used.values())) sys.exit(0) if exit_code else sys.exit(1)
def _run(args, base_dir, workflows_dir, config_path): """ Run a complete workflow. """ if not os.path.exists(config_path): sys.stdout.write( f"The config file: {config_path} does not exist.\nProvide a path to the config file with " f"--config or if you do not have a config file run:\n" f"seq2science init {args.workflow}\n") sys.exit(1) # parse the args parsed_args = { "snakefile": os.path.join(workflows_dir, args.workflow.replace("-", "_"), "Snakefile"), "use_conda": True, "conda_frontend": conda_frontend, "conda_prefix": os.path.join(base_dir, ".snakemake"), "dryrun": args.dryrun, "printreason": args.reason, "keepgoing": args.keep_going, "unlock": args.unlock, "force_incomplete": args.rerun_incomplete } # get the additional snakemake options snakemake_options = args.snakemakeOptions if args.snakemakeOptions is not None else dict( ) snakemake_options.setdefault("config", {}).update( {"rule_dir": os.path.join(base_dir, "rules")}) snakemake_options["configfiles"] = [config_path] parsed_args.update(snakemake_options) # parse the profile if args.profile is not None: profile_file = snakemake.get_profile_file(args.profile, "config.yaml") if profile_file is None: subjectively_prettier_error( profile_arg, "profile given but no config.yaml found.") add_profile_args(profile_file, parsed_args) # cores if args.cores: # CLI parsed_args["cores"] = args.cores elif parsed_args.get("cores"): # profile parsed_args["cores"] = int(parsed_args["cores"]) elif parsed_args["dryrun"]: parsed_args["cores"] = 999 else: parsed_args["cores"] = 0 if parsed_args["cores"] < 2: subjectively_prettier_error(core_arg, "specify at least two cores.") # when running on a cluster assume cores == nodes (just like snakemake does) if "cluster" in parsed_args and not "nodes" in parsed_args: parsed_args["nodes"] = parsed_args["cores"] core_parser(parsed_args) parsed_args["config"].update({"cores": parsed_args["cores"]}) resource_parser(parsed_args) # run snakemake exit_code = snakemake.snakemake(**parsed_args) sys.exit(0) if exit_code else sys.exit(1)