From 54f86c738e57485b79da35dc5ef6e9557a0ad748 Mon Sep 17 00:00:00 2001
From: George Marchment <georgemarchment@yahoo.fr>
Date: Mon, 10 Mar 2025 14:49:53 +0100
Subject: [PATCH] Adding a few updates

---
 src/call.py        | 85 ++++++++++++++++++++++++----------------------
 src/operation.py   |  6 ++--
 src/subworkflow.py |  4 ++-
 src/workflow.py    | 45 ++++++++++++++----------
 4 files changed, 79 insertions(+), 61 deletions(-)

diff --git a/src/call.py b/src/call.py
index 9e22063..b50e93b 100644
--- a/src/call.py
+++ b/src/call.py
@@ -64,49 +64,54 @@ class Call(Executor):
     
 
     def simplify_code(self, new_name = ""):
-        new_call_name = self.get_first_element_called().get_alias_and_id()
-        code = self.get_code()
-        code = re.sub(fr'{re.escape(self.get_first_element_called().get_alias())} *\(', f'{new_call_name}(', code)
-        if(new_name!=""):
-            code = f"{new_name} = {code}"
-        tag_to_add = "//AREA TO ADD PARAMS"
-        code = f"{tag_to_add}\n{code}"
-        index = 1
-        for param in self.parameters:
-            param_new_name = f"{self.get_first_element_called().get_alias_and_id()}_param_{index}"
-            
-            #Case the param is a call
-            if(param.get_type()=="Call"):
-                code = code.replace(param.get_code(get_OG=True), param_new_name)
-                new_bit = param.simplify_code(new_name = param_new_name)
-                code = code.replace(tag_to_add, f"{tag_to_add}\n{new_bit}")
-
-            #Case the param is an operation
-            elif(param.get_type()=="Operation"):
-                #If it's an artificial operation -> we don't need to do anything
-                if(not param.get_artificial_status()):
+        if(self.get_first_element_called().get_type()=="Function"):
+            return self.get_code()
+        else:
+            new_call_name = self.get_first_element_called().get_alias_and_id()
+            code = self.get_code(clean_pipe = True)
+            code = re.sub(fr'{re.escape(self.get_first_element_called().get_alias())} *\(', f'{new_call_name}(', code)
+            if(new_name!=""):
+                code = f"{new_name} = {code}"
+            tag_to_add = "//AREA TO ADD PARAMS"
+            code = f"{tag_to_add}\n{code}"
+            index = 1
+            for param in self.parameters:
+                param_new_name = f"{self.get_first_element_called().get_alias_and_id()}_param_{index}"
                 
+                #Case the param is a call
+                if(param.get_type()=="Call"):
+                    #If it's not a function -> then we rewrite it
+                    if(param.get_first_element_called().get_type()!="Function"):
+                        code = code.replace(param.get_code(get_OG=True), param_new_name)
+                        new_bit = param.simplify_code(new_name = param_new_name)
+                        code = code.replace(tag_to_add, f"{tag_to_add}\n{new_bit}")
+
+                #Case the param is an operation
+                elif(param.get_type()=="Operation"):
+                    #If it's an artificial operation -> we don't need to do anything
+                    if(not param.get_artificial_status()):
+                    
+                        code = code.replace(param.get_code(get_OG=True), param_new_name)
+                        lines = param.simplify_code().split('\n')
+                        if(len(lines)==1):
+                            new_bit = f"{param_new_name} = {lines[0]}"
+                        else:
+                            head = '\n'.join(lines[:-1])
+                            new_bit = f"{head}\n{param_new_name} = {lines[-1]}"
+                        code = code.replace(tag_to_add, f"{tag_to_add}\n{new_bit}")
+                
+                #Case Channel
+                elif(param.get_type()=="Channel"):
+                    raise Exception("This shouldn't happen")
+                    None
+                elif(param.get_type()=="Emitted"):
                     code = code.replace(param.get_code(get_OG=True), param_new_name)
-                    lines = param.simplify_code().split('\n')
-                    if(len(lines)==1):
-                        new_bit = f"{param_new_name} = {lines[0]}"
-                    else:
-                        head = '\n'.join(lines[:-1])
-                        new_bit = f"{head}\n{param_new_name} = {lines[-1]}"
+                    new_bit = f"{param_new_name} = {param.simplify_code()}"
                     code = code.replace(tag_to_add, f"{tag_to_add}\n{new_bit}")
