1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
"""Endpoints for running the rqtl cmd"""
import os
import uuid
import subprocess
from pathlib import Path
from flask import Blueprint
from flask import current_app
from flask import jsonify
from flask import request
from gn3.computations.rqtl import (
generate_rqtl_cmd,
process_rqtl_mapping,
process_rqtl_pairscan,
process_perm_output,
)
from gn3.fs_helpers import assert_path_exists, get_tmpdir
rqtl = Blueprint("rqtl", __name__)
@rqtl.route("/compute", methods=["POST"])
def compute():
"""Given at least a geno_file and pheno_file, generate and
run the rqtl_wrapper script and return the results as JSON
"""
genofile = request.form["geno_file"]
phenofile = request.form["pheno_file"]
assert_path_exists(genofile)
assert_path_exists(phenofile)
run_id = request.args.get("id")
with open(
os.path.join(current_app.config.get("TMPDIR"), f"{run_id}.txt"),
"w+",
encoding="utf-8",
):
# TODO thos should be refactored
pass
# Split kwargs by those with values and boolean ones
# that just convert to True/False
kwargs = ["covarstruct", "model", "method", "nperm", "scale", "control"]
boolean_kwargs = ["addcovar", "interval", "pstrata", "pairscan"]
all_kwargs = kwargs + boolean_kwargs
rqtl_kwargs = {
"geno": genofile,
"pheno": phenofile,
"outdir": current_app.config.get("TMPDIR"),
}
rqtl_bool_kwargs = []
for kwarg in all_kwargs:
if kwarg in request.form:
if kwarg in kwargs:
rqtl_kwargs[kwarg] = request.form[kwarg]
if kwarg in boolean_kwargs:
rqtl_bool_kwargs.append(kwarg)
outdir = os.path.join(get_tmpdir(), "gn3")
if not os.path.isdir(outdir):
os.mkdir(outdir)
rqtl_cmd = generate_rqtl_cmd(
rqtl_wrapper_cmd=str(
Path(__file__)
.absolute()
.parent.parent.parent.joinpath("scripts/rqtl_wrapper.R")
),
rqtl_wrapper_kwargs=rqtl_kwargs,
rqtl_wrapper_bool_kwargs=rqtl_bool_kwargs,
)
rqtl_output = {}
# get the stdout file
run_id = request.args.get("id", str(uuid.uuid4()))
if not os.path.isfile(
os.path.join(
current_app.config.get("TMPDIR"), "gn3", rqtl_cmd.get("output_file")
)
):
pass
stream_ouput_file = os.path.join(current_app.config.get("TMPDIR"), f"{run_id}.txt")
run_process(rqtl_cmd.get("rqtl_cmd").split(), stream_ouput_file, run_id)
if "pairscan" in rqtl_bool_kwargs:
rqtl_output["results"] = process_rqtl_pairscan(
rqtl_cmd.get("output_file"), genofile
)
else:
rqtl_output["results"] = process_rqtl_mapping(rqtl_cmd.get("output_file"))
if int(rqtl_kwargs["nperm"]) > 0:
# pylint: disable=C0301
(
rqtl_output["perm_results"],
rqtl_output["suggestive"],
rqtl_output["significant"],
) = process_perm_output(rqtl_cmd.get("output_file"))
return jsonify(rqtl_output)
def run_process(cmd, output_file, run_id):
"""Function to execute an external process and
capture the stdout in a file
input:
cmd: the command to execute as a list of args.
output_file: abs file path to write the stdout.
run_id: unique id to identify the process
output:
Dict with the results o either success or failure.
"""
try:
# phase: execute the rscript cmd
with subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
) as process:
for line in iter(process.stdout.readline, b""):
# phase: capture the stdout for eaching line allowing read and write
with open(output_file, "a+", encoding="utf-8") as file_handler:
file_handler.write(line.decode("utf-8"))
process.wait()
if process.returncode == 0:
return {"msg": "success", "code": 0, "run_id": run_id}
return {"msg": "Process failed",
"code": process.returncode, "run_id": run_id}
except subprocess.CalledProcessError as error:
return {"msg": "Process failed",
"error": str(error), "run_id": run_id}
|