Rebase dev onto v2_id branch

This commit is contained in:
Keith Edmunds 2022-02-06 22:58:15 +00:00
parent db86d04b9a
commit a164f4c962
13 changed files with 111 additions and 188 deletions

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (musicmuster) (2)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>

View File

@ -36,15 +36,8 @@ class Config(object):
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
MAX_INFO_TABS = 3
MILLISECOND_SIGFIGS = 0
MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_dev" # noqa E501
MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_v2" # noqa E501
NORMALISE_ON_IMPORT = True
NOTE_COLOURS = {
'track': "#ffff00",
'request': "#7cf000",
'wrap': "#fffacd",
'this month then': "#c256c2",
'story': "#dda0dd",
}
ROOT = os.environ.get('ROOT') or "/home/kae/music"
TESTMODE = True
TIMER_MS = 500

View File

@ -19,7 +19,7 @@ from sqlalchemy import (
)
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.orm import relationship, sessionmaker, scoped_session
from config import Config
from log import DEBUG, ERROR
@ -27,16 +27,26 @@ from log import DEBUG, ERROR
# Create session at the global level as per
# https://docs.sqlalchemy.org/en/13/orm/session_basics.html
# Set up database connection
engine = sqlalchemy.create_engine(f"{Config.MYSQL_CONNECT}?charset=utf8",
encoding='utf-8',
echo=Config.DISPLAY_SQL,
pool_pre_ping=True)
Base = declarative_base()
Base.metadata.create_all(engine)
Session = scoped_session(sessionmaker())
# Create a Session factory
Session = sessionmaker(bind=engine)
def dbinit():
# Set up database connection
global Session
engine = sqlalchemy.create_engine(
f"{Config.MYSQL_CONNECT}?charset=utf8",
encoding='utf-8',
echo=Config.DISPLAY_SQL,
pool_pre_ping=True)
Session.configure(bind=engine)
Base.metadata.create_all(engine)
# Create a Session factory
Session = sessionmaker(bind=engine)
# Database classes
@ -634,16 +644,16 @@ class Tracks(Base):
def search_artists(session, text):
return (
session.query(Tracks)
.filter(Tracks.artist.ilike(f"%{text}%"))
.order_by(Tracks.title)
.filter(Tracks.artist.ilike(f"%{text}%"))
.order_by(Tracks.title)
).all()
@staticmethod
def search_titles(session, text):
return (
session.query(Tracks)
.filter(Tracks.title.ilike(f"%{text}%"))
.order_by(Tracks.title)
.filter(Tracks.title.ilike(f"%{text}%"))
.order_by(Tracks.title)
).all()
@staticmethod

View File

@ -27,8 +27,8 @@ import helpers
import music
from config import Config
from model import (Notes, Playdates, Playlists, PlaylistTracks,
Session, Settings, Tracks)
from models import (dbinit, Notes, Playdates, Playlists, PlaylistTracks,
Session, Settings, Tracks)
from playlists import PlaylistTab
from songdb import create_track_from_file
from ui.dlg_search_database_ui import Ui_Dialog
@ -226,12 +226,14 @@ class Window(QMainWindow, Ui_MainWindow):
def close_tab(self, index):
if hasattr(self.tabPlaylist.widget(index), 'is_playlist'):
if self.tabPlaylist.widget(index) == self.current_track_playlist_tab:
self.statusbar.showMessage("Can't close current track playlist",
5000)
if self.tabPlaylist.widget(index) == (
self.current_track_playlist_tab):
self.statusbar.showMessage(
"Can't close current track playlist", 5000)
return
if self.tabPlaylist.widget(index) == self.next_track_playlist_tab:
self.statusbar.showMessage("Can't close next track playlist", 5000)
self.statusbar.showMessage(
"Can't close next track playlist", 5000)
return
# It's OK to close this playlist so remove from open playlist list
with Session() as session:
@ -950,6 +952,7 @@ class SelectPlaylistDialog(QDialog):
def main():
try:
app = QApplication(sys.argv)
dbinit()
win = Window()
win.show()
sys.exit(app.exec())

View File

