Skip to content

Commit

Permalink
Bump flask-sqlalchemy from 2.5.1 to 3.0.2 (#19)
Browse files Browse the repository at this point in the history
* Allow reformatting code with tox -e black-format

* Bump flask-sqlalchemy from 2.5.1 to 3.0.2

Uses create_app() to initialize Flask application instead of
initializing it by importing a module.

Untested and broken JSONP support is dropped.
  • Loading branch information
hluk committed Dec 2, 2022
1 parent 83c5696 commit 0c14d2b
Show file tree
Hide file tree
Showing 27 changed files with 374 additions and 818 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ htmlcov/
test_env
.pytest_cache
.tox
*.sqlite
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ And run as usual.

## Running test suite

After making changes run `tox -e black-format` to reformat the code.

You can run the test suite with the following command::

$ tox
Expand Down
4 changes: 2 additions & 2 deletions conf/resultsdb.wsgi
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
import resultsdb
application = resultsdb.app
from resultsdb import create_app
application = create_app()
745 changes: 137 additions & 608 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ tox = {version = "4.0.0rc1", optional = true}
tox-docker = {version = "4.0.0a2", optional = true}

flask-oidc = "^1.4.0"
Flask-SQLAlchemy = "^2.5.1"
Flask-SQLAlchemy = "^3.0.2"
SQLAlchemy = {version = "^1.4.39"}
psycopg2-binary = {version = "^2.9.3"}
alembic = "^1.8.1"
Expand Down
148 changes: 74 additions & 74 deletions resultsdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@
import os

from resultsdb import proxy
from resultsdb.models import db
from . import config

import flask
from flask import Flask
from flask_sqlalchemy import SQLAlchemy


# the version as used in setup.py
Expand All @@ -40,69 +39,67 @@
basestring = (str, bytes)


# Flask App
app = Flask(__name__)
app.secret_key = "replace-me-with-something-random"
def create_app(config_obj=None):
app = flask.Flask(__name__)
app.secret_key = "replace-me-with-something-random"

# make sure app behaves when behind a proxy
app.wsgi_app = proxy.ReverseProxied(app.wsgi_app)
# make sure app behaves when behind a proxy
app.wsgi_app = proxy.ReverseProxied(app.wsgi_app)

# Monkey patch Flask's "jsonify" to also handle JSONP
original_jsonify = flask.jsonify
# Expose the __version__ variable in templates
app.jinja_env.globals["app_version"] = __version__

# Expose the __version__ variable in templates
app.jinja_env.globals["app_version"] = __version__
# Checks for env variable OPENSHIFT_PROD to trigger OpenShift codepath on init
# The main difference is that settings will be queried from env
# (check config.openshift_config())
# Possible values are:
# "1" - OpenShift production deployment
# "0" - OpenShift testing deployment
openshift = os.getenv("OPENSHIFT_PROD")

# Load default config, then override that with a config file
if not config_obj:
if os.getenv("DEV") == "true":
config_obj = "resultsdb.config.DevelopmentConfig"
elif os.getenv("TEST") == "true" or openshift == "0":
config_obj = "resultsdb.config.TestingConfig"
else:
config_obj = "resultsdb.config.ProductionConfig"

def jsonify_with_jsonp(*args, **kwargs):
response = original_jsonify(*args, **kwargs)
app.config.from_object(config_obj)

callback = flask.request.args.get("callback", None)
if openshift:
config.openshift_config(app.config, openshift)

if callback:
if not isinstance(callback, basestring):
callback = callback[0]
response.mimetype = "application/javascript"
response.set_data("%s(%s);" % (callback, response.get_data()))
default_config_file = app.config.get("DEFAULT_CONFIG_FILE")
config_file = os.environ.get("RESULTSDB_CONFIG", default_config_file)
if config_file and os.path.exists(config_file):
app.config.from_pyfile(config_file)

return response
if app.config["PRODUCTION"]:
if app.secret_key == "replace-me-with-something-random":
raise Warning("You need to change the app.secret_key value for production")

setup_logging(app)

flask.jsonify = jsonify_with_jsonp
app.logger.info("Using configuration object: %s", config_obj)
if openshift:
app.logger.info("Using OpenShift configuration")
app.logger.info("Using configuration file: %s", config_file)

# Checks for env variable OPENSHIFT_PROD to trigger OpenShift codepath on init
# The main difference is that settings will be queried from env (check config.openshift_config())
# Possible values are:
# "1" - OpenShift production deployment
# "0" - OpenShift testing deployment
openshift = os.getenv("OPENSHIFT_PROD")
if app.config["SHOW_DB_URI"]:
app.logger.debug("Using DBURI: %s", app.config["SQLALCHEMY_DATABASE_URI"])

# Load default config, then override that with a config file
if os.getenv("DEV") == "true":
default_config_obj = "resultsdb.config.DevelopmentConfig"
default_config_file = os.getcwd() + "/conf/settings.py"
elif os.getenv("TEST") == "true" or openshift == "0":
default_config_obj = "resultsdb.config.TestingConfig"
default_config_file = ""
else:
default_config_obj = "resultsdb.config.ProductionConfig"
default_config_file = "/etc/resultsdb/settings.py"
db.init_app(app)

app.config.from_object(default_config_obj)
register_handlers(app)
register_blueprints(app)

if openshift:
config.openshift_config(app.config, openshift)
app.logger.debug("Finished ResultsDB initialization")
return app

config_file = os.environ.get("RESULTSDB_CONFIG", default_config_file)
if os.path.exists(config_file):
app.config.from_pyfile(config_file)

if app.config["PRODUCTION"]:
if app.secret_key == "replace-me-with-something-random":
raise Warning("You need to change the app.secret_key value for production")


def setup_logging():
def setup_logging(app):
# Use LOGGING if defined instead of the old options
log_config = app.config.get("LOGGING")
if log_config:
Expand Down Expand Up @@ -152,39 +149,42 @@ def setup_logging():
app.logger.addHandler(file_handler)


setup_logging()

if app.config["SHOW_DB_URI"]:
app.logger.debug("using DBURI: %s" % app.config["SQLALCHEMY_DATABASE_URI"])
def register_handlers(app):
# TODO: find out why error handler works for 404 but not for 400
@app.errorhandler(400)
def bad_request(error):
return flask.jsonify({"message": "Bad request"}), 400

db = SQLAlchemy(app)
@app.errorhandler(404)
def not_found(error):
return flask.jsonify({"message": "Not found"}), 404

from resultsdb.controllers.main import main # noqa: E402

app.register_blueprint(main)
def register_blueprints(app):
from resultsdb.controllers.main import main # noqa: E402

from resultsdb.controllers.api_v2 import api as api_v2 # noqa: E402
app.register_blueprint(main)

app.register_blueprint(api_v2, url_prefix="/api/v2.0")
from resultsdb.controllers.api_v2 import api as api_v2 # noqa: E402

from resultsdb.controllers.api_v3 import api as api_v3, oidc # noqa: E402
app.register_blueprint(api_v2, url_prefix="/api/v2.0")

app.register_blueprint(api_v3, url_prefix="/api/v3")
from resultsdb.controllers.api_v3 import api as api_v3, oidc # noqa: E402

if app.config["AUTH_MODULE"] == "oidc":
app.register_blueprint(api_v3, url_prefix="/api/v3")

@app.route("/auth/oidclogin")
@oidc.require_login
def login():
return {
"username": oidc.user_getfield(app.config["OIDC_USERNAME_FIELD"]),
"token": oidc.get_access_token(),
}
if app.config["AUTH_MODULE"] == "oidc":

oidc.init_app(app)
app.oidc = oidc
app.logger.info("OpenIDConnect authentication is enabled")
else:
app.logger.info("OpenIDConnect authentication is disabled")
@app.route("/auth/oidclogin")
@oidc.require_login
def login():
return {
"username": oidc.user_getfield(app.config["OIDC_USERNAME_FIELD"]),
"token": oidc.get_access_token(),
}

app.logger.debug("Finished ResultsDB initialization")
oidc.init_app(app)
app.oidc = oidc
app.logger.info("OpenIDConnect authentication is enabled")
else:
app.logger.info("OpenIDConnect authentication is disabled")
7 changes: 3 additions & 4 deletions resultsdb/alembic/env.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import with_statement
from alembic import context
from flask import current_app as app
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig

from resultsdb import db

# add '.' to the pythonpath to support migration inside development env
import sys
Expand All @@ -18,7 +19,6 @@

# add your model's MetaData object here
# for 'autogenerate' support
from resultsdb import db

target_metadata = db.metadata
# target_metadata = None
Expand Down Expand Up @@ -57,7 +57,6 @@ def run_migrations_online():
"""

alembic_config = config.get_section(config.config_ini_section)
from resultsdb import app

alembic_config["sqlalchemy.url"] = app.config["SQLALCHEMY_DATABASE_URI"]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
db.relationship = relationship
db.relation = relation

RESULT_OUTCOME = ("PASSED", "INFO", "FAILED", "NEEDS_INSPECTION")
JOB_STATUS = []


class GroupsToResults(Base):
__tablename__ = "groups_to_results"
Expand Down
9 changes: 2 additions & 7 deletions resultsdb/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,8 @@ def match_testcase_permissions(testcase, permissions):
testcase_match = any(
fnmatch(testcase, testcase_pattern) for testcase_pattern in permission["testcases"]
)
elif "_testcase_regex_pattern" in permission:
testcase_match = re.search(permission["_testcase_regex_pattern"], testcase)
else:
continue

if testcase_match:
yield permission
if testcase_match:
yield permission


def verify_authorization(user, testcase, permissions, ldap_host, ldap_searches):
Expand Down
17 changes: 16 additions & 1 deletion resultsdb/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,29 @@
# Josef Skladanka <jskladan@redhat.com>

import sys
from functools import wraps
from optparse import OptionParser

from alembic.config import Config
from alembic import command as al_command
from alembic.migration import MigrationContext
from flask import current_app as app

from resultsdb import db
from resultsdb import create_app, db
from resultsdb.models.results import Group, Testcase, Result, ResultData

from sqlalchemy.engine import reflection


def with_app_context(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
with app.app_context():
return fn(*args, **kwargs)

return wrapper


def get_alembic_config():
# the location of the alembic ini file and alembic scripts changes when
# installed via package
Expand All @@ -44,6 +55,7 @@ def upgrade_db(*args):
al_command.upgrade(alembic_cfg, "head")


@with_app_context
def init_alembic(*args):
alembic_cfg = get_alembic_config()

Expand All @@ -60,6 +72,7 @@ def init_alembic(*args):
print("Alembic already initialized")


@with_app_context
def initialize_db(destructive):
alembic_cfg = get_alembic_config()

Expand Down Expand Up @@ -91,6 +104,7 @@ def initialize_db(destructive):
print(" Run 'init_alembic' sub-command first.")


@with_app_context
def mock_data(destructive):
print("Populating tables with mock-data")

Expand Down Expand Up @@ -163,6 +177,7 @@ def main():
if not options.destructive:
print("Proceeding in non-destructive mode. To perform destructive steps use -d option.")

create_app()
command(options.destructive)

sys.exit(0)
Expand Down
14 changes: 14 additions & 0 deletions resultsdb/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
import sys


def db_uri_for_testing():
postgres_port = os.getenv("POSTGRES_5432_TCP", None)
if postgres_port:
return f"postgresql+psycopg2://resultsdb:resultsdb@localhost:{postgres_port}/resultsdb"

return "sqlite:///.test_db.sqlite"


class Config(object):
DEBUG = True
PRODUCTION = False
Expand Down Expand Up @@ -100,6 +108,7 @@ class Config(object):


class ProductionConfig(Config):
DEFAULT_CONFIG_FILE = "/etc/resultsdb/settings.py"
DEBUG = False
PRODUCTION = True
SHOW_DB_URI = False
Expand All @@ -108,13 +117,18 @@ class ProductionConfig(Config):


class DevelopmentConfig(Config):
DEFAULT_CONFIG_FILE = os.getcwd() + "/conf/settings.py"
TRAP_BAD_REQUEST_ERRORS = True
SQLALCHEMY_DATABASE_URI = "sqlite:////var/tmp/resultsdb_db.sqlite"
OIDC_CLIENT_SECRETS = os.getcwd() + "/conf/oauth2_client_secrets.json.example"


class TestingConfig(DevelopmentConfig):
DEFAULT_CONFIG_FILE = None
TRAP_BAD_REQUEST_ERRORS = True

SQLALCHEMY_DATABASE_URI = db_uri_for_testing()

FEDMENU_URL = "https://apps.stg.fedoraproject.org/fedmenu"
FEDMENU_DATA_URL = "https://apps.stg.fedoraproject.org/js/data.js"
ADDITIONAL_RESULT_OUTCOMES = ("AMAZING",)
Expand Down
Loading

0 comments on commit 0c14d2b

Please sign in to comment.