From 4bca662b811f3a7d8298446b51a073f20b7f2acd Mon Sep 17 00:00:00 2001 From: Sikati Kenmogne Samuel Date: Fri, 29 Nov 2024 11:08:13 +0100 Subject: [PATCH] Refactor CLI to handle help command and following clig.dev guidelines - Updated `Typer` app initialization to `invoke_without_command=False` to enforce command requirement. - Improved command-line interface consistency and usability. --- .gitignore | 4 ++++ Makefile | 2 +- aphylogeo/main.py | 35 ++++++++++++++++++++++++++--------- aphylogeo/utils.py | 18 ++++++++++-------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index f9c43450..c5d50b75 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ aphylogeo/bin/*.fasta #Output *.dnd + +#Ignore process files +datasets/example/geneticTrees.json +result.csv diff --git a/Makefile b/Makefile index b8200905..9ca2db62 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ aPhylogeo: - python aphylogeo/main.py + python aphylogeo/main.py run .PHONY: clean diff --git a/aphylogeo/main.py b/aphylogeo/main.py index 407b491c..310b409b 100644 --- a/aphylogeo/main.py +++ b/aphylogeo/main.py @@ -1,3 +1,5 @@ +import sys + import pandas as pd import time from aphylogeo.alignement import AlignSequences @@ -21,7 +23,11 @@ \/__/ """ # https://patorjk.com/software/taag/#p=display&f=Larry%203D&t=aphylogeo%20 -app = typer.Typer(invoke_without_command=True) +app = typer.Typer( + invoke_without_command=False, + help="A tool for processing climatic and genetic data to generate phylogenetic trees.", + callback=lambda: typer.echo(typer.style(titleCard, fg=typer.colors.GREEN)) +) @app.command() def climate_pipeline( @@ -29,9 +35,11 @@ def climate_pipeline( output: str = typer.Option("./datasets/example/climaticTrees.nwk", help="The name of the file to save the climatic trees."), ): """ - This function is used to run the climatic pipeline that creates the climatic trees. + Run the climatic pipeline that process the climatic trees. + Args: file_name (str): The name of the file containing the climatic data. + output (str): The name of the file to save the climatic trees. """ Params.load_from_file() @@ -49,9 +57,11 @@ def genetic_pipeline( output: str = typer.Option("./datasets/example/geneticTrees.json", help="The name of the file to save the genetic trees."), ): """ - This function is used to run the genetic pipeline that creates the genetic trees. + Run the genetic pipeline that process the genetic trees. + Args: reference_gene_filepath (str): The path to the reference gene file. + output (str): The name of the file to save the genetic trees. """ Params.load_from_file() @@ -72,12 +82,20 @@ def genetic_pipeline( except Exception as e: print(f"Error saving the file: {e}") -@app.callback() -def main( +@app.command() +def run( climatic_tree: str = typer.Option(None, help="The name of the file containing the climatic trees."), genetic_tree: str = typer.Option(None, help="The name of the file containing the genetic trees."), + output: str = typer.Option("./results/output.csv", help="The name of the file to save the output."), ): + """ + Run the pipelines and process the trees and phylogeographic analyses. + Args: + climatic_tree (str): The name of the file containing the climatic trees. + genetic_tree (str): The name of the file containing the genetic trees. + output (str): The name of the file to save the output. + """ # geneticTrees = GeneticTrees.load_trees_from_file("./results/geneticTreesTest.json") # loaded_seq_alignment = Alignment.load_from_json("./results/aligned_sequences.json") @@ -93,8 +111,6 @@ def main( trees = GeneticTrees(trees_dict=geneticTrees, format="newick") else: - typer.echo(typer.style(titleCard, fg=typer.colors.GREEN)) - sequenceFile = utils.loadSequenceFile(Params.reference_gene_filepath) align_sequence = AlignSequences(sequenceFile) @@ -115,7 +131,9 @@ def main( climatic_data = pd.read_csv(Params.file_name) climaticTrees = utils.climaticPipeline(climatic_data) - utils.filterResults(climaticTrees, geneticTrees, climatic_data) + filtered_results = utils.filterResults(climaticTrees, geneticTrees, climatic_data) + + utils.writeOutputFile(filtered_results, output) # save results if alignements is not None: @@ -123,6 +141,5 @@ def main( trees.save_trees_to_json("./results/geneticTrees.json") - if __name__ == "__main__": app() diff --git a/aphylogeo/utils.py b/aphylogeo/utils.py index faa45d5a..1929e1af 100644 --- a/aphylogeo/utils.py +++ b/aphylogeo/utils.py @@ -462,17 +462,19 @@ def getData(leavesName, dist, index, climaticList, bootstrap, genetic, csv_data, return [reference_gene_filename, climaticList[index], leave, genetic, str(bootstrap), str(round(dist, 2))] -def writeOutputFile(data): +def writeOutputFile(data, output_file): """ Write the datas from data list into a new csv file :param data: The list containing the final data. + :param output_file: Output csv filepath for the results. :type data: list + :type output_file: String """ print("Writing the output file") directory = os.path.abspath("./results") os.makedirs(directory, exist_ok=True) - with open("./results/output.csv", "w", encoding="UTF8") as f: + with open(output_file, "w", encoding="UTF8") as f: writer = csv_writer(f) writer.writerow(header()) for i in range(len(data)): @@ -498,8 +500,8 @@ def filterResults( :param create_file: Whether to create a file or not. Default is True. :type create_file: bool - :return: The final data in a dictionary format. - :rtype: dict + :return: The final data in a list format. + :rtype: list """ # Create a list of the tree if the bootstrap is superior to the @@ -606,10 +608,10 @@ def filterResults( else: raise ValueError("Invalid distance method") - if create_file: - # We write the datas into an output csv file - writeOutputFile(data) - return format_to_csv(data) + # if create_file: + # # We write the datas into an output csv file + # writeOutputFile(data, Params.output_file) + return data def format_to_csv(data):