Source code for isoenum_webgui.routes

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
isoenum_webgui.routes
~~~~~~~~~~~~~~~~~~~~~

Isotopic enumerator web interface routes.
"""

import csv
import io
import json

from flask import render_template
from flask import request
from flask import redirect
from flask import url_for
from flask import jsonify
from flask import flash
from pyexcel.exceptions import FileTypeNotSupported

from isoenum_webgui import app
from isoenum_webgui.forms import FileForm
from isoenum_webgui.proc import generate_table
from isoenum_webgui.proc import generate_nmr
from isoenum_webgui.proc import update_record
from isoenum_webgui.proc import create_initial_record
from isoenum_webgui.proc import create_empty_record

from . import RECORDS
from . import HEADER
from . import CSV_HEADER
from . import NMR_TYPES
from . import EXAMPLE_PROJECT


[docs]@app.route("/", methods=["GET", "POST"]) @app.route("/home", methods=["GET", "POST"]) def home(): """Home.""" file_input_form = FileForm() if file_input_form.validate_on_submit(): if RECORDS: RECORDS.clear() try: json_str = request.files["file"].read() RECORDS.update(json.loads(json_str)) except json.decoder.JSONDecodeError: try: table_data = request.get_array(field_name="file") if len(table_data[0]) == 1 and table_data[0][0].lower() != "base identifier": table_header = ["Base Identifier"] else: table_header = table_data.pop(0) for table_row in table_data: record = create_initial_record(header=table_header, row=table_row) RECORDS[record["record_id"]] = record for i in generate_table(records=RECORDS): progress_percentage = "{0:.0%}".format(i / len(RECORDS)) except FileTypeNotSupported: flash("Invalid file", "danger") return render_template("home.html", file_input_form=file_input_form) except Exception: flash("Invalid file", "danger") return render_template("home.html", file_input_form=file_input_form) return redirect(url_for("table")) return render_template("home.html", file_input_form=file_input_form)
[docs]@app.route("/example", methods=["GET", "POST"]) def example_project(): """Example project.""" if RECORDS: RECORDS.clear() RECORDS.update(EXAMPLE_PROJECT) return redirect(url_for("table"))
[docs]@app.route("/table", methods=["GET", "POST"]) def table(): """Display base and representative InChI.""" if request.method == "POST" and request.form.get("nmr-inchi-table-data"): nmr_experiment_type = request.form.get("select-nmr-experiment") generate_nmr( nmr_experiment_type=nmr_experiment_type, records=RECORDS ) return redirect(url_for("nmrtable", nmr_type=nmr_experiment_type)) return render_template("table.html", table_header=HEADER, table_data=RECORDS)
[docs]@app.route("/nmrtable", methods=["GET", "POST"]) def nmrtable(): """Display NMR-specific InChI.""" nmr_experiment_type = request.args.get("nmr_type", "1D-1H") nmr_experiment_type = NMR_TYPES[nmr_experiment_type] return render_template( "nmrtable.html", table_header=HEADER, table_data=RECORDS, nmr_experiment_type=nmr_experiment_type)
[docs]@app.route("/update_record", methods=["POST"]) def update(): """Update record.""" record_id = request.form.get("record_id", "") new_record = update_record(record=request.form) RECORDS[record_id].update(new_record) return jsonify(RECORDS[record_id])
[docs]@app.route("/add_record", methods=["POST"]) def add(): """Add empty record.""" record = create_empty_record() RECORDS[record["record_id"]] = record return jsonify({"record_id": record["record_id"]})
[docs]@app.route("/remove_record", methods=["POST"]) def remove(): """Remove record.""" record_id = request.form.get("record_id", "") if record_id: try: RECORDS.pop(record_id) except KeyError: raise KeyError else: raise KeyError return jsonify({"record_id": record_id, "success": True})
[docs]@app.route("/molfile/<record_id>/<record_type>", methods=["GET"]) def display_molfile(record_id, record_type): """Display Molfile.""" if record_type == "repr": svg = RECORDS[record_id]["Repr SVG"] molfile = RECORDS[record_id]["Repr Molfile"] elif record_type == "base": svg = RECORDS[record_id]["Base SVG"] molfile = RECORDS[record_id]["Base Molfile"] else: raise ValueError("Unknown record type") return render_template("molfile.html", svg=svg, molfile=molfile)
[docs]@app.route("/export_json", methods=["GET"]) def export_json(): """Export as JSON.""" response = app.response_class( response=json.dumps(RECORDS, indent=4), status=201, mimetype="application/json", headers={"Content-Disposition": "attachment;filename=records.json"}, ) return response
[docs]@app.route("/export_csv", methods=["GET"]) def export_csv(): """Export as CSV.""" textio = io.StringIO() csv_writer = csv.writer(textio) header = CSV_HEADER["table"] csv_writer.writerow(header) for record in RECORDS.values(): row = [record[title] for title in header] csv_writer.writerow(row) response = app.response_class( response=textio.getvalue(), status=201, mimetype="text/csv", headers={"Content-Disposition": "attachment;filename=records.csv"}, ) return response
[docs]@app.route("/export_nmr_csv", methods=["GET", "POST"]) def export_nmr_csv(): """Export NMR-specific InChI as CSV.""" nmr_experiment_type = request.args.get("nmr_type") selected_rows = request.form.get("nmr-csv-data") if selected_rows: row_ids = selected_rows.split(",") textio = io.StringIO() csv_writer = csv.writer(textio) header = CSV_HEADER["nmrtable"] csv_writer.writerow(header) for row_id in row_ids: record_id, _ = row_id.split("_") record_name = RECORDS[record_id]["Name"] base_inchi = RECORDS[record_id]["Base Identifier"] repr_inchi = RECORDS[record_id]["Repr Identifier"] descr = " + ".join(RECORDS[record_id]["NMR"][nmr_experiment_type][repr_inchi][row_id]["descr"]) nmr_inchi = RECORDS[record_id]["NMR"][nmr_experiment_type][repr_inchi][row_id]["inchi"] row = [record_name, base_inchi, repr_inchi, descr, nmr_inchi] csv_writer.writerow(row) response = app.response_class( response=textio.getvalue(), status=201, mimetype="text/csv", headers={"Content-Disposition": "attachment;filename=records.csv"}, ) return response else: flash("Please select NMR-specific InChI", "danger") return redirect(url_for("nmrtable", nmr_type=nmr_experiment_type))
[docs]@app.route("/about") def about(): """About page.""" return render_template("about.html")
[docs]@app.after_request def after_request(response): """Do not cache responses.""" response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0" return response