about summary refs log tree commit diff
path: root/gn3/api/rqtl.py
blob: 1139d9e401b9543d6c49c3ff83b52c73c897321c (plain)
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
"""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"), 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(rscript_cmd, output_file, run_id):
    """Main function to do the streaming"""
    # TODO: move this function to own file
    # pylint: disable=consider-using-with
    process = subprocess.Popen(
        rscript_cmd, shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT
    )
    for line in iter(process.stdout.readline, b""):
        # these allow endpoint stream to read the file since
        # no read and write file same tiem
        with open(output_file, "a+", encoding="utf-8") as file_handler:
            file_handler.write(line.decode("utf-8"))
    process.stdout.close()
    process.wait()
    if process.returncode == 0:
        return jsonify({"msg": "success",
                        "results": "file_here",
                        "run_id": run_id})
    return jsonify({"msg": "fail",
                    "error": "Process failed",
                    "run_id": run_id})