2 Commits

  1. 12
      2-5-23.txt
  2. 0
      __init__.py
  3. 27
      app.py
  4. 5
      entrypoint.sh
  5. 56
      migrations/versions/1a0a82192181_.py
  6. 17
      poetry.lock
  7. 1
      pyproject.toml
  8. 3
      templates/admin.html
  9. 4
      templates/batchadd.html
  10. 4
      templates/batchquery.html
  11. 9
      validate.py

12
2-5-23.txt

@ -1,12 +0,0 @@
# Changes to Make
- Show how to make a network request in R to the server
- Version Control (what date a compound was added)
- createdAt, but configurable. DONE
- Compare the database to the list of compunds and you only want compounds
from that date or before? DONE
- Emphasizing Local? - Accessible through a url. DONE, all fields accessible.
- Shiny app
- Permissions System (revoke, access API keys)

0
__init__.py

27
app.py

@ -11,13 +11,16 @@ from flask_migrate import Migrate
from uuid import uuid4
import csv
import validate
import secrets
from dotenv import load_dotenv
load_dotenv()
# from datetime import date
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
app.secret_key = '98d31240f9fbe14c8083586db49c19c3a8d3f726'
app.secret_key = os.getenv('SECRET_KEY', secrets.token_hex(16))
db: SQLAlchemy = SQLAlchemy()
migrate = Migrate()
db.init_app(app)
@ -72,20 +75,20 @@ def object_as_dict(obj):
class Chemical(db.Model):
query: db.Query
id = db.Column(db.Integer, primary_key=True)
person_name = db.Column(db.String, nullable=False)
standard_grp = db.Column(db.String, nullable=False)
uploaded_by = db.Column(db.String, nullable=False)
# all fields after here are included in the database
chemical_db_id = db.Column(db.String)
library = db.Column(db.String)
# important fields
name = db.Column(db.String, nullable=False)
metabolite_name = db.Column(db.String, nullable=False)
formula = db.Column(db.String, nullable=False)
mass = db.Column(db.Float, nullable=False)
pubchem_cid = db.Column(db.Integer)
pubmed_refcount = db.Column(db.Integer)
standard_class = db.Column(db.String)
inchikey = db.Column(db.String)
inchikey = db.Column(db.String, nullable=False)
inchikey14 = db.Column(db.String)
final_mz = db.Column(db.Float, nullable=False)
@ -95,7 +98,7 @@ class Chemical(db.Model):
adduct = db.Column(db.String)
detected_adducts = db.Column(db.String)
adduct_calc_mz = db.Column(db.String)
msms_detected = db.Column(db.Boolean)
msms_detected = db.Column(db.Boolean, nullable=False)
msms_purity = db.Column(db.Float)
# serialized into datetime.date
@ -275,7 +278,7 @@ def search_api():
data = []
for x in result:
data.append({"url": url_for("chemical_view", id=x.id),
"name": x.name, "mz": x.final_mz, "rt": x.final_rt})
"name": x.metabolite_name, "mz": x.final_mz, "rt": x.final_rt})
return jsonify(data)
@ -289,10 +292,10 @@ def batch_add_request():
if not session.get('admin'):
abort(403)
if request.method == "POST":
if "csv" not in request.files or request.files["csv"].filename == '':
if "input" not in request.files or request.files["input"].filename == '':
return render_template("batchadd.html", invalid="Blank file included")
# save the file to RAM
file = request.files["csv"]
file = request.files["input"]
os.makedirs("/tmp/walkerdb", exist_ok=True)
filename = os.path.join("/tmp/walkerdb", str(uuid4()))
file.save(filename)
@ -320,10 +323,10 @@ def batch_query_request():
if not session.get('admin'):
abort(403)
if request.method == "POST":
if "csv" not in request.files or request.files["csv"].filename == '':
if "input" not in request.files or request.files["input"].filename == '':
return render_template("batchadd.html", invalid="Blank file included")
# save the file to RAM
file = request.files["csv"]
file = request.files["input"]
os.makedirs("/tmp/walkerdb", exist_ok=True)
filename = os.path.join("/tmp/walkerdb", str(uuid4()))
file.save(filename)
@ -331,7 +334,7 @@ def batch_query_request():
def cleanup(): return os.remove(filename)
# read it as a csv
with open(filename, "r") as csvfile:
reader = csv.DictReader(csvfile)
reader = csv.DictReader(csvfile, delimiter="\t")
queries, error = validate.validate_query_csv_fields(reader)
if error:
cleanup()
@ -351,7 +354,7 @@ def batch_query_request():
hits = []
for x in result:
hits.append({"url": url_for("chemical_view", id=x.id),
"name": x.name, "mz": x.final_mz, "rt": x.final_rt})
"name": x.metabolite_name, "mz": x.final_mz, "rt": x.final_rt})
data.append(dict(
query=query,
hits=hits,

5
entrypoint.sh

@ -2,7 +2,6 @@
set -x
#flask db upgrade
./initialize_db.py
#gunicorn -b 0.0.0.0:5000 'app.__init__.create_app()' --chdir /app
cd /app || exit
flask db upgrade
gunicorn -b 0.0.0.0:5000 app:app --chdir /app

56
migrations/versions/1a0a82192181_.py

@ -0,0 +1,56 @@
"""empty message
Revision ID: 1a0a82192181
Revises: 7e9528cf1416
Create Date: 2023-04-11 19:01:00.565936
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1a0a82192181'
down_revision = '7e9528cf1416'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('chemical', schema=None) as batch_op:
batch_op.add_column(sa.Column('person_name', sa.String(), nullable=False))
batch_op.add_column(sa.Column('standard_grp', sa.String(), nullable=False))
batch_op.add_column(sa.Column('metabolite_name', sa.String(), nullable=False))
batch_op.alter_column('inchikey',
existing_type=sa.VARCHAR(),
nullable=False)
batch_op.alter_column('final_adduct',
existing_type=sa.VARCHAR(),
nullable=False)
batch_op.alter_column('msms_detected',
existing_type=sa.BOOLEAN(),
nullable=False)
batch_op.drop_column('name')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('chemical', schema=None) as batch_op:
batch_op.add_column(sa.Column('name', sa.VARCHAR(), nullable=False))
batch_op.alter_column('msms_detected',
existing_type=sa.BOOLEAN(),
nullable=True)
batch_op.alter_column('final_adduct',
existing_type=sa.VARCHAR(),
nullable=True)
batch_op.alter_column('inchikey',
existing_type=sa.VARCHAR(),
nullable=True)
batch_op.drop_column('metabolite_name')
batch_op.drop_column('standard_grp')
batch_op.drop_column('person_name')
# ### end Alembic commands ###

17
poetry.lock

@ -278,6 +278,17 @@ category = "dev"
optional = false
python-versions = ">=3.6"
[[package]]
name = "python-dotenv"
version = "1.0.0"
description = "Read key-value pairs from a .env file and set them as environment variables"
category = "main"
optional = false
python-versions = ">=3.8"
[package.extras]
cli = ["click (>=5.0)"]
[[package]]
name = "six"
version = "1.16.0"
@ -473,7 +484,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-co
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "8595ab65ac1a098228335d1c012a7f266cea9014f71af835581a10debdf36230"
content-hash = "29c910c8ad182165233a27e0d14ba7a56f9bc8393e7ab8f081767bfa0a470dc9"
[metadata.files]
alembic = [
@ -663,6 +674,10 @@ pycodestyle = [
{file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"},
{file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"},
]
python-dotenv = [
{file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
]
six = []
sqlalchemy = [
{file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"},

1
pyproject.toml

@ -15,6 +15,7 @@ wtforms-alchemy = "^0.18.0"
flask-wtf = "^1.0.1"
gunicorn = "^20.1.0"
Flask-Migrate = "^4.0.4"
python-dotenv = "^1.0.0"
[tool.poetry.dev-dependencies]
autopep8 = "^2.0.1"

3
templates/admin.html

@ -53,8 +53,9 @@ session.post(baseurl + "/admin/login", {"username": (username), "password": (pas
fields = {
"chemical_db_id": &lt;db id from another database&gt;,
"library": (library, is a string),
"person_name": (name of person who uploaded, string)
# name, formula, and mass are required fields!
"name": (name of the chemical, is a string),
"metabolite_name": (name of the chemical, is a string),
"formula": (molecular formula, is a string),
"mass": (monoisotopic mass, is a float),
"pubchem_cid": &lt;string&gt;,

4
templates/batchadd.html

@ -5,8 +5,8 @@
<a href="https://git.junickim.me/junikimm717/walker-database/raw/master/validate.py"> Source Code with required type definitions </a>
<form method="post" enctype="multipart/form-data">
<label for="csv"> Input file (tab delimited text file) </label>
<input type="file" name="csv">
<label for="input"> Input file (tab delimited text file) </label>
<input type="file" name="input">
<input type="submit" value="Submit">
</form>

4
templates/batchquery.html

@ -5,8 +5,8 @@
<a href="https://git.junickim.me/junikimm717/walker-database/raw/master/validate.py"> Source Code with required type definitions </a>
<form method="post" enctype="multipart/form-data">
<label for="csv">CSV: </label>
<input type="file" name="csv">
<label for="input">Input (tab-delimited text file): </label>
<input type="file" name="input">
<input type="submit" value="Submit">
</form>

9
validate.py

@ -6,8 +6,9 @@ Required fields when inserting into the database.
_required_fields = [
# the "str" type means that this field can be any valid string.
("name", "str"),
("metabolite_name", "str"),
("formula", "str"),
("person_name", "str"),
# any field labeled a "float" needs to have a value in decimal notation.
("mass", "float"),
@ -15,7 +16,9 @@ _required_fields = [
("final_rt", "float"),
("final_adduct", "str"),
("standard_grp", "str"),
("uploaded_by", "str"),
("person_name", "str"),
("msms_detected", "yesno"), # Value can either be "Yes" or "No"
("inchikey", "str"),
]
@ -30,13 +33,11 @@ _optional_fields = [
("pubchem_cid", "int"), # Only integers are permitted.
("pubmed_refcount", "int"),
("standard_class", "str"),
("inchikey", "str"),
("inchikey14", "str"),
("adduct", "str"),
("detected_adducts", "str"),
("adduct_calc_mz", "str"),
("msms_detected", "yesno"), # Value can either be "Yes" or "No"
("msms_purity", "float"),
]

Loading…
Cancel
Save