Commit ff0000aa authored by Carine Rey's avatar Carine Rey
Browse files

Parse_input_tree.py : split file to remove dependencies

parent c6cb3658
......@@ -117,13 +117,13 @@ rate_distribution=Constant()
|}
let multi_profiles ?(descr="") ~profile_f ~profile_c ~tree_dataset ~hypothesis ~seed =
let multi_profiles ?(descr="") ~profile_f ~profile_c ~input_tree ~hypothesis ~seed =
let nb_sites_per_profile = 1 in
let config_f = dest // "config.bpp" in
let profile_c_ok = dep profile_c in
let out = dest // "seq.fa" in
let tree = Tree_dataset.tree tree_dataset `Simulation in
let nodes = Tree_dataset.nodes tree_dataset hypothesis in
let tree = Tree_dataset.prepare_tree_with_node_id input_tree in
let nodes = Tree_dataset.prepare_nodes input_tree hypothesis in
let ne_g = Convergence_hypothesis.neg_of_model hypothesis in
let ne_c = Convergence_hypothesis.nec_of_model hypothesis in
let ne_a = ne_g in
......
......@@ -6,7 +6,7 @@ module Bppseqgen : sig
?descr : string ->
profile_f: text_file pworkflow ->
profile_c: text_file pworkflow ->
tree_dataset:[`tree_dataset] dworkflow ->
input_tree: nhx pworkflow ->
hypothesis:Convergence_hypothesis.t ->
seed:int ->
[`bppseqgen] dworkflow
......
......@@ -16,6 +16,11 @@ class type diffsel_tree = object
method format : [`diffsel_tree]
end
class type topological_tree = object
inherit text_file
method format : [`topological_tree]
end
class type nucleotide_fasta = object
inherit fasta
method alphabet : [`Nucleotide]
......
......@@ -70,7 +70,7 @@ let derive_from_model ~model ~input_tree ~tree_dataset ~tree_prefix ~profile ~se
let profile_f = profile.profile_f in
let profile_c = profile.profile_c in
let seed = calc_fixed_seed ~str:descr seed in
let run_fna = Bppsuite.Bppseqgen.multi_profiles ~descr ~tree_dataset ~hypothesis:model ~profile_f ~profile_c ~seed in
let run_fna = Bppsuite.Bppseqgen.multi_profiles ~descr ~input_tree ~hypothesis:model ~profile_f ~profile_c ~seed in
let fna = Bppsuite.Bppseqgen.alignment run_fna in
let fna_infos = Some (Bppsuite.Bppseqgen.info run_fna) in
let faa = Bppsuite.fna2faa fna in
......@@ -201,10 +201,10 @@ let derive_from_det_meth ~det_meth ~(dataset : Dataset.t) ~preview =
let faa = dataset.dataset.faa in
let fna = dataset.dataset.fna in
let phy_n = Bppsuite.fna2phy ~fna in
let tree_sc = Tree_dataset.tree dataset.dataset.tree_dataset `Detection in
let tree_id = Tree_dataset.tree dataset.dataset.tree_dataset `Simulation in
let diffsel_tree = Tree_dataset.diffsel_tree dataset.dataset.tree_dataset in
let tree_conv = Tree_dataset.topological_tree dataset.dataset.tree_dataset in
let tree_sc = Tree_dataset.prepare_sc_tree dataset.dataset.input_tree in
let tree_id = Tree_dataset.prepare_tree_with_node_id dataset.dataset.input_tree in
let diffsel_tree = Tree_dataset.prepare_diffsel_tree ~descr:tree_prefix dataset.dataset.input_tree in
let tree_conv = Tree_dataset.prepare_topological_tree ~descr:tree_prefix dataset.dataset.input_tree in
let w_every = if preview then 1 else 1 in
let n_cycles = if preview then 2000 else 2000 in
let seed = Hashtbl.hash dataset.seed in
......@@ -257,7 +257,7 @@ let derive_from_dataset ~dataset ~preview ~use_diffsel ~use_c60=
let merged_results = merge_results ?fna_infos ~res_by_tools () in
let tsv = merged_results in
let faa = dataset.dataset.faa in
let tree = Tree_dataset.tree dataset.dataset.tree_dataset `Detection in
let tree = Tree_dataset.prepare_sc_tree dataset.dataset.input_tree in
let plot_all_sites = if dataset.is_real then false else true in
let plot_merged_results = plot_merge_results ~plot_all_sites ~res_by_tools ~tsv ~faa ~tree () in
let model_prefix = dataset.model_prefix in
......
......@@ -113,7 +113,7 @@ let bppseqgen sim ~hypothesis ~nb_sites ~profiles ~seed =
let seed = calc_fixed_seed ~str:descr seed in
Bppsuite.Bppseqgen.multi_profiles
~descr
~tree_dataset:(tree_dataset sim)
~input_tree:(tree sim)
~hypothesis ~profile_f ~profile_c ~seed
let rec nucleotide_alignment = function
......@@ -136,7 +136,7 @@ let phylip_nucleotide_alignment d =
Bppsuite.fna2phy ~fna:(nucleotide_alignment d)
let diffseltree d =
Tree_dataset.diffsel_tree (Tree_dataset.prepare (tree d))
Tree_dataset.prepare_diffsel_tree (tree d)
let diffsel d =
Diffsel.diffsel
......@@ -155,15 +155,15 @@ let tdg09 d =
|> Tamuri.results
let identical d =
let tree_sc = Tree_dataset.tree (tree_dataset d) `Detection in
let tree_id = Tree_dataset.tree (tree_dataset d) `Simulation in
let tree_sc = Tree_dataset.prepare_sc_tree (tree d) in
let tree_id = Tree_dataset.prepare_tree_with_node_id (tree d) in
Identical.identical ~tree_id ~tree_sc ~prot_model:"LG08" ~faa:(amino_acid_alignment d) ()
|> Identical.results
let topological d =
let faa = amino_acid_alignment d in
let tree = Tree_dataset.tree (tree_dataset d) `Simulation in
let tree_conv = Tree_dataset.topological_tree (tree_dataset d) in
let tree_conv = Tree_dataset.prepare_topological_tree (tree d) in
let tree = Tree_dataset.prepare_tree_with_node_id (tree d) in
Topological.topological ~faa ~tree ~tree_conv ~prot_model:"LG08" ()
|> Topological.results
......
......@@ -548,7 +548,7 @@ let plot_det_meth_res_auto_t ~t_choices ~dataset_results_l =
let tree_prefix = dataset_results.tree_prefix in
let model_prefix = dataset_results.model_prefix in
let ready_dataset = dataset_results.dataset.dataset in
let tree = Tree_dataset.tree ready_dataset.tree_dataset `Detection in
let tree = Tree_dataset.prepare_sc_tree ready_dataset.input_tree in
let faa = ready_dataset.faa in
let tsv = dataset_results.merged_results in
let res_by_tools = dataset_results.res_by_tools in
......@@ -563,7 +563,7 @@ let get_simu_infos ~(dataset:Dataset.t) =
let model_prefix = dataset.model_prefix in
let ready_dataset = dataset.dataset in
let faa = ready_dataset.faa in
let tree_sc = Tree_dataset.tree ready_dataset.tree_dataset `Detection in
let tree_sc = Tree_dataset.prepare_sc_tree ready_dataset.input_tree in
let fna_infos = ready_dataset.fna_infos in
match fna_infos with
| Some w -> Some (make_simu_infos ~descr:model_prefix ~faa ~tree_sc ~fna_infos:w)
......
......@@ -24,17 +24,18 @@ let of_raw ?(descr="") (raw_dataset : Raw_dataset.t) =
let repo rd =
let phy_nt = (Bppsuite.fna2phy ~fna:rd.fna) in
let phy_aa = (Bppsuite.faa2phy ~faa:rd.faa) in
let tree_prefix = "to_be_fix" in
Repo.[
[
item ["input_tree.nhx"] rd.input_tree ;
item ["recalculated_tree_nt.nw"] (Phyml.phyml_tree ~model:GTR ~tree:rd.input_tree phy_nt );
item ["recalculated_tree_aa.nw"] (Phyml.phyml_tree ~model:LG ~tree:rd.input_tree phy_aa );
item ["tree.H0.node_ids" ] (Tree_dataset.nodes rd.tree_dataset (H0 (Fixed 5.))) ;
item ["tree.Ha.node_ids" ] (Tree_dataset.nodes rd.tree_dataset (HaPCOC (Fixed 1.))) ;
item ["tree.only_convergent_tags.nhx" ] (Tree_dataset.tree rd.tree_dataset `Detection) ;
item ["tree.only_node_ids.nhx" ] (Tree_dataset.tree rd.tree_dataset `Simulation) ;
item ["tree.diffsel" ] (Tree_dataset.diffsel_tree rd.tree_dataset) ;
item ["tree.convergent_topology" ] (Tree_dataset.topological_tree rd.tree_dataset) ;
item ["tree.H0.node_ids" ] (Tree_dataset.prepare_nodes rd.input_tree (H0 (Fixed 5.))) ;
item ["tree.Ha.node_ids" ] (Tree_dataset.prepare_nodes rd.input_tree (HaPCOC (Fixed 1.))) ;
item ["tree.only_convergent_tags.nhx" ] (Tree_dataset.prepare_sc_tree rd.input_tree ) ;
item ["tree.only_node_ids.nhx" ] (Tree_dataset.prepare_tree_with_node_id rd.input_tree ) ;
item ["tree.diffsel" ] (Tree_dataset.prepare_diffsel_tree ~descr:tree_prefix rd.input_tree) ;
item ["tree.convergent_topology" ] (Tree_dataset.prepare_topological_tree ~descr:tree_prefix rd.input_tree) ;
item ["simulated_sequences.fna"] rd.fna ;
item ["simulated_sequences_nt.phy"] phy_nt ;
item ["simulated_sequences_aa.phy"] phy_aa ;
......@@ -58,7 +59,7 @@ let repo_realdata ~tree_prefix ~ali_prefix ~calc_dnds rd =
];
Repo.[
item [ali_prefix ^ ".nt.phy"] phy_nt ;
item [ali_prefix ^ ".tree.diffsel" ] (Tree_dataset.diffsel_tree rd.tree_dataset) ;
item [ali_prefix ^ ".tree.diffsel" ] (Tree_dataset.prepare_diffsel_tree rd.input_tree) ;
] |> Repo.shift "ForDiffsel";
if calc_dnds then
Repo.[
......
#===================================================================================================
# Create output files
#===================================================================================================
######### output trees for simulation
### tree.only_node_ids.nhx: a tree with numbered nodes
t.write(format=1, features=["ND"], outfile = "%s/tree.only_node_ids.nhx" %(OutDirName),format_root_node=True)
### tree.H0.node_ids: null hypothesis
#### -> 1 line: all nodes ids
all_node_ids = range(nodeId-1)
with open("%s/tree.H0.node_ids" %(OutDirName), "w") as output_H0_node_ids:
output_H0_node_ids.write("nonhomogeneous.number_of_models = 1")
output_H0_node_ids.write("\n")
output_H0_node_ids.write("model1.nodes_id="+",".join(map(str, all_node_ids)))
### tree.Ha.node_ids: alternative hypothesis
#### -> 3 lines: 1) node ids under the ancestral model
#### 2) node ids under the convergent model (transition)
#### 3) node ids under the convergent model
conv_node_ids = [n.ND for n in t.search_nodes(Condition = "1")]
trans_node_ids = [n.ND for n in t.search_nodes(Transition = "1")]
conv_node_ids = [i for i in conv_node_ids if i not in trans_node_ids]
not_conv_node_ids = [i for i in all_node_ids if i not in conv_node_ids+trans_node_ids]
logger.info(conv_node_ids)
logger.info(trans_node_ids)
logger.info(not_conv_node_ids)
if trans_node_ids and conv_node_ids:
nonhomogeneous_number_of_models = "nonhomogeneous.number_of_models = 3"
models = "\n".join(["model2 = $(modelT)",
"model3 = $(modelC)"])
node_ids = "\n".join(["model1.nodes_id="+",".join(map(str, not_conv_node_ids)),
"model2.nodes_id="+",".join(map(str, trans_node_ids)),
"model3.nodes_id="+",".join(map(str, conv_node_ids))
])
elif trans_node_ids and not conv_node_ids:
nonhomogeneous_number_of_models = "nonhomogeneous.number_of_models = 2"
models = "\n".join(["model2 = $(modelT)"])
node_ids = "\n".join(["model1.nodes_id="+",".join(map(str, not_conv_node_ids)),
"model2.nodes_id="+",".join(map(str, trans_node_ids))
])
elif not trans_node_ids and conv_node_ids:
nonhomogeneous_number_of_models = "nonhomogeneous.number_of_models = 2"
models = "\n".join(["model2 = $(modelC)"])
node_ids = "\n".join(["model1.nodes_id="+",".join(map(str, not_conv_node_ids)),
"model2.nodes_id="+",".join(map(str, conv_node_ids))
])
else:
logger.error("No convergent nodes")
sys.exit(2)
with open("%s/tree.Ha.node_ids" %(OutDirName), "w") as output_Ha_node_ids:
output_Ha_node_ids.write(nonhomogeneous_number_of_models)
output_Ha_node_ids.write("\n")
output_Ha_node_ids.write(models)
output_Ha_node_ids.write("\n")
output_Ha_node_ids.write(node_ids)
### tree.H0_a.node_ids: alternative hypothesis
#### -> 2 lines: 1) node ids under the ancestral model
#### 2) node ids under the convergent model (convergent+transition)
if trans_node_ids + conv_node_ids:
nonhomogeneous_number_of_models = "nonhomogeneous.number_of_models = 2"
models = ""
node_ids = "\n".join(["model1.nodes_id="+",".join(map(str, not_conv_node_ids)),
"model2.nodes_id="+",".join(map(str, trans_node_ids+conv_node_ids))
])
else:
logger.error("No convergent nodes")
sys.exit(2)
with open("%s/tree.H0_a.node_ids" %(OutDirName), "w") as output_Ha_node_ids:
output_Ha_node_ids.write(nonhomogeneous_number_of_models)
output_Ha_node_ids.write("\n")
output_Ha_node_ids.write(models)
output_Ha_node_ids.write("\n")
output_Ha_node_ids.write(node_ids)
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright or Copr. Centre National de la Recherche Scientifique (CNRS) (2018)
# Contributors:
# - Carine Rey <carine.rey@ens-lyon.org>
# This software is a computer program whose purpose is to provide a set of scripts for pre and post processing of data for
# convergence detection programs.
# This software is governed by the CeCILL-C license under French law and abiding by the rules of distribution of free software.
# You can use, modify and/ or redistribute the software under the terms of the CeCILL-C license as circulated by CEA, CNRS and
# INRIA at the following URL "http://www.cecill.info".
# As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, users
# are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive
# licensors have only limited liability.
# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or
# reproducing the software by the user in light of its specific status of free software, that may mean that it is complicated
# to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth
# computer knowledge. Users are therefore encouraged to load and test the software's suitability as regards their requirements
# in conditions enabling the security of their systems and/or data to be ensured and, more generally, to use and operate it in
# the same conditions as regards security.
# The fact that you are presently reading this means that you have had knowledge of the CeCILL-C license and that you accept
# its terms.
import argparse
import sys
import os
import logging
from ete3 import Tree, NodeStyle, TreeStyle, TextFace
#===================================================================================================
# inputs
#===================================================================================================
### Option defining
parser = argparse.ArgumentParser(prog="parse_input_tree.py",
description='')
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
parser.add_argument('--debug', action="store_true",
help="debug mode",
default=False)
##############
requiredOptions = parser.add_argument_group('REQUIRED OPTIONS')
requiredOptions.add_argument('-t', "--tree", type=argparse.FileType('r'),
help='Input tree filename', required=True)
requiredOptions.add_argument('-o', '--output_dir', type=str,
help="Output directory name", required=True)
##############
### Option parsing
args = parser.parse_args()
TreeFile = args.tree
OutDirName = args.output_dir
#===================================================================================================
# Set up output directory and logger
#===================================================================================================
### Set up the logger
# create logger
logger = logging.getLogger("parse_input_tree")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
if args.debug:
ch.setLevel(logging.DEBUG)
else:
ch.setLevel(logging.INFO)
# create formatter and add it to the handlers
formatter_ch = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter_ch)
logger.addHandler(ch)
logger.debug(sys.argv)
### Set up the output directory
if os.path.isdir(OutDirName):
pass
elif OutDirName: # if OutDirName is not a empty string we create the directory
os.makedirs(OutDirName)
logger.debug("mkdir %s", OutDirName)
#===================================================================================================
# Read input tree
#===================================================================================================
try:
t=Tree(TreeFile.name)
except Exception as exc:
logger.error(str(exc))
sys.exit(1)
if t:
features = []
for n in t.traverse("postorder"): # get all features:
features.extend(list(set(dir(n)) - set(dir(Tree()))))
features = list(set(features)) # list(set(*)) = remove duplicates
logger.info("No detected tag" if not features else "Detected tags: "+", ".join([f for f in features]))
#check rooted tree
nb_root_children = len(t.get_children())
if nb_root_children > 2:
logger.error("Unrooted tree")
sys.exit(1)
if "ND" in features:
logger.warning("\"ND\" is in the detected tags but it will be removed by the programm")
features.remove("ND")
if not "Condition" in features:
logger.error("\"Condition\" must be in the detected tags. \"Condition:1\" must identify nodes under the convergent model under Ha")
sys.exit(1)
if not "Transition" in features:
logger.error("\"Transition\" must be in the detected tags. \"Transition:1\" must identify nodes where there are transitions")
sys.exit(1)
if "Transition" in features:
logger.info("\"Transition\" is in the detected tags. \"Transition:1\" will be use to indicate OneChange model on this node")
# Check existing bl
branch_lengths = []
nodeId = 0
for node in t.traverse("postorder"):
node.add_features(ND=nodeId)
branch_lengths.append(node.dist)
nodeId = nodeId + 1
logger.debug("Branch length %s", branch_lengths)
if set(branch_lengths) == set([1.0]):
logger.warning("No branch length in %s, all branch length will be put to 1",tree_filename)
if not (t and branch_lengths):
sys.exit(1)
logger.info("Tree (%s) ok after checking", TreeFile.name)
#===================================================================================================
# Create output files
#===================================================================================================
######### output trees for detection
all_node_ids = range(nodeId-1)
conv_node_ids = [n.ND for n in t.search_nodes(Condition = "1")]
trans_node_ids = [n.ND for n in t.search_nodes(Transition = "1")]
conv_node_ids = [i for i in conv_node_ids if i not in trans_node_ids]
not_conv_node_ids = [i for i in all_node_ids if i not in conv_node_ids+trans_node_ids]
### tree.diffsel: a diffsel input formated tree
tdiffsel = t.copy(method="deepcopy")
for n in tdiffsel.traverse():
if n.ND in conv_node_ids+trans_node_ids:
n.dist = 1
elif n.ND in not_conv_node_ids:
n.dist = 0
tdiffsel.write(format=1, outfile = "%s/tree.diffsel" %(OutDirName))
######### output trees for detection
### tree.only_convergent_tags.nhx: a tree with only Condition and Transition tags
t.write(format=1, features=["Condition","Transition"], outfile = "%s/tree.only_convergent_tags.nhx" %(OutDirName))
#===================================================================================================
# Create output files
#===================================================================================================
######### output trees for detection
### tree.topological : a diffsel input formated tree
def build_conv_topo(t):
conv_nodes_ids = [n.ND for n in t.search_nodes(Condition="1")]
tconv = t.copy(method="deepcopy")
for n in tconv.iter_leaves():
n.add_features(L=1)
for n in tconv.traverse():
n.add_features(COPY=0)
# get the most recent ancestral node of all the convergent clades
l_convergent_clades = tconv.search_nodes(Condition="1")
common_anc_conv=tconv.get_common_ancestor(l_convergent_clades)
# duplicate it at its same location (branch lenght = 0). we get
# a duplicated subtree with subtrees A and B (A == B)
dist_dup = common_anc_conv.dist
if not common_anc_conv.is_root():
dup_point = common_anc_conv.add_sister(name="dup_point",dist=0.000001)
dup_point_root = False
else:
dup_point = Tree()
dup_point_root = True
dup_point.dist=0.000001
dup_point.add_features(ND=0,Transition="0", Condition="0")
common_anc_conv.detach()
common_anc_conv_copy = common_anc_conv.copy(method="deepcopy")
# tag duplicated nodes:
for n in common_anc_conv_copy.traverse():
n.COPY=1
if n.ND not in conv_nodes_ids and not n.is_root():
n.dist=0.000001
# pruned A from all branches not leading to any convergent clade
l_leaves_to_keep_A = common_anc_conv.search_nodes(COPY=0, Condition="0", L=1)
#logger.debug("A: %s",l_leaves_to_keep_A)
common_anc_conv.prune(l_leaves_to_keep_A, preserve_branch_length=True)
# pruned B from all branches not leading to any non-convergent clade
l_leaves_to_keep_B = common_anc_conv_copy.search_nodes(COPY=1, Condition="1", L=1)
#logger.debug("B : %s", l_leaves_to_keep_B)
common_anc_conv_copy.prune(l_leaves_to_keep_B, preserve_branch_length=True)
dup_point.add_child(common_anc_conv_copy)
dup_point.add_child(common_anc_conv)
tconv = dup_point.get_tree_root()
nodeId = 0
for node in tconv.traverse("postorder"):
node.ND = nodeId
nodeId += 1
return tconv
tconv = build_conv_topo(t)
tconv.write(format=1, outfile = "%s/tree.topological" %(OutDirName))
......@@ -13,23 +13,84 @@ let prepare ?(descr="") tree =
]
]
let nodes dataset (model : Convergence_hypothesis.t) =
Workflow.select dataset (
match model with
| H0 Fixed _ -> [ "tree.H0.node_ids" ]
| H0 Variable _ -> [ "tree.H0_a.node_ids" ]
| HaPC _ | HaPCOC _ -> [ "tree.Ha.node_ids" ]
let prepare_nodes ?(descr="") tree (model : Convergence_hypothesis.t) =
let w = Workflow.shell ~descr:("utils.prepare_diffsel_tree." ^ descr) [
cmd "python" ~img [
file_dump (
seq ~sep:"\n" [
string Scripts.parse_input_tree_common_part ;
string Scripts.parse_input_tree_bpp_sim_part ;
]
) ;
opt "-t" dep tree ;
opt "-o" ident dest ;
]
] in
Workflow.select w (
match model with
| H0 Fixed _ -> [ "tree.H0.node_ids" ]
| H0 Variable _ -> [ "tree.H0_a.node_ids" ]
| HaPC _ | HaPCOC _ -> [ "tree.Ha.node_ids" ]
)
let tree dataset mode =
Workflow.select dataset (
match mode with
| `Detection -> [ "tree.only_convergent_tags.nhx" ]
| `Simulation -> [ "tree.only_node_ids.nhx" ]
)
let prepare_tree_with_node_id ?(descr="") tree =
let w = Workflow.shell ~descr:("utils.prepare_id_tree." ^ descr) [
cmd "python" ~img [
file_dump (
seq ~sep:"\n" [
string Scripts.parse_input_tree_common_part ;
string Scripts.parse_input_tree_bpp_sim_part ;
]
) ;
opt "-t" dep tree ;
opt "-o" ident dest ;
]
] in
Workflow.select w [ "tree.only_node_ids.nhx" ]
let diffsel_tree dataset =
Workflow.select dataset [ "tree.diffsel" ]
let topological_tree dataset =
Workflow.select dataset [ "tree.topological" ]
let prepare_sc_tree ?(descr="") tree =
let w = Workflow.shell ~descr:("utils.prepare_pcoc_tree." ^ descr) [
cmd "python" ~img [
file_dump (
seq ~sep:"\n" [
string Scripts.parse_input_tree_common_part ;
string Scripts.parse_input_tree_pcoc_part ;
]
) ;
opt "-t" dep tree ;
opt "-o" ident dest ;
]
] in
Workflow.select w [ "tree.only_convergent_tags.nhx" ]
let prepare_diffsel_tree ?(descr="") tree =
let w = Workflow.shell ~descr:("utils.prepare_diffsel_tree." ^ descr) [
cmd "python" ~img [
file_dump (
seq ~sep:"\n" [
string Scripts.parse_input_tree_common_part ;
string Scripts.parse_input_tree_diffsel_part ;
]
) ;
opt "-t" dep tree ;
opt "-o" ident dest ;
]
] in
Workflow.select w [ "tree.diffsel" ]
let prepare_topological_tree ?(descr="") tree =
let w = Workflow.shell ~descr:("utils.prepare_topological_tree." ^ descr) [
cmd "python" ~img [
file_dump (
seq ~sep:"\n" [
string Scripts.parse_input_tree_common_part ;
string Scripts.parse_input_tree_topological_part ;
]