From 490b0bf8cc5891a23c8850185d21987b5476ba4f Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Thu, 22 Jun 2023 12:11:36 +0300 Subject: Store all configs in the app object --- wqflask/base/webqtlConfig.py | 72 +++++++------- wqflask/utility/tools.py | 232 ++++++++++++++++++++++--------------------- wqflask/wqflask/__init__.py | 4 + 3 files changed, 157 insertions(+), 151 deletions(-) diff --git a/wqflask/base/webqtlConfig.py b/wqflask/base/webqtlConfig.py index a7dbed3d..b7e278ae 100644 --- a/wqflask/base/webqtlConfig.py +++ b/wqflask/base/webqtlConfig.py @@ -8,7 +8,8 @@ # ######################################### import os -from utility.tools import valid_path, mk_dir, assert_dir, assert_writable_dir, flat_files, TEMPDIR +from flask import Flask +from utility.tools import valid_path, mk_dir, assert_dir, get_setting, assert_writable_dir, flat_files # Debug Level # 1 for debug, mod python will reload import each time @@ -69,39 +70,36 @@ PHENOGEN_URL = "https://phenogen.org/gene.jsp?speciesCB=Rn&auto=Y&geneTxt=%s&gen RRID_MOUSE_URL = "https://www.jax.org/strain/%s" RRID_RAT_URL = "https://rgd.mcw.edu/rgdweb/report/strain/main.html?id=%s" -# Temporary storage (note that this TMPDIR can be set as an -# environment variable - use utility.tools.TEMPDIR when you -# want to reach this base dir -assert_writable_dir(TEMPDIR) - -TMPDIR = mk_dir(TEMPDIR + '/gn2/') -assert_writable_dir(TMPDIR) - -CACHEDIR = mk_dir(TMPDIR + '/cache/') -# We can no longer write into the git tree: -GENERATED_IMAGE_DIR = mk_dir(TMPDIR + 'generated/') -GENERATED_TEXT_DIR = mk_dir(TMPDIR + 'generated_text/') - -# Make sure we have permissions to access these -assert_writable_dir(CACHEDIR) -assert_writable_dir(GENERATED_IMAGE_DIR) -assert_writable_dir(GENERATED_TEXT_DIR) - -# Flat file directories -GENODIR = flat_files('genotype') + '/' -assert_dir(GENODIR) -# assert_dir(GENODIR+'bimbam') # for gemma - -# JSON genotypes are OBSOLETE -JSON_GENODIR = flat_files('genotype/json') + '/' -if not valid_path(JSON_GENODIR): - # fall back on old location (move the dir, FIXME) - JSON_GENODIR = flat_files('json') - - -TEXTDIR = os.path.join(os.environ.get( - "GNSHARE", "/gnshare/gn/"), "web/ProbeSetFreeze_DataMatrix") -# Are we using the following...? -PORTADDR = "http://50.16.251.170" -INFOPAGEHREF = '/dbdoc/%s.html' -CGIDIR = '/webqtl/' # XZ: The variable name 'CGIDIR' should be changed to 'PYTHONDIR' +def update_settings(app: Flask) -> Flask: + # Temporary storage (note that this TMPDIR can be set as an + # environment variable - use utility.tools.TEMPDIR when you + # want to reach this base dir + TEMPDIR = assert_writable_dir(get_setting(app, "TEMPDIR")) + + TMPDIR = assert_writable_dir(mk_dir(TEMPDIR + '/gn2/')) + app.config["TMPDIR"] = TMPDIR + + app.config["CACHEDIR"] = assert_writable_dir(mk_dir(TMPDIR + '/cache/')) + # We can no longer write into the git tree: + app.config["GENERATED_IMAGE_DIR"] = assert_writable_dir(mk_dir(TMPDIR + 'generated/')) + app.config["GENERATED_TEXT_DIR"] = assert_writable_dir(mk_dir(TMPDIR + 'generated_text/')) + + # Flat file directories + app.config["GENODIR"] = assert_dir(flat_files(app, 'genotype') + '/') + # assert_dir(GENODIR+'bimbam') # for gemma + + # JSON genotypes are OBSOLETE + JSON_GENODIR = flat_files(app, 'genotype/json') + '/' + app.config["JSON_GENODIR"] = JSON_GENODIR + if not valid_path(JSON_GENODIR): + # fall back on old location (move the dir, FIXME) + app.config["JSON_GENODIR"] = flat_files(app, 'json') + + + app.config["TEXTDIR"] = os.path.join(os.environ.get( + "GNSHARE", "/gnshare/gn/"), "web/ProbeSetFreeze_DataMatrix") + # Are we using the following...? + app.config["PORTADDR"] = "http://50.16.251.170" + app.config["INFOPAGEHREF"] = '/dbdoc/%s.html' + app.config["CGIDIR"] = '/webqtl/' # XZ: The variable name 'CGIDIR' should be changed to 'PYTHONDIR' + return app diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 00b8368c..2969f31c 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -4,21 +4,22 @@ import os import sys import json +from typing import Any, Optional -from wqflask import app +from flask import Flask # Use the standard logger here to avoid a circular dependency import logging logger = logging.getLogger(__name__) -def app_set(command_id, value): +def app_set(app: Flask, command_id: str, value: Any) -> Any: """Set application wide value""" app.config.setdefault(command_id, value) return value -def get_setting(command_id, guess=None): +def get_setting(app: Flask, command_id: str, guess: Optional[Any] = None) -> Any: """Resolve a setting from the environment or the global settings in app.config, with valid_path is a function checking whether the path points to an expected directory and returns the full path to @@ -45,7 +46,7 @@ def get_setting(command_id, guess=None): def value(command): if command: # sys.stderr.write("Found "+command+"\n") - app_set(command_id, command) + app_set(app, command_id, command) return command else: return app.config.get(command_id) @@ -66,15 +67,15 @@ def get_setting(command_id, guess=None): return command -def get_setting_bool(id): - v = get_setting(id) +def get_setting_bool(app, id): + v = get_setting(app, id) if v not in [0, False, 'False', 'FALSE', None]: return True return False -def get_setting_int(id): - v = get_setting(id) +def get_setting_int(app, id): + v = get_setting(app, id) if isinstance(v, str): return int(v) if v is None: @@ -100,43 +101,43 @@ def valid_path(dir): return None -def js_path(module=None): +def js_path(app, module=None): """ Find the JS module in the two paths """ - try_gn = get_setting("JS_GN_PATH") + "/" + module + try_gn = get_setting(app, "JS_GN_PATH") + "/" + module if valid_path(try_gn): return try_gn - try_guix = get_setting("JS_GUIX_PATH") + "/" + module + try_guix = get_setting(app, "JS_GUIX_PATH") + "/" + module if valid_path(try_guix): return try_guix raise "No JS path found for " + module + \ " (if not in Guix check JS_GN_PATH)" -def reaper_command(guess=None): - return get_setting("REAPER_COMMAND", guess) +def reaper_command(app, guess=None): + return get_setting(app, "REAPER_COMMAND", guess) -def gemma_command(guess=None): - return assert_bin(get_setting("GEMMA_COMMAND", guess)) +def gemma_command(app, guess=None): + return assert_bin(get_setting(app, "GEMMA_COMMAND", guess)) -def gemma_wrapper_command(guess=None): - return assert_bin(get_setting("GEMMA_WRAPPER_COMMAND", guess)) +def gemma_wrapper_command(app, guess=None): + return assert_bin(get_setting(app, "GEMMA_WRAPPER_COMMAND", guess)) -def plink_command(guess=None): - return assert_bin(get_setting("PLINK_COMMAND", guess)) +def plink_command(app, guess=None): + return assert_bin(get_setting(app, "PLINK_COMMAND", guess)) -def flat_file_exists(subdir): - base = get_setting("GENENETWORK_FILES") +def flat_file_exists(app, subdir): + base = get_setting(app, "GENENETWORK_FILES") return valid_path(base + "/" + subdir) -def flat_files(subdir=None): - base = get_setting("GENENETWORK_FILES") +def flat_files(app, subdir=None): + base = get_setting(app, "GENENETWORK_FILES") if subdir: return assert_dir(base + "/" + subdir) return assert_dir(base) @@ -178,13 +179,13 @@ def mk_dir(dir): return assert_dir(dir) -def locate(name, subdir=None): +def locate(app: Flask, name: str, subdir=None) -> str: """ Locate a static flat file in the GENENETWORK_FILES environment. This function throws an error when the file is not found. """ - base = get_setting("GENENETWORK_FILES") + base = get_setting(app, "GENENETWORK_FILES") if subdir: base = base + "/" + subdir if valid_path(base): @@ -198,18 +199,18 @@ def locate(name, subdir=None): raise Exception("Can not locate " + name + " in " + base) -def locate_phewas(name, subdir=None): - return locate(name, '/phewas/' + subdir) +def locate_phewas(app: Flask, name, subdir=None): + return locate(app, name, '/phewas/' + subdir) -def locate_ignore_error(name, subdir=None): +def locate_ignore_error(app: Flask, name, subdir=None): """ Locate a static flat file in the GENENETWORK_FILES environment. This function does not throw an error when the file is not found but returns None. """ - base = get_setting("GENENETWORK_FILES") + base = get_setting(app, "GENENETWORK_FILES") if subdir: base = base + "/" + subdir if valid_path(base): @@ -219,11 +220,11 @@ def locate_ignore_error(name, subdir=None): return None -def tempdir(): +def tempdir(app: Flask) -> str: """ Get UNIX TMPDIR by default """ - return valid_path(get_setting("TMPDIR", "/tmp")) + return valid_path(get_setting(app, "TMPDIR", "/tmp")) BLUE = '\033[94m' @@ -232,15 +233,14 @@ BOLD = '\033[1m' ENDC = '\033[0m' -def show_settings(): - from utility.tools import LOG_LEVEL +def show_settings(app: Flask) -> None: + LOG_LEVEL = get_setting(app, "LOG_LEVEL") print(("Set global log level to " + BLUE + LOG_LEVEL + ENDC), file=sys.stderr) log_level = getattr(logging, LOG_LEVEL.upper()) logging.basicConfig(level=log_level) - logger.info(OVERRIDES) logger.info(BLUE + "Mr. Mojo Risin 2" + ENDC) keylist = list(app.config.keys()) print("runserver.py: ****** Webserver configuration - k,v pairs from app.config ******", @@ -248,89 +248,93 @@ def show_settings(): keylist.sort() for k in keylist: try: - print(("%s: %s%s%s%s" % (k, BLUE, BOLD, get_setting(k), ENDC)), + print(("%s: %s%s%s%s" % (k, BLUE, BOLD, get_setting(app, k), ENDC)), file=sys.stderr) except: print(("%s: %s%s%s%s" % (k, GREEN, BOLD, app.config[k], ENDC)), file=sys.stderr) -# Cached values -GN_VERSION = get_setting('GN_VERSION') -HOME = get_setting('HOME') -SERVER_PORT = get_setting('SERVER_PORT') -WEBSERVER_MODE = get_setting('WEBSERVER_MODE') -GN2_BASE_URL = get_setting('GN2_BASE_URL') -GN2_BRANCH_URL = get_setting('GN2_BRANCH_URL') -GN_SERVER_URL = get_setting('GN_SERVER_URL') -GN_PROXY_URL = get_setting('GN_PROXY_URL') -GN3_LOCAL_URL = get_setting('GN3_LOCAL_URL') -SERVER_PORT = get_setting_int('SERVER_PORT') -SQL_URI = get_setting('SQL_URI') -LOG_LEVEL = get_setting('LOG_LEVEL') -LOG_LEVEL_DEBUG = get_setting_int('LOG_LEVEL_DEBUG') -LOG_SQL = get_setting_bool('LOG_SQL') -LOG_SQL_ALCHEMY = get_setting_bool('LOG_SQL_ALCHEMY') -LOG_BENCH = get_setting_bool('LOG_BENCH') -LOG_FORMAT = "%(message)s" # not yet in use -USE_REDIS = get_setting_bool('USE_REDIS') -REDIS_URL = get_setting('REDIS_URL') -USE_GN_SERVER = get_setting_bool('USE_GN_SERVER') - -GENENETWORK_FILES = get_setting('GENENETWORK_FILES') -JS_GUIX_PATH = get_setting('JS_GUIX_PATH') -assert_dir(JS_GUIX_PATH) -JS_GN_PATH = get_setting('JS_GN_PATH') -# assert_dir(JS_GN_PATH) - -GITHUB_CLIENT_ID = get_setting('GITHUB_CLIENT_ID') -GITHUB_CLIENT_SECRET = get_setting('GITHUB_CLIENT_SECRET') -GITHUB_AUTH_URL = "" -if GITHUB_CLIENT_ID != 'UNKNOWN' and GITHUB_CLIENT_SECRET: - GITHUB_AUTH_URL = "https://github.com/login/oauth/authorize?client_id=" + \ - GITHUB_CLIENT_ID + "&client_secret=" + GITHUB_CLIENT_SECRET - GITHUB_API_URL = get_setting('GITHUB_API_URL') - -ORCID_CLIENT_ID = get_setting('ORCID_CLIENT_ID') -ORCID_CLIENT_SECRET = get_setting('ORCID_CLIENT_SECRET') -ORCID_AUTH_URL = None -if ORCID_CLIENT_ID != 'UNKNOWN' and ORCID_CLIENT_SECRET: - ORCID_AUTH_URL = "https://orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=" + \ - ORCID_CLIENT_ID + "&client_secret=" + ORCID_CLIENT_SECRET + \ - "&redirect_uri=" + GN2_BRANCH_URL + "n/login/orcid_oauth2" - ORCID_TOKEN_URL = get_setting('ORCID_TOKEN_URL') - - -SMTP_CONNECT = get_setting('SMTP_CONNECT') -SMTP_USERNAME = get_setting('SMTP_USERNAME') -SMTP_PASSWORD = get_setting('SMTP_PASSWORD') - -REAPER_COMMAND = app_set("REAPER_COMMAND", reaper_command()) -GEMMA_COMMAND = app_set("GEMMA_COMMAND", gemma_command()) -assert(GEMMA_COMMAND is not None) -PLINK_COMMAND = app_set("PLINK_COMMAND", plink_command()) -GEMMA_WRAPPER_COMMAND = gemma_wrapper_command() -TEMPDIR = tempdir() # defaults to UNIX TMPDIR -assert_dir(TEMPDIR) - -# ---- Handle specific JS modules -JS_GUIX_PATH = get_setting("JS_GUIX_PATH") -assert_dir(JS_GUIX_PATH) -assert_dir(JS_GUIX_PATH + '/cytoscape-panzoom') - -CSS_PATH = JS_GUIX_PATH # The CSS is bundled together with the JS -# assert_dir(JS_PATH) - -JS_TWITTER_POST_FETCHER_PATH = get_setting( - "JS_TWITTER_POST_FETCHER_PATH", js_path("javascript-twitter-post-fetcher")) -assert_dir(JS_TWITTER_POST_FETCHER_PATH) -assert_file(JS_TWITTER_POST_FETCHER_PATH + "/js/twitterFetcher_min.js") - -JS_CYTOSCAPE_PATH = get_setting("JS_CYTOSCAPE_PATH", js_path("cytoscape")) -assert_dir(JS_CYTOSCAPE_PATH) -assert_file(JS_CYTOSCAPE_PATH + '/cytoscape.min.js') - -# assert_file(PHEWAS_FILES+"/auwerx/PheWAS_pval_EMMA_norm.RData") - -OAUTH2_CLIENT_ID = get_setting('OAUTH2_CLIENT_ID') -OAUTH2_CLIENT_SECRET = get_setting('OAUTH2_CLIENT_SECRET') +def set_mandatory_settings(app: Flask) -> Flask: + """Set the mandatory settings then return the `app` object.""" + # Cached values + app.config["GN_VERSION"] = get_setting(app, 'GN_VERSION') + app.config["HOME"] = get_setting(app, 'HOME') + app.config["SERVER_PORT"] = get_setting(app, 'SERVER_PORT') + app.config["WEBSERVER_MODE"] = get_setting(app, 'WEBSERVER_MODE') + app.config["GN2_BASE_URL"] = get_setting(app, 'GN2_BASE_URL') + app.config["GN2_BRANCH_URL"] = get_setting(app, 'GN2_BRANCH_URL') + app.config["GN_SERVER_URL"] = get_setting(app, 'GN_SERVER_URL') + app.config["GN_PROXY_URL"] = get_setting(app, 'GN_PROXY_URL') + app.config["GN3_LOCAL_URL"] = get_setting(app, 'GN3_LOCAL_URL') + app.config["SERVER_PORT"] = get_setting_int(app, 'SERVER_PORT') + app.config["SQL_URI"] = get_setting(app, 'SQL_URI') + app.config["LOG_LEVEL"] = get_setting(app, 'LOG_LEVEL') + app.config["LOG_LEVEL_DEBUG"] = get_setting_int(app, 'LOG_LEVEL_DEBUG') + app.config["LOG_SQL"] = get_setting_bool(app, 'LOG_SQL') + app.config["LOG_SQL_ALCHEMY"] = get_setting_bool(app, 'LOG_SQL_ALCHEMY') + app.config["LOG_BENCH"] = get_setting_bool(app, 'LOG_BENCH') + app.config["LOG_FORMAT"] = "%(message)s" # not yet in use + app.config["USE_REDIS"] = get_setting_bool(app, 'USE_REDIS') + app.config["REDIS_URL"] = get_setting(app, 'REDIS_URL') + app.config["USE_GN_SERVER"] = get_setting_bool(app, 'USE_GN_SERVER') + + app.config["GENENETWORK_FILES"] = get_setting(app, 'GENENETWORK_FILES') + app.config["JS_GUIX_PATH"] = assert_dir(get_setting(app, 'JS_GUIX_PATH')) + app.config["JS_GN_PATH"] = get_setting(app, 'JS_GN_PATH') + # assert_dir(JS_GN_PATH) + + app.config["GITHUB_CLIENT_ID"] = get_setting(app, 'GITHUB_CLIENT_ID') + app.config["GITHUB_CLIENT_SECRET"] = get_setting(app, 'GITHUB_CLIENT_SECRET') + app.config["GITHUB_AUTH_URL"] = "" + if app.config["GITHUB_CLIENT_ID"] != 'UNKNOWN' and app.config["GITHUB_CLIENT_SECRET"]: + app.config["GITHUB_AUTH_URL"] = "https://github.com/login/oauth/authorize?client_id=" + \ + app.config["GITHUB_CLIENT_ID"] + "&client_secret=" + \ + app.config["GITHUB_CLIENT_SECRET"] + app.config["GITHUB_API_URL"] = get_setting(app, 'GITHUB_API_URL') + + app.config["ORCID_CLIENT_ID"] = get_setting(app, 'ORCID_CLIENT_ID') + app.config["ORCID_CLIENT_SECRET"] = get_setting(app, 'ORCID_CLIENT_SECRET') + app.config["ORCID_AUTH_URL"] = None + if app.config["ORCID_CLIENT_ID"] != 'UNKNOWN' and app.config["ORCID_CLIENT_SECRET"]: + app.config["ORCID_AUTH_URL"] = "https://orcid.org/oauth/authorize" + \ + "?response_type=code&scope=/authenticate&show_login=true" + \ + "&client_id=" + \ + app.config["ORCID_CLIENT_ID"] + "&client_secret=" + \ + app.config["ORCID_CLIENT_SECRET"] + "&redirect_uri=" + \ + app.config["GN2_BRANCH_URL"] + "n/login/orcid_oauth2" + app.config["ORCID_TOKEN_URL"] = get_setting(app, 'ORCID_TOKEN_URL') + + + app.config["SMTP_CONNECT"] = get_setting(app, 'SMTP_CONNECT') + app.config["SMTP_USERNAME"] = get_setting(app, 'SMTP_USERNAME') + app.config["SMTP_PASSWORD"] = get_setting(app, 'SMTP_PASSWORD') + + app.config["REAPER_COMMAND"] = app_set(app, "REAPER_COMMAND", reaper_command(app)) + app.config["GEMMA_COMMAND"] = app_set(app, "GEMMA_COMMAND", gemma_command(app)) + assert(app.config["GEMMA_COMMAND"] is not None) + app.config["PLINK_COMMAND"] = app_set(app, "PLINK_COMMAND", plink_command(app)) + app.config["GEMMA_WRAPPER_COMMAND"] = gemma_wrapper_command(app) + app.config["TEMPDIR"] = assert_dir(tempdir(app)) # defaults to UNIX TMPDIR + + # ---- Handle specific JS modules + app.config["JS_GUIX_PATH"] = assert_dir(get_setting(app, "JS_GUIX_PATH")) + assert_dir(app.config["JS_GUIX_PATH"] + '/cytoscape-panzoom') + + app.config["CSS_PATH"] = app.config["JS_GUIX_PATH"] # The CSS is bundled together with the JS + # assert_dir(JS_PATH) + + app.config["JS_TWITTER_POST_FETCHER_PATH"] = assert_dir(get_setting( + app, + "JS_TWITTER_POST_FETCHER_PATH", + js_path(app, "javascript-twitter-post-fetcher"))) + assert_file(app.config["JS_TWITTER_POST_FETCHER_PATH"] + "/js/twitterFetcher_min.js") + + app.config["JS_CYTOSCAPE_PATH"] = assert_dir(get_setting(app, "JS_CYTOSCAPE_PATH", js_path(app, "cytoscape"))) + assert_file(app.config["JS_CYTOSCAPE_PATH"] + '/cytoscape.min.js') + + # assert_file(PHEWAS_FILES+"/auwerx/PheWAS_pval_EMMA_norm.RData") + + app.config["OAUTH2_CLIENT_ID"] = get_setting(app, 'OAUTH2_CLIENT_ID') + app.config["OAUTH2_CLIENT_SECRET"] = get_setting(app, 'OAUTH2_CLIENT_SECRET') + return app diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py index 140e94ad..5f264a06 100644 --- a/wqflask/wqflask/__init__.py +++ b/wqflask/wqflask/__init__.py @@ -37,6 +37,9 @@ from wqflask.oauth2.request_utils import user_details, authserver_authorise_uri from wqflask.jupyter_notebooks import jupyter_notebooks +from base.webqtlConfig import update_settings +from utility.tools import set_mandatory_settings + app = Flask(__name__) @@ -60,6 +63,7 @@ app.jinja_env.globals.update( num_collections=num_collections) app.config["SESSION_REDIS"] = redis.from_url(app.config["REDIS_URL"]) +app = update_settings(set_mandatory_settings(app)) # Registering blueprints app.register_blueprint(glossary_blueprint, url_prefix="/glossary") -- cgit v1.2.3