Apply factory pattern WIP

pull/78/head
Konstantin Gründger 2019-09-12 22:53:42 +02:00 zatwierdzone przez Meisterschueler
rodzic 34d9c39ab6
commit b13064cf73
20 zmienionych plików z 92 dodań i 104 usunięć

Wyświetl plik

@ -1,12 +1,10 @@
language: python language: python
env:
- OGN_CONFIG_MODULE='config/test.py'
python: python:
- 3.5 - 3.5
- 3.6 - 3.6
- 3.7-dev - 3.7
- 3.8-dev
addons: addons:
postgresql: "9.6" postgresql: "9.6"

Wyświetl plik

@ -7,21 +7,32 @@ from celery import Celery
from app.flask_celery import make_celery from app.flask_celery import make_celery
bootstrap = Bootstrap()
db = SQLAlchemy()
cache = Cache()
def create_app(config_name='development'):
# Initialize Flask # Initialize Flask
app = Flask(__name__) app = Flask(__name__)
# Load the configuration # Load the configuration
if config_name == 'testing':
app.config.from_object('app.config.test')
else:
app.config.from_object('app.config.default') app.config.from_object('app.config.default')
app.config.from_envvar("OGN_CONFIG_MODULE", silent=True) app.config.from_envvar("OGN_CONFIG_MODULE", silent=True)
# Initialize other things # Initialize other things
bootstrap = Bootstrap(app) bootstrap.init_app(app)
db = SQLAlchemy(app) db.init_app(app)
migrate = Migrate(app, db) cache.init_app(app)
cache = Cache(app)
celery = make_celery(app) #migrate = Migrate(app, db)
#celery = make_celery(app)
from app.main import bp as bp_main from app.main import bp as bp_main
app.register_blueprint(bp_main) app.register_blueprint(bp_main)
from app import commands #from app import commands
return app

Wyświetl plik