@ -19,7 +19,7 @@ from config import Config
from datetime import datetime, timedelta
from helpers import get_relative_date, open_in_audacity
from log import DEBUG, ERROR
from model import (
from models import (
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks, NoteColours
)
from songdb import create_track_from_file, update_meta

View File

@ -8,7 +8,7 @@ import tempfile
from config import Config
from helpers import show_warning
from log import DEBUG, INFO
from model import Notes, Playdates, PlaylistTracks, Session, Tracks
from models import Notes, Playdates, PlaylistTracks, Session, Tracks
from mutagen.flac import FLAC
from mutagen.mp3 import MP3
from pydub import AudioSegment, effects

View File

@ -1,83 +1,56 @@
# https://stewartadam.io/blog/2019/04/04/testing-flask-applications-code-database-views-flask-config-and-app-context-pytest
# https://itnext.io/setting-up-transactional-tests-with-pytest-and-sqlalchemy-b2d726347629
import pytest
import sys
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
sys.path.append("app")
from config import Config # noqa E402
from flask import g # noqa E402
from kpi import create_app # noqa E402
from kpi import db as _db # noqa E402
from app.models import Base # noqa E402
class TestConfig(Config):
# TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite://'
PYTESTING = True
@pytest.fixture(scope="session")
def connection():
engine = create_engine(
"mysql+mysqldb://musicmuster_testing:musicmuster_testing@"
"localhost/musicmuster_testing"
)
return engine.connect()
# @pytest.fixture(scope="module")
# def app():
# app = create_app(TestConfig)
# app_context = app.app_context()
# app_context.push()
# db.create_all()
# return app
def seed_database():
pass
# users = [
# {
# "id": 1,
# "name": "John Doe",
# },
# # ...
# ]
# for user in users:
# db_user = User(**user)
# db_session.add(db_user)
# db_session.commit()
@pytest.fixture(scope="session")
def setup_database(connection):
Base.metadata.bind = connection
Base.metadata.create_all()
# seed_database()
yield
models.Base.metadata.drop_all()
@pytest.fixture
def no_bank_holidays():
"Set no bank holidays"
g.BankHolidays = []
@pytest.fixture(scope="session")
def app(request):
"""Test session-wide test `Flask` application."""
app = create_app(TestConfig)
return app
@pytest.fixture(autouse=True)
def _setup_app_context_for_test(request, app):
"""
Given app is session-wide, sets up a app context per test to ensure that
app and request stack is not shared between tests.
"""
ctx = app.app_context()
ctx.push()
yield # tests will run here
ctx.pop()
@pytest.fixture(scope="session")
def db(app, request):
"""Returns session-wide initialized database"""
with app.app_context():
_db.create_all()
yield _db
_db.drop_all()
@pytest.fixture(scope="function")
def session(app, db, request):
"""Creates a new database session for each test,
rolling back changes afterwards"""
connection = _db.engine.connect()
def db_session(setup_database, connection):
transaction = connection.begin()
options = dict(bind=connection, binds={})
session = _db.create_scoped_session(options=options)
_db.session = session
yield session
yield scoped_session(
sessionmaker(autocommit=False, autoflush=False, bind=connection)
)
transaction.rollback()
connection.close()
session.remove()

View File

@ -1,83 +0,0 @@
# https://stewartadam.io/blog/2019/04/04/testing-flask-applications-code-database-views-flask-config-and-app-context-pytest
import pytest
import sys
sys.path.append("app")
from config import Config # noqa E402
from flask import g # noqa E402
from kpi import create_app # noqa E402
from kpi import db as _db # noqa E402
class TestConfig(Config):
# TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite://'
PYTESTING = True
# @pytest.fixture(scope="module")
# def app():
# app = create_app(TestConfig)
# app_context = app.app_context()
# app_context.push()
# db.create_all()
# return app
@pytest.fixture
def no_bank_holidays():
"Set no bank holidays"
g.BankHolidays = []
@pytest.fixture(scope="session")
def app(request):
"""Test session-wide test `Flask` application."""
app = create_app(TestConfig)
return app
@pytest.fixture(autouse=True)
def _setup_app_context_for_test(request, app):
"""
Given app is session-wide, sets up a app context per test to ensure that
app and request stack is not shared between tests.
"""
ctx = app.app_context()
ctx.push()
yield # tests will run here
ctx.pop()
@pytest.fixture(scope="session")
def db(app, request):
"""Returns session-wide initialized database"""
with app.app_context():
_db.create_all()
yield _db
_db.drop_all()
@pytest.fixture(scope="function")
def session(app, db, request):
"""Creates a new database session for each test,
rolling back changes afterwards"""
connection = _db.engine.connect()
transaction = connection.begin()
options = dict(bind=connection, binds={})
session = _db.create_scoped_session(options=options)
_db.session = session
yield session
transaction.rollback()
connection.close()
session.remove()

View File

@ -24,7 +24,7 @@ fileConfig(config.config_file_name)
path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, path)
sys.path.insert(0, os.path.join(path, "app"))
from app.model import Base
from app.models import Base
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:

25
poetry.lock generated
View File

@ -353,6 +353,27 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pytest"
version = "7.0.0"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
py = ">=1.8.2"
tomli = ">=1.0.0"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "python-vlc"
version = "3.0.12118"
@ -804,6 +825,10 @@ pyqtwebengine-qt5 = [
{file = "PyQtWebEngine_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9e80b408d8de09d4e708d5d84c3ceaf3603292ff8f5e566ae44bb0320fa59c33"},
{file = "PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d"},
]
pytest = [
{file = "pytest-7.0.0-py3-none-any.whl", hash = "sha256:42901e6bd4bd4a0e533358a86e848427a49005a3256f657c5c8f8dd35ef137a9"},
{file = "pytest-7.0.0.tar.gz", hash = "sha256:dad48ffda394e5ad9aa3b7d7ddf339ed502e5e365b1350e0af65f4a602344b11"},
]
python-vlc = [
{file = "python-vlc-3.0.12118.tar.gz", hash = "sha256:566f2f7c303f6800851cacc016df1c6eeec094ad63e0a49d87db9d698094f1fb"},
{file = "python_vlc-3.0.12118-py3-none-any.whl", hash = "sha256:f88be06c6f819a4db2de1c586b193b5df1410ff10fca33b8c6f4e56037c46f7b"},

View File

@ -20,6 +20,7 @@ PyQt5-sip = "^12.9.0"
[tool.poetry.dev-dependencies]
mypy = "^0.931"
pytest = "^7.0.0"
ipdb = "^0.13.9"
[build-system]

View File

@ -1 +0,0 @@
3149370

View File

@ -1,7 +1,6 @@
from model import Playlists, Session
from app.models import Playlists, Session
def test_get_colour():
with Session() as session:
x = Playlists.get_all_playlists(session)
def test_get_colour(db_session):
x = Playlists.get_all_playlists(db_session)
assert False