diff --git a/src/block.py b/src/block.py index 4a4b5c4c5b6bd803d426ab8baa9fb0ba4bc50807..8fc620bced3c5c3e86ad6f2d1ba78cf359c44210 100644 --- a/src/block.py +++ b/src/block.py @@ -7,10 +7,8 @@ class Block(Root): Root.__init__(self = self, code = code, origin = origin, modules_defined = modules_defined, subworkflow_inputs = existing_channels) self.condition = Condition(origin=self, condition = condition) - def initialise(self): - print(self.condition.condition) - if(self.condition.condition not in ["params.downloadFastq == true", "params.downloadGenome == true"]): - return super().initialise() + #def initialise(self): + # return super().initialise() def get_type(self): return "Root" diff --git a/src/call.py b/src/call.py index 77f63f932bc9680c0cc0383a3e8781b8a20c85d1..ea7f06154c9c6c8f4e82d3edd416a278c5f52123 100644 --- a/src/call.py +++ b/src/call.py @@ -22,6 +22,7 @@ class Call(Executor): self.OG_code = OG_code self.initialised = False self.emits = [] + self.analyse_first_element_called(self.get_code(clean_pipe = True)) #It's important this is last #self.condition = Condition(self) @@ -344,26 +345,58 @@ class Call(Executor): raise Exception("This shouldn't happens") self.analye_parameters(params) + # process = self.get_process_from_name(tab_call[0]) + # subworkflow = self.get_subworkflow_from_name(tab_call[0]) + # fun = self.get_function_from_name(tab_call[0]) + # if(process!=None and subworkflow==None and fun==None): + # #If the elements need to duplicated -> then we need to duplicate it + # if(self.get_duplicate_status()): + # process = process.copy() + # process.initialise() + # self.first_element_called = process + # self.origin.add_element_to_elements_being_called(process) + # #temp.incremente_number_times_called() + # if(process==None and subworkflow!=None and fun==None): + # if(self.get_duplicate_status()): + # subworkflow = subworkflow.copy() + # subworkflow.initialise() + # self.first_element_called = subworkflow + # self.origin.add_element_to_elements_being_called(subworkflow) + # if(process==None and subworkflow==None and fun!=None): + # self.first_element_called = fun + # if(process==None and subworkflow==None and fun==None): + # raise Exception("No first call found!!") + # self.called.append(self.first_element_called) + #else: + # raise BioFlowInsightError(f"Failed to extract the call{self.get_string_line(self.get_code())}. Try rewriting it in a simplified version.", num = 15, origin=self) + + def analyse_first_element_called(self, call): + tab_call = self.get_code_split_space(call) + if(re.fullmatch(constant.WORD, tab_call[0]) and tab_call[1]=='('): + #params1 = ' '.join(tab_call[2:-1]) + start = re.findall(tab_call[0]+constant.END_CALL, call)[0] + params = call.replace(start, "") + if(params[-1]==')'): + params = params[:-1] + else: + raise Exception("This shouldn't happens") + + #self.analye_parameters(params) process = self.get_process_from_name(tab_call[0]) subworkflow = self.get_subworkflow_from_name(tab_call[0]) fun = self.get_function_from_name(tab_call[0]) if(process!=None and subworkflow==None and fun==None): #If the elements need to duplicated -> then we need to duplicate it - #temp = process - #if(self.get_duplicate_status()): - # if(process.get_number_times_called()>0): - # temp = copy.copy(process) - # temp.set_alias(f"{process.get_name()}_{process.get_number_times_called()}") if(self.get_duplicate_status()): process = process.copy() - process.initialise() + process.initialise() self.first_element_called = process self.origin.add_element_to_elements_being_called(process) #temp.incremente_number_times_called() if(process==None and subworkflow!=None and fun==None): if(self.get_duplicate_status()): subworkflow = subworkflow.copy() - subworkflow.initialise() + subworkflow.initialise() self.first_element_called = subworkflow self.origin.add_element_to_elements_being_called(subworkflow) if(process==None and subworkflow==None and fun!=None): @@ -373,6 +406,7 @@ class Call(Executor): self.called.append(self.first_element_called) else: raise BioFlowInsightError(f"Failed to extract the call{self.get_string_line(self.get_code())}. Try rewriting it in a simplified version.", num = 15, origin=self) + def get_called(self): @@ -421,6 +455,7 @@ class Call(Executor): self.initialised = True self.analyse_call(self.get_code(clean_pipe = True)) self.write_summary() + diff --git a/src/emitted.py b/src/emitted.py index e5b6f5232cab6c1f462f21bd026cd340f3b79862..55142b0f2d98df41b35030a26bd7766d3a7f7c44 100644 --- a/src/emitted.py +++ b/src/emitted.py @@ -48,23 +48,26 @@ class Emitted(Channel): raise Exception(f"No emitted matched with '{name}' (in file '{self.get_file_address()}'). Should match with emittes from '{self.emitted_by.get_name()}' (in file '{self.emitted_by.get_file_address()}'") def set_emits(self, input): - if(input!=""): - try: - input = int(input) - self.set_emits_decimal(decimal=input) - except: - self.set_emits_name(name=input) + thing_which_emits = self.emitted_by.get_first_element_called() + if(thing_which_emits.get_type()=="Process"): + #TODO -> i don't konw what to do with this + #self.emits = thing_which_emits + None + else: - thing_which_emits = self.emitted_by.get_first_element_called() - if(thing_which_emits.get_type()=='Process'): - #self.emits = self.emitted_by - None - elif(thing_which_emits.get_type()=='Subworkflow'): - if(len(thing_which_emits.emit)!=1): - raise BioFlowInsightError(f"One channel was expected in the emit '{self.get_code()}'. Even though multiple emits are defined for the workflow '{self.emitted_by.get_name()}'", num=6, origin=self) - self.emits = thing_which_emits.emit[0] + if(input!=""): + try: + input = int(input) + self.set_emits_decimal(decimal=input) + except: + self.set_emits_name(name=input) else: - raise Exception("This shoudn't happen!") + if(thing_which_emits.get_type()=='Subworkflow'): + if(len(thing_which_emits.emit)!=1): + raise BioFlowInsightError(f"One channel was expected in the emit '{self.get_code()}'. Even though multiple emits are defined for the workflow '{self.emitted_by.get_name()}'", num=6, origin=self) + self.emits = thing_which_emits.emit[0] + else: + raise Exception("This shoudn't happen!") def get_structure(self, dico, B): emits = self.get_emitted_by() @@ -76,6 +79,7 @@ class Emitted(Channel): if(self.emits==None): raise Exception("Just a check") else: + dico["edges"].append({'A':str(self.emits), 'B':str(B), "label":self.get_name()}) else: raise Exception("This shouldn't happen") diff --git a/src/executor.py b/src/executor.py index 9c6b57cc99e5857f9b0deb6cfd0eb8a9bf5336b2..6e54eb9c0c3bb2f49e1e42f2d1ef934cb7632e4b 100644 --- a/src/executor.py +++ b/src/executor.py @@ -206,11 +206,17 @@ class Executor(Nextflow_Building_Blocks): #Method which returns the call which calls the element called def get_call_by_name(self, name): + #We get the calls that have already been analysed or which are currently being analysed + #for example "p(a.out)" -> the call for 'a' may not have been analysed yet + #In that case when calling "get_calls" -> we don't want to reanalyse the "p(a.out)" + calls_that_have_been_analysed = self.get_calls_that_have_been_analysed() if(self.origin.get_type() in ['Root', 'Block']): for c in self.origin.get_calls(): - c.initialise() - if(c.first_element_called.get_alias()==name): - return c + if(c not in calls_that_have_been_analysed): + calls_that_have_been_analysed[c] = True + #c.initialise() + if(c.first_element_called.get_alias()==name): + return c return None else: diff --git a/src/graph.py b/src/graph.py index c74c3ec4cb6b944ae86bc5983b4a5b26c76ec5c0..ef0caf11ff6e6592b77abae6af3593e26af3106f 100644 --- a/src/graph.py +++ b/src/graph.py @@ -74,8 +74,8 @@ class Graph(): remove_node(self.full_dico, node_id) - #self.get_dependency_graph() - #self.get_process_dependency_graph() + self.get_dependency_graph() + self.get_process_dependency_graph() #self.networkX_wo_operations = self.get_networkx_graph(self.dico_process_dependency_graph, self.networkX_wo_operations) diff --git a/src/include.py b/src/include.py index 9ac48bebaab00b8b32649f453f063300754dc2ea..4a92090fb58d491d31fcb69535c2e0b13ae82722 100644 --- a/src/include.py +++ b/src/include.py @@ -37,14 +37,14 @@ class Include(Nextflow_Building_Blocks): return self.origin.get_root_directory() - def get_list_name_includes(self): - if(self.get_duplicate_status()): - names = [] - for ele in self.defines: - names.append(ele.get_alias()) - return names - else: - return list(self.aliases.keys()) + #def get_list_name_includes(self): + # if(self.get_duplicate_status()): + # names = [] + # for ele in self.defines: + # names.append(ele.get_alias()) + # return names + # else: + # return list(self.aliases.keys()) def define_file(self, file): from .nextflow_file import Nextflow_File @@ -112,7 +112,6 @@ class Include(Nextflow_Building_Blocks): for match in re.finditer(pattern_as, include): found = True if(self.get_duplicate_status()): - #thing_as = copy.copy(self.nextflow_file.get_element_from_name(match.group(1))) thing_as = self.nextflow_file.get_element_from_name(match.group(1)).copy() thing_as.set_alias(match.group(3)) self.defines[match.group(3)] = thing_as diff --git a/src/main.py b/src/main.py index 522bde77c2048d390b8bcd83a775a9cfea9e606f..5b80b7d2f44503b596bf303c340e53c031abc048 100644 --- a/src/main.py +++ b/src/main.py @@ -15,6 +15,9 @@ class Main(Nextflow_Building_Blocks): self.initialised = False self.root = None + def get_calls_that_have_been_analysed(self): + return self.nextflow_file.get_calls_that_have_been_analysed() + def get_string_line(self, bit_of_code): return self.nextflow_file.get_string_line(bit_of_code) diff --git a/src/nextflow_building_blocks.py b/src/nextflow_building_blocks.py index 1488bf347cd01bf768fad073ae3db8e94aaf64ad..c004e35b967f63712ac356f71ea3a5ab0d7320d8 100644 --- a/src/nextflow_building_blocks.py +++ b/src/nextflow_building_blocks.py @@ -21,6 +21,9 @@ class Nextflow_Building_Blocks: #AUXILIARY METHODS FOR ALL CLASSES #--------------------------------- + def get_calls_that_have_been_analysed(self): + return self.origin.get_calls_that_have_been_analysed() + def get_code(self, get_OG = False): return self.code.get_code(get_OG = get_OG) diff --git a/src/nextflow_file.py b/src/nextflow_file.py index c3724a34aa0b844454e3d2b5cd7afa8ff591c8ed..48e105704d98daf9a2adb5c2421d72265ca491eb 100644 --- a/src/nextflow_file.py +++ b/src/nextflow_file.py @@ -50,6 +50,9 @@ class Nextflow_File(Nextflow_Building_Blocks): def get_DSL(self): return self.workflow.get_DSL() + def get_calls_that_have_been_analysed(self): + return self.workflow.get_calls_that_have_been_analysed() + #Method which returns the DSL of the workflow -> by default it's DSL2 #I use the presence of include, subworkflows and into/from in processes as a proxy def find_DSL(self): diff --git a/src/process.py b/src/process.py index affecbe0c3bd6e48c8a3ffccae61827fe2883323..6372e462dd25cb8fddb9467aed8ffd286387a6f9 100644 --- a/src/process.py +++ b/src/process.py @@ -28,6 +28,7 @@ class Process(Nextflow_Building_Blocks): self.script_code = "" self.called_by = []#List of calls + self.initialised = False def copy(self): @@ -44,6 +45,7 @@ class Process(Nextflow_Building_Blocks): process.pusblishDir_code = "" process.script_code = "" process.called_by = []#List of calls + process.initialised = False return process def add_to_emits(self, emit): @@ -386,8 +388,10 @@ class Process(Nextflow_Building_Blocks): def initialise(self): - self.initialise_name() - self.initialise_parts() - self.initialise_inputs_outputs() + if(not self.initialised): + self.initialised = True + self.initialise_name() + self.initialise_parts() + self.initialise_inputs_outputs() diff --git a/src/root.py b/src/root.py index cddaca9d8e039325fdb8031154ecd99df82520d0..24f7a310d6e3b2b7c64083c0abdd8e77f489fd91 100644 --- a/src/root.py +++ b/src/root.py @@ -70,12 +70,14 @@ class Root(Nextflow_Building_Blocks): from .block import Block body = code[conditions[c][0]:conditions[c][1]] block = Block(code=body, origin=self, condition=c, modules_defined=self.modules_defined, existing_channels = self.channels) - block.initialise() self.blocks.append(block) self.extract_executors() + for block in self.blocks: + block.initialise() + #Analyse Executors for e in self.executors: e.initialise() diff --git a/src/subworkflow.py b/src/subworkflow.py index 3402a3c062e727d3e500388452fb0a7dbbfdc285..3ce064e6f45a2bfe98d91846ca039c66457fa6a7 100644 --- a/src/subworkflow.py +++ b/src/subworkflow.py @@ -44,10 +44,13 @@ class Subworkflow(Main): return sub def get_call_by_name(self, name): + calls_that_have_been_analysed = self.get_calls_that_have_been_analysed() for c in self.root.get_calls(): - c.initialise() - if(c.first_element_called.get_alias()==name): - return c + if(c not in calls_that_have_been_analysed): + calls_that_have_been_analysed[c] = True + #c.initialise() + if(c.first_element_called.get_alias()==name): + return c return None diff --git a/src/workflow.py b/src/workflow.py index 5e4248f95f292962184cb7d47c947d7daac8da77..a0ac31e3d2c2463f3a88ea15222bf23b830e5c34 100644 --- a/src/workflow.py +++ b/src/workflow.py @@ -61,6 +61,8 @@ class Workflow: self.name = name self.graph = None + self.calls_that_have_been_analysed = {} + OG_file = Nextflow_File(file, workflow = self, first_file = True) self.DSL = OG_file.find_DSL() self.create_empty_results() @@ -80,6 +82,9 @@ class Workflow: with open(self.output_dir / "debug" / "operations_in_call.nf",'w') as file: pass + def get_calls_that_have_been_analysed(self): + return self.calls_that_have_been_analysed + def get_duplicate_status(self): return self.duplicate