@ -2,12 +2,11 @@ from sqlalchemy import distinct
from sqlalchemy.sql import null, and_, func, not_, case from sqlalchemy.sql import null, and_, func, not_, case
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from flask import current_app
from app.model import Country, DeviceInfo, DeviceInfoOrigin, AircraftBeacon, ReceiverBeacon, Device, Receiver from app.model import Country, DeviceInfo, DeviceInfoOrigin, AircraftBeacon, ReceiverBeacon, Device, Receiver
from app.utils import get_ddb, get_flarmnet from app.utils import get_ddb, get_flarmnet
from app import app
def upsert(session, model, rows, update_cols): def upsert(session, model, rows, update_cols):
"""Insert rows in model. On conflicting update columns if new value IS NOT NULL.""" """Insert rows in model. On conflicting update columns if new value IS NOT NULL."""
@ -46,7 +45,7 @@ def import_ddb(session, logger=None):
"""Import registered devices from the DDB.""" """Import registered devices from the DDB."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
logger.info("Import registered devices fom the DDB...") logger.info("Import registered devices fom the DDB...")
counter = update_device_infos(session, DeviceInfoOrigin.OGN_DDB) counter = update_device_infos(session, DeviceInfoOrigin.OGN_DDB)
@ -60,7 +59,7 @@ def update_country_code(session, logger=None):
"""Update country code in receivers table if None.""" """Update country code in receivers table if None."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
update_receivers = ( update_receivers = (
session.query(Receiver) session.query(Receiver)

Wyświetl plik

@ -1,18 +1,17 @@
from sqlalchemy import and_, or_, insert, update, exists, between from sqlalchemy import and_, or_, insert, update, exists, between
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from sqlalchemy.sql.expression import true, false from sqlalchemy.sql.expression import true, false
from flask import current_app
from app.model import TakeoffLanding, Logbook, AircraftBeacon from app.model import TakeoffLanding, Logbook, AircraftBeacon
from app.utils import date_to_timestamps from app.utils import date_to_timestamps
from app import app
def update_entries(session, date, logger=None): def update_entries(session, date, logger=None):
"""Add/update logbook entries.""" """Add/update logbook entries."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
logger.info("Compute logbook.") logger.info("Compute logbook.")
@ -167,7 +166,7 @@ def update_max_altitudes(session, date, logger=None):
"""Add max altitudes in logbook when flight is complete (takeoff and landing).""" """Add max altitudes in logbook when flight is complete (takeoff and landing)."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
logger.info("Update logbook max altitude.") logger.info("Update logbook max altitude.")

Wyświetl plik

@ -1,18 +1,17 @@
from sqlalchemy import Date from sqlalchemy import Date
from sqlalchemy import and_, insert, update, exists, between from sqlalchemy import and_, insert, update, exists, between
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from flask import current_app
from app.model import AircraftBeacon, ReceiverCoverage from app.model import AircraftBeacon, ReceiverCoverage
from app.utils import date_to_timestamps from app.utils import date_to_timestamps
from app import app
def update_entries(session, date, logger=None): def update_entries(session, date, logger=None):
"""Create receiver coverage stats for Melissas ognrange.""" """Create receiver coverage stats for Melissas ognrange."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
logger.info("Compute receiver coverages.") logger.info("Compute receiver coverages.")

Wyświetl plik

@ -1,12 +1,11 @@
from flask import current_app
from sqlalchemy import insert, distinct, between, literal from sqlalchemy import insert, distinct, between, literal
from sqlalchemy.sql import null, and_, func, or_, update from sqlalchemy.sql import null, and_, func, or_, update
from sqlalchemy.sql.expression import case from sqlalchemy.sql.expression import case
from app.model import AircraftBeacon, DeviceStats, Country, CountryStats, ReceiverStats, ReceiverBeacon, RelationStats, Receiver, Device from app.model import AircraftBeacon, DeviceStats, Country, CountryStats, ReceiverStats, ReceiverBeacon, RelationStats, Receiver, Device
from app.utils import date_to_timestamps from app.utils import date_to_timestamps
from app import app
# 40dB@10km is enough for 640km # 40dB@10km is enough for 640km
MAX_PLAUSIBLE_QUALITY = 40 MAX_PLAUSIBLE_QUALITY = 40
@ -16,7 +15,7 @@ def create_device_stats(session, date, logger=None):
"""Add/update device stats.""" """Add/update device stats."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
(start, end) = date_to_timestamps(date) (start, end) = date_to_timestamps(date)
@ -83,7 +82,7 @@ def create_receiver_stats(session, date, logger=None):
"""Add/update receiver stats.""" """Add/update receiver stats."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
(start, end) = date_to_timestamps(date) (start, end) = date_to_timestamps(date)
@ -155,7 +154,7 @@ def create_receiver_stats(session, date, logger=None):
def create_country_stats(session, date, logger=None): def create_country_stats(session, date, logger=None):
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
(start, end) = date_to_timestamps(date) (start, end) = date_to_timestamps(date)
@ -181,7 +180,7 @@ def update_device_stats_jumps(session, date, logger=None):
"""Update device stats jumps.""" """Update device stats jumps."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
(start, end) = date_to_timestamps(date) (start, end) = date_to_timestamps(date)
@ -237,7 +236,7 @@ def create_relation_stats(session, date, logger=None):
"""Add/update relation stats.""" """Add/update relation stats."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
(start, end) = date_to_timestamps(date) (start, end) = date_to_timestamps(date)
@ -274,7 +273,7 @@ def update_qualities(session, date, logger=None):
"""Calculate relative qualities of receivers and devices.""" """Calculate relative qualities of receivers and devices."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
# Calculate avg quality of devices # Calculate avg quality of devices
dev_sq = session.query(RelationStats.device_id, func.avg(RelationStats.quality).label("quality")).filter(RelationStats.date == date).group_by(RelationStats.device_id).subquery() dev_sq = session.query(RelationStats.device_id, func.avg(RelationStats.quality).label("quality")).filter(RelationStats.date == date).group_by(RelationStats.device_id).subquery()
@ -339,7 +338,7 @@ def update_receivers(session, logger=None):
"""Update receivers with stats.""" """Update receivers with stats."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
receiver_stats = ( receiver_stats = (
session.query( session.query(
@ -394,7 +393,7 @@ def update_devices(session, logger=None):
"""Update devices with stats.""" """Update devices with stats."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
device_stats = ( device_stats = (
session.query( session.query(

Wyświetl plik

@ -1,19 +1,18 @@
from datetime import timedelta from datetime import timedelta
from flask import current_app
from sqlalchemy import and_, or_, insert, between, exists from sqlalchemy import and_, or_, insert, between, exists
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from sqlalchemy.sql.expression import case from sqlalchemy.sql.expression import case
from app.model import AircraftBeacon, TakeoffLanding, Airport from app.model import AircraftBeacon, TakeoffLanding, Airport
from app import app
def update_entries(session, start, end, logger=None): def update_entries(session, start, end, logger=None):
"""Compute takeoffs and landings.""" """Compute takeoffs and landings."""
if logger is None: if logger is None:
logger = app.logger logger = current_app.logger
logger.info("Compute takeoffs and landings.") logger.info("Compute takeoffs and landings.")

Wyświetl plik

@ -1,5 +1,3 @@
from app import app
from .database import user_cli as database_cli from .database import user_cli as database_cli
from .export import user_cli as export_cli from .export import user_cli as export_cli
from .flights import user_cli as flights_cli from .flights import user_cli as flights_cli
@ -7,6 +5,7 @@ from .gateway import user_cli as gateway_cli
from .logbook import user_cli as logbook_cli from .logbook import user_cli as logbook_cli
from .stats import user_cli as stats_cli from .stats import user_cli as stats_cli
def register(app):
app.cli.add_command(database_cli) app.cli.add_command(database_cli)
app.cli.add_command(export_cli) app.cli.add_command(export_cli)
app.cli.add_command(flights_cli) app.cli.add_command(flights_cli)

Wyświetl plik

@ -1,3 +1,4 @@
from flask import current_app
from flask.cli import AppGroup from flask.cli import AppGroup
import click import click
@ -8,7 +9,6 @@ from app.collect.database import update_device_infos, update_country_code
from app.model import * from app.model import *
from app.utils import get_airports, get_days from app.utils import get_airports, get_days
from app import app
from app import db from app import db
user_cli = AppGroup("database") user_cli = AppGroup("database")
@ -36,8 +36,8 @@ def get_database_days(start, end):
@user_cli.command("info") @user_cli.command("info")
def info(): def info():
print(app.config) print(current_app.config)
print(app.config["SQLALCHEMY_DATABASE_URI"]) print(current_app.config["SQLALCHEMY_DATABASE_URI"])
@user_cli.command("init") @user_cli.command("init")

Wyświetl plik

@ -1,11 +1,10 @@
from flask import current_app
from flask.cli import AppGroup from flask.cli import AppGroup
import click import click
from ogn.client import AprsClient from ogn.client import AprsClient
from app.gateway.bulkimport import ContinuousDbFeeder from app.gateway.bulkimport import ContinuousDbFeeder
from app import app
user_cli = AppGroup("gateway") user_cli = AppGroup("gateway")
user_cli.help = "Connection to APRS servers." user_cli.help = "Connection to APRS servers."
@ -21,14 +20,14 @@ def run(aprs_user="anon-dev"):
print("aprs_user must be a string of 3-9 characters.") print("aprs_user must be a string of 3-9 characters.")
return return
app.logger.warning("Start ogn gateway") current_app.logger.warning("Start ogn gateway")
client = AprsClient(aprs_user) client = AprsClient(aprs_user)
client.connect() client.connect()
try: try:
client.run(callback=saver.add, autoreconnect=True) client.run(callback=saver.add, autoreconnect=True)
except KeyboardInterrupt: except KeyboardInterrupt:
app.logger.warning("\nStop ogn gateway") current_app.logger.warning("\nStop ogn gateway")
saver.flush() saver.flush()
client.disconnect() client.disconnect()

Wyświetl plik

@ -1,6 +1,7 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from io import StringIO from io import StringIO
from flask import current_app
from flask.cli import AppGroup from flask.cli import AppGroup
import click import click
from tqdm import tqdm from tqdm import tqdm
@ -13,7 +14,6 @@ from app.utils import open_file
from app.gateway.process_tools import * from app.gateway.process_tools import *
from app import db from app import db
from app import app
user_cli = AppGroup("bulkimport") user_cli = AppGroup("bulkimport")
user_cli.help = "Tools for accelerated data import." user_cli.help = "Tools for accelerated data import."
@ -91,16 +91,16 @@ def string_to_message(raw_string, reference_date):
try: try:
message = parse(raw_string, reference_date) message = parse(raw_string, reference_date)
except NotImplementedError as e: except NotImplementedError as e:
app.logger.error("No parser implemented for message: {}".format(raw_string)) current_app.logger.error("No parser implemented for message: {}".format(raw_string))
return None return None
except ParseError as e: except ParseError as e:
app.logger.error("Parsing error with message: {}".format(raw_string)) current_app.logger.error("Parsing error with message: {}".format(raw_string))
return None return None
except TypeError as e: except TypeError as e:
app.logger.error("TypeError with message: {}".format(raw_string)) current_app.logger.error("TypeError with message: {}".format(raw_string))
return None return None
except Exception as e: except Exception as e:
app.logger.error("Other Exception with string: {}".format(raw_string)) current_app.logger.error("Other Exception with string: {}".format(raw_string))
return None return None
# update reference receivers and distance to the receiver # update reference receivers and distance to the receiver
@ -160,7 +160,7 @@ class ContinuousDbFeeder:
self.receiver_buffer.write(complete_message) self.receiver_buffer.write(complete_message)
self.receiver_buffer.write("\n") self.receiver_buffer.write("\n")
else: else:
app.logger.error("Ignore beacon_type: {}".format(message["beacon_type"])) current_app.logger.error("Ignore beacon_type: {}".format(message["beacon_type"]))
return return
if datetime.utcnow() - self.last_flush >= timedelta(seconds=20): if datetime.utcnow() - self.last_flush >= timedelta(seconds=20):
@ -243,7 +243,7 @@ class FileDbFeeder:
self.receiver_buffer.write(complete_message) self.receiver_buffer.write(complete_message)
self.receiver_buffer.write("\n") self.receiver_buffer.write("\n")
else: else:
app.logger.error("Ignore beacon_type: {}".format(message["beacon_type"])) current_app.logger.error("Ignore beacon_type: {}".format(message["beacon_type"]))
return return
def prepare(self): def prepare(self):

Wyświetl plik

@ -1,6 +1,5 @@
[program:celerybeat] [program:celerybeat]
environment=OGN_CONFIG_MODULE='config/default.py' command=/home/pi/ogn-python/venv/bin/celery -A app.collect beat -l info
command=/home/pi/venv/bin/celery -A app.collect beat -l info
directory=/home/pi/ogn-python directory=/home/pi/ogn-python
user=pi user=pi

Wyświetl plik

@ -1,5 +1,4 @@
[program:celery] [program:celery]
environment=OGN_CONFIG_MODULE='config/default.py'
command=/home/pi/ogn-python/venv/bin/celery -A app.collect worker -l info command=/home/pi/ogn-python/venv/bin/celery -A app.collect worker -l info
directory=/home/pi/ogn-python directory=/home/pi/ogn-python

Wyświetl plik

@ -1,5 +1,4 @@
[program:flower] [program:flower]
environment=OGN_CONFIG_MODULE='config/default.py'
command=/home/pi/ogn-python/venv/bin/celery flower -A app.celery --port=5555 -l info command=/home/pi/ogn-python/venv/bin/celery flower -A app.celery --port=5555 -l info
directory=/home/pi/ogn-python directory=/home/pi/ogn-python

Wyświetl plik

@ -1,5 +1,4 @@
[program:gunicorn] [program:gunicorn]
environment=OGN_CONFIG_MODULE='config/default.py'
command=/home/pi/ogn-python/venv/bin/gunicorn --bind :5000 ogn_python:app command=/home/pi/ogn-python/venv/bin/gunicorn --bind :5000 ogn_python:app
directory=/home/pi/ogn-python directory=/home/pi/ogn-python

Wyświetl plik

@ -1,7 +1,6 @@
[program:ogn-feeder] [program:ogn-feeder]
environment=OGN_CONFIG_MODULE='config/default.py'
command=/home/pi/ogn-python/venv/bin/python -m flask gateway run command=/home/pi/ogn-python/venv/bin/python -m flask gateway run
directory=/home/pi/ogn_python directory=/home/pi/ogn-python
user=pi user=pi
stderr_logfile=/var/log/supervisor/ogn-feeder.log stderr_logfile=/var/log/supervisor/ogn-feeder.log

Wyświetl plik

@ -1,5 +1,13 @@
from app import app import os
from flask_migrate import Migrate
from app import create_app, db
from app.commands import register
if __name__ == '__main__': app = create_app(os.getenv('FLASK_CONFIG') or 'default')
app.run() migrate = Migrate(app, db)
register(app)
@app.shell_context_processor
def make_shell_context():
return dict(app=app, db=db)

Wyświetl plik

@ -1,36 +1,18 @@
import unittest import unittest
import os from app import create_app, db
os.environ["OGN_CONFIG_MODULE"] = "config/test.py"
from app import db # noqa: E402
class TestBaseDB(unittest.TestCase): class TestBaseDB(unittest.TestCase):
@classmethod def setUp(self):
def setUpClass(cls): self.app = create_app('testing')
db.session.execute("CREATE EXTENSION IF NOT EXISTS postgis;") self.app_context = self.app.app_context()
db.session.commit() self.app_context.push()
db.drop_all()
db.create_all() db.create_all()
def setUp(self):
pass
def tearDown(self): def tearDown(self):
db.session.execute( db.session.remove()
""" db.drop_all()
DELETE FROM aircraft_beacons; self.app_context.pop()
DELETE FROM receiver_beacons;
DELETE FROM takeoff_landings;
DELETE FROM logbook;
DELETE FROM receiver_coverages;
DELETE FROM device_stats;
DELETE FROM receiver_stats;
DELETE FROM receivers;
DELETE FROM devices;
"""
)
if __name__ == "__main__": if __name__ == "__main__":

Wyświetl plik

@ -9,6 +9,8 @@ from app.collect.logbook import update_entries
class TestLogbook(TestBaseDB): class TestLogbook(TestBaseDB):
def setUp(self): def setUp(self):
super().setUp()
# Create basic data and insert # Create basic data and insert
self.dd0815 = Device(address="DD0815") self.dd0815 = Device(address="DD0815")
self.dd4711 = Device(address="DD4711") self.dd4711 = Device(address="DD4711")

Wyświetl plik

@ -1,17 +1,16 @@
import unittest import unittest
import os import os
from tests.base import TestBaseDB, db from flask import current_app
from app.model import DeviceInfo from app.model import DeviceInfo
from app.commands.database import import_file from app.commands.database import import_file
from app import app from tests.base import TestBaseDB, db
class TestDatabase(TestBaseDB): class TestDatabase(TestBaseDB):
def test_import_ddb_file(self): def test_import_ddb_file(self):
runner = app.test_cli_runner() runner = current_app.test_cli_runner()
result = runner.invoke(import_file, [os.path.dirname(__file__) + "/../custom_ddb.txt"]) result = runner.invoke(import_file, [os.path.dirname(__file__) + "/../custom_ddb.txt"])
self.assertEqual(result.exit_code, 0) self.assertEqual(result.exit_code, 0)