-            
-            #Case Channel
-            elif(param.get_type()=="Channel"):
-                raise Exception("This shouldn't happen")
-                None
-            elif(param.get_type()=="Emitted"):
-                code = code.replace(param.get_code(get_OG=True), param_new_name)
-                new_bit = f"{param_new_name} = {param.simplify_code()}"
-                code = code.replace(tag_to_add, f"{tag_to_add}\n{new_bit}")
-            else:
-                raise Exception("This shouldn't happen")
-            index+=1
-        return code.replace(tag_to_add, "").strip()
+                else:
+                    raise Exception("This shouldn't happen")
+                index+=1
+            return code.replace(tag_to_add, "").strip()
 
         
     
diff --git a/src/operation.py b/src/operation.py
index 6e1bf5a..1a88d6e 100644
--- a/src/operation.py
+++ b/src/operation.py
@@ -902,8 +902,10 @@ class Operation(Executor):
         to_add = []
         for o in self.origins:
             if(o.get_type()=="Call"):
-                to_add.append(add_origin_equals(o, index))
-                code = code.replace(o.get_code(get_OG=True), f"operation_{operation_id}_{index}")
+                #If it's not a function -> then we rewrite it
+                if(o.get_first_element_called().get_type()!="Function"):
+                    to_add.append(add_origin_equals(o, index))
+                    code = code.replace(o.get_code(get_OG=True), f"operation_{operation_id}_{index}")
             elif(o.get_type()=="Emitted"):
                 code = code.replace(o.get_code(get_OG=True), o.simplify_code())
             index += 1
diff --git a/src/subworkflow.py b/src/subworkflow.py
index 774a7d2..0e0d1ad 100644
--- a/src/subworkflow.py
+++ b/src/subworkflow.py
@@ -169,7 +169,9 @@ class Subworkflow(Main):
         #Case nothing is there
         if(take_pos==(0, 0) and main_pos==(0, 0) and emit_pos==(0, 0)):
             #raise Exception(f"Subworkflow {code} doesn't have anything defined")
-            self.work = Code(code, origin = self)
+            firt_curly  = code.find("{")
+            last_curly = code.rfind('}')
+            self.work = Code(code[firt_curly+1:last_curly], origin = self)
         #Case there is an input but no output
         if(take_pos!=(0, 0) and main_pos!=(0, 0) and emit_pos==(0, 0)):
             if(take_pos[0]<main_pos[0]):
diff --git a/src/workflow.py b/src/workflow.py
index ace12fe..be488f2 100644
--- a/src/workflow.py
+++ b/src/workflow.py
@@ -359,7 +359,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
 
             #Putting || back
             code = code.replace("$OR$", "||")
-            self.rewrite_and_initialise(code, self.processes_2_remove)
+            self.rewrite_and_initialise(code, self.processes_2_remove, render_graphs=False)
             return code
     
     #This methods generates a random set of processes to consider as relavant 
@@ -515,7 +515,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
         return subs
 
 
-    def rewrite_and_initialise(self, code, processes_2_remove):
+    def rewrite_and_initialise(self, code, processes_2_remove, render_graphs):
         temp_process_dependency_graph = self.graph.get_process_dependency_graph() 
         temp_spec_graph = self.graph.full_dico    
         #Write new code in temporary file
@@ -532,10 +532,12 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
         self.initialise()
         self.graph.initialise(processes_2_remove = self.processes_2_remove)
         if(not self.graph.check_if_process_dependendy_is_equivalent_to_other_without_subworkflows(temp_process_dependency_graph)):
-            generate_graph(self.get_output_dir()/ "debug" /"spec_graph_OG", temp_spec_graph, render_graphs = True)
-            generate_graph(self.get_output_dir()/ "debug" /"spec_graph", self.graph.full_dico, render_graphs = True)
-            generate_graph(self.get_output_dir()/ "debug" /"process_dependency_graph_OG", temp_process_dependency_graph, render_graphs = True)
-            generate_graph(self.get_output_dir()/ "debug" /"process_dependency_graph", self.graph.get_process_dependency_graph() , render_graphs = True)
+            print(render_graphs)
+            if(render_graphs==True):
+                generate_graph(self.get_output_dir()/ "debug" /"spec_graph_OG", temp_spec_graph, render_graphs = True)
+                generate_graph(self.get_output_dir()/ "debug" /"spec_graph", self.graph.full_dico, render_graphs = True)
+                generate_graph(self.get_output_dir()/ "debug" /"process_dependency_graph_OG", temp_process_dependency_graph, render_graphs = True)
+                generate_graph(self.get_output_dir()/ "debug" /"process_dependency_graph", self.graph.get_process_dependency_graph() , render_graphs = True)
             raise Exception("Something went wrong: The flat dependency graph is not the same!")
 
 
