aboutsummaryrefslogtreecommitdiff
path: root/qc_app/upload/rqtl2.py
diff options
context:
space:
mode:
Diffstat (limited to 'qc_app/upload/rqtl2.py')
-rw-r--r--qc_app/upload/rqtl2.py104
1 files changed, 101 insertions, 3 deletions
diff --git a/qc_app/upload/rqtl2.py b/qc_app/upload/rqtl2.py
index c05f675..7a53756 100644
--- a/qc_app/upload/rqtl2.py
+++ b/qc_app/upload/rqtl2.py
@@ -28,9 +28,9 @@ from qc_app.files import save_file, fullpath
from qc_app.dbinsert import species as all_species
from qc_app.db_utils import with_db_connection, database_connection
-from qc_app.db.tissues import all_tissues, tissue_by_id
from qc_app.db.platforms import platform_by_id, platforms_by_species
from qc_app.db.averaging import averaging_methods, averaging_method_by_id
+from qc_app.db.tissues import all_tissues, tissue_by_id, create_new_tissue
from qc_app.db import (
species_by_id,
save_population,
@@ -65,6 +65,7 @@ def select_species():
flash("Invalid species or no species selected!", "alert-error error-rqtl2")
return redirect(url_for("upload.rqtl2.select_species"))
+
@rqtl2.route("/upload/species/<int:species_id>/select-population",
methods=["GET", "POST"])
def select_population(species_id: int):
@@ -93,6 +94,7 @@ def select_population(species_id: int):
species_id=species["SpeciesId"],
population_id=population["InbredSetId"]))
+
@rqtl2.route("/upload/species/<int:species_id>/create-population",
methods=["POST"])
def create_population(species_id: int):
@@ -129,9 +131,11 @@ def create_population(species_id: int):
pgsrc="create-population"),
code=307)
+
class __RequestError__(Exception): #pylint: disable=[invalid-name]
"""Internal class to avoid pylint's `too-many-return-statements` error."""
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle"),
methods=["GET", "POST"])
@@ -197,6 +201,7 @@ def upload_rqtl2_bundle(species_id: int, population_id: int):
return redirect(url_for(
"upload.rqtl2.rqtl2_bundle_qc_status", jobid=jobid))
+
@rqtl2.route("/upload/species/rqtl2-bundle/qc-status/<uuid:jobid>",
methods=["GET", "POST"])
def rqtl2_bundle_qc_status(jobid: UUID):
@@ -255,15 +260,18 @@ def rqtl2_bundle_qc_status(jobid: UUID):
except jobs.JobNotFound:
return render_template("rqtl2/no-such-job.html", jobid=jobid)
+
def form_errors(formargs, *errorcheckers) -> Iterable[tuple[str, Response]]:
"""Retrieve all errors from the form inputs"""
return (checker(formargs) for checker in errorcheckers)
+
def redirect_on_error(flaskroute, **kwargs):
"""Utility to redirect on error"""
return redirect(url_for(flaskroute, **kwargs, pgsrc="error"),
code=(307 if request.method == "POST" else 302))
+
def check_species(conn: mdb.Connection, formargs: dict) -> Optional[
tuple[str, Response]]:
"""
@@ -280,6 +288,7 @@ def check_species(conn: mdb.Connection, formargs: dict) -> Optional[
return None
+
def check_population(conn: mdb.Connection,
formargs: dict,
species_id) -> Optional[tuple[str, Response]]:
@@ -299,6 +308,7 @@ def check_population(conn: mdb.Connection,
return None
+
def check_r_qtl2_bundle(formargs: dict,
species_id,
population_id) -> Optional[tuple[str, Response]]:
@@ -315,6 +325,7 @@ def check_r_qtl2_bundle(formargs: dict,
return None
+
def check_geno_dataset(formargs: dict,
species_id,
population_id) -> Optional[tuple[str, Response]]:
@@ -328,6 +339,7 @@ def check_geno_dataset(formargs: dict,
return None
+
def check_probe_study(formargs: dict,
species_id,
population_id) -> Optional[tuple[str, Response]]:
@@ -340,6 +352,7 @@ def check_probe_study(formargs: dict,
return None
+
def check_probe_dataset(formargs: dict,
species_id,
population_id) -> Optional[tuple[str, Response]]:
@@ -352,6 +365,7 @@ def check_probe_dataset(formargs: dict,
return None
+
def with_errors(conn: mdb.Connection, endpointthunk: Callable, *checkerstrings):
"""Run 'endpointthunk' with error checking."""
formargs = {**dict(request.args), **dict(request.form)}
@@ -378,6 +392,7 @@ def with_errors(conn: mdb.Connection, endpointthunk: Callable, *checkerstrings):
return endpointthunk()
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/select-geno-dataset"),
methods=["POST"])
@@ -406,6 +421,7 @@ def select_geno_dataset(species_id: int, population_id: int):
return with_errors(
conn, __thunk__, "species", "population", "rqtl2_bundle_file", "geno_dataset")
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/create-geno-dataset"),
methods=["POST"])
@@ -457,6 +473,71 @@ def create_geno_dataset(species_id: int, population_id: int):
return with_errors(conn, __thunk__, "species", "population",
"rqtl2_bundle_file")
+
+@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
+ "/rqtl2-bundle/select-tissue"),
+ methods=["POST"])
+def select_tissue(species_id: int, population_id: int):
+ """Select from existing tissues."""
+ with database_connection(app.config["SQL_URI"]) as conn:
+ def __thunk__():
+ if not bool(request.form.get("tissueid", "").strip()):
+ flash("Invalid tissue selection!",
+ "alert-error error-select-tissue error-rqtl2")
+
+ return redirect(url_for("upload.rqtl2.select_dataset_info",
+ species_id=species_id,
+ population_id=population_id,
+ pgsrc="upload.rqtl2.select_geno_dataset"),
+ code=307)
+
+ return with_errors(
+ conn, __thunk__, "species", "population", "rqtl2_bundle_file", "geno_dataset")
+
+@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
+ "/rqtl2-bundle/create-tissue"),
+ methods=["POST"])
+def create_tissue(species_id: int, population_id: int):
+ """Add new tissue, organ or biological material to the system."""
+ form = request.form
+ datasetinfopage = redirect(
+ url_for("upload.rqtl2.select_dataset_info",
+ species_id=species_id,
+ population_id=population_id,
+ pgsrc="upload.rqtl2.select_geno_dataset"),
+ code=307)
+ with database_connection(app.config["SQL_URI"]) as conn:
+ tissuename = form.get("tissuename", "").strip()
+ tissueshortname = form.get("tissueshortname", "").strip()
+ if not bool(tissuename):
+ flash("Organ/Tissue name MUST be provided.",
+ "alert-error error-create-tissue error-rqtl2")
+ return datasetinfopage
+
+ if not bool(tissueshortname):
+ flash("Organ/Tissue short name MUST be provided.",
+ "alert-error error-create-tissue error-rqtl2")
+ return datasetinfopage
+
+ try:
+ tissue = create_new_tissue(conn, tissuename, tissueshortname)
+ flash("Tissue created successfully!", "alert-success")
+ return render_template(
+ "rqtl2/create-tissue-success.html",
+ species=species_by_id(conn, species_id),
+ population=population_by_species_and_id(
+ conn, species_id, population_id),
+ rqtl2_bundle_file=request.form["rqtl2_bundle_file"],
+ geno_dataset=geno_dataset_by_id(
+ conn,
+ int(request.form["geno-dataset-id"])),
+ tissue=tissue)
+ except mdb.IntegrityError as _ierr:
+ flash("Tissue/Organ with that short name already exists!",
+ "alert-error error-create-tissue error-rqtl2")
+ return datasetinfopage
+
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/select-probeset-study"),
methods=["POST"])
@@ -477,6 +558,7 @@ def select_probeset_study(species_id: int, population_id: int):
"rqtl2_bundle_file", "geno_dataset",
"probeset_study")
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/select-probeset-dataset"),
methods=["POST"])
@@ -498,6 +580,7 @@ def select_probeset_dataset(species_id: int, population_id: int):
"rqtl2_bundle_file", "geno_dataset",
"probeset_study", "probeset_dataset")
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/create-probeset-study"),
methods=["POST"])
@@ -540,6 +623,7 @@ def create_probeset_study(species_id: int, population_id: int):
return with_errors(conn, __thunk__, "species", "population",
"rqtl2_bundle_file", "geno_dataset")
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/create-probeset-dataset"),
methods=["POST"])
@@ -597,6 +681,7 @@ def create_probeset_dataset(species_id: int, population_id: int):#pylint: disabl
"rqtl2_bundle_file", "geno_dataset",
"probeset_study")
+
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/dataset-info"),
methods=["POST"])
@@ -625,6 +710,19 @@ def select_dataset_info(species_id: int, population_id: int):
geno_dataset = geno_dataset_by_id(conn, int(form["geno-dataset-id"]))
if "pheno" in cdata and not bool(form.get("probe-study-id")):
+ tissue = tissue_by_id(conn, form.get("tissueid", "").strip())
+ if not bool(tissue):
+ return render_template(
+ "rqtl2/select-tissue.html",
+ species=species,
+ population=population,
+ rqtl2_bundle_file=thefile.name,
+ geno_dataset=geno_dataset,
+ studies=probeset_studies_by_species_and_population(
+ conn, species_id, population_id),
+ platforms=platforms_by_species(conn, species_id),
+ tissues=all_tissues(conn))
+
return render_template(
"rqtl2/select-probeset-study-id.html",
species=species,
@@ -634,7 +732,7 @@ def select_dataset_info(species_id: int, population_id: int):
studies=probeset_studies_by_species_and_population(
conn, species_id, population_id),
platforms=platforms_by_species(conn, species_id),
- tissues=all_tissues(conn))
+ tissue=tissue)
probeset_study = probeset_study_by_id(
conn, int(form["probe-study-id"]))
@@ -666,7 +764,6 @@ def select_dataset_info(species_id: int, population_id: int):
"rqtl2_bundle_file")
-
@rqtl2.route(("/upload/species/<int:species_id>/population/<int:population_id>"
"/rqtl2-bundle/confirm-bundle-details"),
methods=["POST"])
@@ -719,6 +816,7 @@ def confirm_bundle_details(species_id: int, population_id: int):
"rqtl2_bundle_file", "geno_dataset",
"probeset_study", "probeset_dataset")
+
@rqtl2.route("/status/<uuid:jobid>")
def rqtl2_processing_status(jobid: UUID):
"""Retrieve the status of the job processing the uploaded R/qtl2 bundle."""