diff --git a/changelog.md b/changelog.md index 6d9a87e4..998023a3 100644 --- a/changelog.md +++ b/changelog.md @@ -4,14 +4,28 @@ ### New components -- `maxbin2`: An automatic tool for binning metagenomic sequences -- `bowtie2`: Align short paired-end sequencing reads to long reference sequences +- `maxbin2`: An automatic tool for binning metagenomic sequences. +- `bowtie2`: Align short paired-end sequencing reads to long reference +sequences. + +### New recipes + +- `plasmids`: A recipe to perform mapping, mash screen on reads +and also mash dist for assembly based approaches (all to detect +plasmdis). This also includes annotation with abricate for the assembly. +- `plasmids_mapping`: A recipe to perfmorm mapping for plasmids. +- `plasmids_mash`: A recipe to perform mash screen for plasmids. +- `plasmids_assembly`: A recipe to perform mash dist for plasmid +assemblies. ### Minor/Other changes - Added "smart" check when the user provides a typo in pipeline string for a given process, outputting some "educated" guesses to the the terminal. +- Added "-cr" option to show current recipe `pipeline_string`. +- Changed the way recipes were being parsed by `proc_collector` for the +usage of `-l` and `-L` options. ### Bug fixes diff --git a/flowcraft/flowcraft.py b/flowcraft/flowcraft.py index 740ed2b8..437e0562 100755 --- a/flowcraft/flowcraft.py +++ b/flowcraft/flowcraft.py @@ -15,7 +15,7 @@ from __init__ import __version__, __build__ from generator.engine import NextflowGenerator, process_map from generator.inspect import NextflowInspector - from generator.recipe import brew_recipe + from generator.recipe import brew_recipe, available_recipes from generator.pipeline_parser import parse_pipeline, SanityError from generator.process_details import proc_collector, colored_print import generator.error_handling as eh @@ -23,7 +23,7 @@ from flowcraft import __version__, __build__ from flowcraft.generator.engine import NextflowGenerator, process_map from flowcraft.generator.inspect import NextflowInspector - from flowcraft.generator.recipe import brew_recipe + from flowcraft.generator.recipe import brew_recipe, available_recipes from flowcraft.generator.pipeline_parser import parse_pipeline, \ SanityError from flowcraft.generator.process_details import proc_collector, \ @@ -77,6 +77,12 @@ def get_args(args=None): "-l", "--short-list", action="store_const", dest="short_list", const=True, help="Print a short list of the currently " "available processes") + build_parser.add_argument("-cr", "--check-recipe", dest="check_recipe", + action="store_const", const=True, + help="Check tasks that the recipe contain and " + "their flow. This option might be useful " + "if a user wants to change some components " + "of a given recipe, by using the -t option.") # GENERAL OPTIONS parser.add_argument( @@ -121,6 +127,9 @@ def get_args(args=None): def validate_build_arguments(args): + if args.detailed_list or args.short_list: + return + if not args.tasks and not args.recipe and not args.check_only \ and not args.detailed_list and not args.short_list: logger.error(colored_print( @@ -128,7 +137,8 @@ def validate_build_arguments(args): "-l, -L", "red_bold")) sys.exit(1) - if (args.tasks or args.recipe) and not args.output_nf: + if (args.tasks or args.recipe) and not args.check_recipe \ + and not args.output_nf: logger.error(colored_print( "Please provide the path and name of the pipeline file using the" " -o option.", "red_bold")) @@ -202,13 +212,26 @@ def build(args): # If a recipe is specified, build pipeline based on the # appropriate recipe if args.recipe: - pipeline_string, list_processes = brew_recipe(args) + if args.recipe == "innuendo": + pipeline_string = brew_recipe(args, available_recipes) + else: + pipeline_string = available_recipes[args.recipe] + if args.tasks: + logger.warning(colored_print( + "-t parameter will be ignored for recipe: {}\n" + .format(args.recipe), "yellow_bold") + ) + + if args.check_recipe: + logger.info(colored_print("Pipeline string for recipe: {}" + .format(args.recipe), "purple_bold")) + logger.info(pipeline_string) + sys.exit(0) else: pipeline_string = args.tasks - list_processes = None # used for lists print - proc_collector(process_map, args, list_processes) + proc_collector(process_map, args, pipeline_string) logger.info(colored_print("Resulting pipeline string:\n")) logger.info(colored_print(pipeline_string + "\n")) diff --git a/flowcraft/generator/process_details.py b/flowcraft/generator/process_details.py index ff81ccb2..240359b6 100644 --- a/flowcraft/generator/process_details.py +++ b/flowcraft/generator/process_details.py @@ -10,7 +10,8 @@ "white_bold": "1;38m", "white_underline": "4;38m", "blue_bold": "1;36m", - "purple_bold": "1;34m" + "purple_bold": "1;34m", + "yellow_bold": "1;93m" } @@ -75,7 +76,7 @@ def procs_dict_parser(procs_dict): )) -def proc_collector(process_map, args, processes_list=None): +def proc_collector(process_map, args, pipeline_string): """ Function that collects all processes available and stores a dictionary of the required arguments of each process class to be passed to @@ -89,9 +90,8 @@ def proc_collector(process_map, args, processes_list=None): args: argparse.Namespace The arguments passed through argparser that will be access to check the type of list to be printed - processes_list: list - List with all the available processes of a recipe. In case no recipe - is passed, the list should come empty. + pipeline_string: str + the pipeline string """ @@ -120,16 +120,16 @@ def proc_collector(process_map, args, processes_list=None): # loops between all process_map Processes for name, cls in process_map.items(): - if processes_list: - # Skip process if process_list is provided and name not in - # processes list - if name not in processes_list: - continue - # instantiates each Process class cls_inst = cls(template=name) - d = {arg_key: vars(cls_inst)[arg_key] for arg_key in vars(cls_inst) - if arg_key in arguments_list} + + # checks if recipe is provided + if pipeline_string: + if name not in pipeline_string: + continue + + d = {arg_key: vars(cls_inst)[arg_key] for arg_key in + vars(cls_inst) if arg_key in arguments_list} procs_dict[name] = d procs_dict_parser(procs_dict) diff --git a/flowcraft/generator/recipe.py b/flowcraft/generator/recipe.py index 7f1500b6..608ccc7d 100644 --- a/flowcraft/generator/recipe.py +++ b/flowcraft/generator/recipe.py @@ -478,8 +478,8 @@ def run_auto_pipeline(self, tasks): return self.pipeline_string - def get_process_info(self): - return list(self.process_descriptions.keys()) + # def get_process_info(self): + # return list(self.process_descriptions.keys()) class Innuendo(Recipe): @@ -512,17 +512,12 @@ def __init__(self, *args, **kwargs): "mlst": [False, "pilon", "abricate|prokka|chewbbaca|sistr"], "sistr": [True, "mlst", None], "abricate": [True, "mlst", None], - "prokka": [True, "mlst", None], + #"prokka": [True, "mlst", None], "chewbbaca": [True, "mlst", None] } -available_recipes = { - "innuendo": Innuendo -} - - -def brew_recipe(args): +def brew_recipe(args, available_recipes): """Brews a given list of processes according to the recipe Parameters @@ -555,8 +550,6 @@ def brew_recipe(args): else: input_processes = args.tasks - # Get the list of processes for that recipe - list_processes = automatic_pipeline.get_process_info() # Validate the provided pipeline processes validated = automatic_pipeline.validate_pipeline(input_processes) if not validated: @@ -564,4 +557,16 @@ def brew_recipe(args): # Get the final pipeline string pipeline_string = automatic_pipeline.run_auto_pipeline(input_processes) - return pipeline_string, list_processes + return pipeline_string + + +# A dictionary of quick recipes +available_recipes = { + "innuendo": Innuendo, + "plasmids": "integrity_coverage fastqc_trimmomatic (spades pilon " + "(mash_dist | abricate) | mash_screen | mapping_patlas)", + "plasmids_mapping": "integrity_coverage fastqc_trimmomatic mapping_patlas", + "plasmids_assembly": "integrity_coverage fastqc_trimmomatic (spades pilon" + " mash_dist)", + "plasmids_mash": "integrity_coverage fastqc_trimmomatic mash_screen", +} diff --git a/flowcraft/tests/test_assemblerflow.py b/flowcraft/tests/test_assemblerflow.py index e9310cff..401f6c99 100644 --- a/flowcraft/tests/test_assemblerflow.py +++ b/flowcraft/tests/test_assemblerflow.py @@ -14,24 +14,6 @@ def tmp(): shutil.rmtree("temp") -def test_list_short(): - - sys.argv.append(1) - args = af.get_args(["build", "-l"]) - - with pytest.raises(SystemExit): - af.build(args) - - -def test_list_long(): - - sys.argv.append(1) - args = af.get_args(["build", "-L"]) - - with pytest.raises(SystemExit): - af.build(args) - - def test_check(): sys.argv.append(1) diff --git a/flowcraft/tests/test_process_details.py b/flowcraft/tests/test_process_details.py index a05a081e..39cf5129 100644 --- a/flowcraft/tests/test_process_details.py +++ b/flowcraft/tests/test_process_details.py @@ -19,14 +19,18 @@ def test_long_list(): arguments = af.get_args(["build", "-L"]) + pipeline_string = "fastqc trimmomatic" + with pytest.raises(SystemExit): - pd.proc_collector(process_map, arguments) + pd.proc_collector(process_map, arguments, pipeline_string) def test_short_list(): arguments = af.get_args(["build", "-l"]) + pipeline_string = "fastqc trimmomatic" + with pytest.raises(SystemExit): - pd.proc_collector(process_map, arguments) + pd.proc_collector(process_map, arguments, pipeline_string) \ No newline at end of file