@@ -574,7 +576,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
         code = code.replace(subworklfow.get_code(), "")
         OG_call = subworklfow.get_call()
         OG_body = subworklfow.get_work()
-        
+
         #REPLACE HEADER TAKES
         subworkflow_takes = subworklfow.get_takes()
         parameters = OG_call.get_parameters()
@@ -614,8 +616,9 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             old, new = r
             temp_code = code
             #Case of channel = channel
-            if(new.split("=")[0].strip()==new.split("=")[1].strip()):
-                new = ''
+            if(new.find("=")!=-1):
+                if(new.split("=")[0].strip()==new.split("=")[1].strip()):
+                    new = ''
             code = code.replace(old, new)
             if(temp_code==code):
                 raise Exception("Something went wrong: The code hasn't changed")
@@ -659,7 +662,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
     #This Function returns the channels the subworkflow (things_added_in_cluster) emits (other things depend on)
     def get_emits(self, things_added_in_cluster):
         channel_2_sink = {}
-        #Basiccaly this is a deco of channels to opeartions -> when the value is an empty list 
+        #Basiccaly this is a deco of channels to opea -> this doesn't really work yetrtions -> when the value is an empty list 
         #This means that the channel is totally definied in the subworkflow -> so we are searching for 
         #Channels which aren't totatly defined in the subworkflow
         #This means that things outside the subworkflow depend on this channel 
@@ -689,13 +692,16 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
 
     #Method which rewrites the workflow follwong the user view
     #Conert workflow to user_view only makes sense when the option duplicate is activated -> otherwise is doesn't make sense + it makes the analysis way more complicated
-    def convert_workflow_2_user_view(self, relevant_processes = []):
+    def convert_workflow_2_user_view(self, relevant_processes = [], render_graphs = True):
+        self.iniatilise_tab_processes_2_remove()
+        self.graph.initialise(processes_2_remove = self.processes_2_remove)
+
         if(self.get_DSL()=="DSL1"):
             code = self.convert_to_DSL2()
 
         if(self.duplicate):
             code = self.simplify_workflow_code()
-            self.rewrite_and_initialise(code, self.processes_2_remove)
+            self.rewrite_and_initialise(code, self.processes_2_remove, render_graphs=render_graphs)
             
             
             
@@ -757,7 +763,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             
             #Get the clusters and the code
             relevant_processes = self.check_relevant_processes_in_workflow(relevant_processes)
-            self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [])
+            self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [], render_graphs=render_graphs)
             clusters = self.graph.get_clusters_from_user_view()
             broken_subworkflows = get_workflows_broken(get_subworkflow_2_executors(), get_clusters_with_calls(clusters))
             #While there still are broken workflows -> need to redo the analysis
@@ -765,11 +771,12 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                 #Rewrite broken subworkflows
                 sub = broken_subworkflows[0]
                 code = self.rewrite_subworkflow_call(code, sub)
-                self.rewrite_and_initialise(code, self.processes_2_remove)
+                self.rewrite_and_initialise(code, self.processes_2_remove, render_graphs=render_graphs)
                 #Get the clusters and the code
                 #TODO -> remove the generate all_graphs -> it is not necessary 
-                self.generate_all_graphs()
-                self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [])
+                if(render_graphs):
+                    self.generate_all_graphs()
+                self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [], render_graphs=render_graphs)
                 clusters = self.graph.get_clusters_from_user_view()
                 broken_subworkflows = get_workflows_broken(get_subworkflow_2_executors(), get_clusters_with_calls(clusters))
             
@@ -795,7 +802,9 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                 new_clusters.append(tab)
             clusters = new_clusters
             #clusters = self.graph.get_topogical_order(clusters)
-    
+            #for e in executors_in_order:
+            #    print(e.get_code()[:20])
+            #print(executors_in_order)
 
 
             #Creating the subworkflows from clusters
@@ -1085,7 +1094,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             f = open(self.get_output_dir()/ "debug" / "rewritten.nf", "w")
             f.write(code)
             f.close()
-            self.rewrite_and_initialise(code, self.processes_2_remove)
+            self.rewrite_and_initialise(code, self.processes_2_remove, render_graphs=render_graphs)
             return code
             #return code
             #
-- 
GitLab