Rebase dev onto v2_id branch
This commit is contained in:
parent
db86d04b9a
commit
a164f4c962
@ -1,4 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (musicmuster) (2)" project-jdk-type="Python SDK" />
|
<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>
|
</project>
|
||||||
@ -36,15 +36,8 @@ class Config(object):
|
|||||||
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
|
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
|
||||||
MAX_INFO_TABS = 3
|
MAX_INFO_TABS = 3
|
||||||
MILLISECOND_SIGFIGS = 0
|
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
|
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"
|
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
||||||
TESTMODE = True
|
TESTMODE = True
|
||||||
TIMER_MS = 500
|
TIMER_MS = 500
|
||||||
|
|||||||
@ -19,7 +19,7 @@ from sqlalchemy import (
|
|||||||
)
|
)
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
|
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 config import Config
|
||||||
from log import DEBUG, ERROR
|
from log import DEBUG, ERROR
|
||||||
@ -27,16 +27,26 @@ from log import DEBUG, ERROR
|
|||||||
# Create session at the global level as per
|
# Create session at the global level as per
|
||||||
# https://docs.sqlalchemy.org/en/13/orm/session_basics.html
|
# https://docs.sqlalchemy.org/en/13/orm/session_basics.html
|
||||||
|
|
||||||
# Set up database connection
|
Base = declarative_base()
|
||||||
engine = sqlalchemy.create_engine(f"{Config.MYSQL_CONNECT}?charset=utf8",
|
Session = scoped_session(sessionmaker())
|
||||||
|
|
||||||
|
|
||||||
|
def dbinit():
|
||||||
|
# Set up database connection
|
||||||
|
|
||||||
|
global Session
|
||||||
|
|
||||||
|
engine = sqlalchemy.create_engine(
|
||||||
|
f"{Config.MYSQL_CONNECT}?charset=utf8",
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
echo=Config.DISPLAY_SQL,
|
echo=Config.DISPLAY_SQL,
|
||||||
pool_pre_ping=True)
|
pool_pre_ping=True)
|
||||||
Base = declarative_base()
|
|
||||||
Base.metadata.create_all(engine)
|
|
||||||
|
|
||||||
# Create a Session factory
|
Session.configure(bind=engine)
|
||||||
Session = sessionmaker(bind=engine)
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
|
# Create a Session factory
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
|
||||||
|
|
||||||
# Database classes
|
# Database classes
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import helpers
|
|||||||
import music
|
import music
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from model import (Notes, Playdates, Playlists, PlaylistTracks,
|
from models import (dbinit, Notes, Playdates, Playlists, PlaylistTracks,
|
||||||
Session, Settings, Tracks)
|
Session, Settings, Tracks)
|
||||||
from playlists import PlaylistTab
|
from playlists import PlaylistTab
|
||||||
from songdb import create_track_from_file
|
from songdb import create_track_from_file
|
||||||
@ -226,12 +226,14 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def close_tab(self, index):
|
def close_tab(self, index):
|
||||||
if hasattr(self.tabPlaylist.widget(index), 'is_playlist'):
|
if hasattr(self.tabPlaylist.widget(index), 'is_playlist'):
|
||||||
if self.tabPlaylist.widget(index) == self.current_track_playlist_tab:
|
if self.tabPlaylist.widget(index) == (
|
||||||
self.statusbar.showMessage("Can't close current track playlist",
|
self.current_track_playlist_tab):
|
||||||
5000)
|
self.statusbar.showMessage(
|
||||||
|
"Can't close current track playlist", 5000)
|
||||||
return
|
return
|
||||||
if self.tabPlaylist.widget(index) == self.next_track_playlist_tab:
|
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
|
return
|
||||||
# It's OK to close this playlist so remove from open playlist list
|
# It's OK to close this playlist so remove from open playlist list
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
@ -950,6 +952,7 @@ class SelectPlaylistDialog(QDialog):
|
|||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
dbinit()
|
||||||
win = Window()
|
win = Window()
|
||||||
win.show()
|
win.show()
|
||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
|
|||||||
@ -19,7 +19,7 @@ from config import Config
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from helpers import get_relative_date, open_in_audacity
|
from helpers import get_relative_date, open_in_audacity
|
||||||
from log import DEBUG, ERROR
|
from log import DEBUG, ERROR
|
||||||
from model import (
|
from models import (
|
||||||
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks, NoteColours
|
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks, NoteColours
|
||||||
)
|
)
|
||||||
from songdb import create_track_from_file, update_meta
|
from songdb import create_track_from_file, update_meta
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import tempfile
|
|||||||
from config import Config
|
from config import Config
|
||||||
from helpers import show_warning
|
from helpers import show_warning
|
||||||
from log import DEBUG, INFO
|
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.flac import FLAC
|
||||||
from mutagen.mp3 import MP3
|
from mutagen.mp3 import MP3
|
||||||
from pydub import AudioSegment, effects
|
from pydub import AudioSegment, effects
|
||||||
|
|||||||
113
conftest.py
113
conftest.py
@ -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 pytest
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||||
|
|
||||||
sys.path.append("app")
|
sys.path.append("app")
|
||||||
|
from app.models import Base # noqa E402
|
||||||
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):
|
@pytest.fixture(scope="session")
|
||||||
# TESTING = True
|
def connection():
|
||||||
SQLALCHEMY_DATABASE_URI = 'sqlite://'
|
engine = create_engine(
|
||||||
PYTESTING = True
|
"mysql+mysqldb://musicmuster_testing:musicmuster_testing@"
|
||||||
|
"localhost/musicmuster_testing"
|
||||||
|
)
|
||||||
|
return engine.connect()
|
||||||
|
|
||||||
# @pytest.fixture(scope="module")
|
|
||||||
# def app():
|
def seed_database():
|
||||||
# app = create_app(TestConfig)
|
pass
|
||||||
# app_context = app.app_context()
|
|
||||||
# app_context.push()
|
# users = [
|
||||||
# db.create_all()
|
# {
|
||||||
# return app
|
# "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
|
@pytest.fixture
|
||||||
def no_bank_holidays():
|
def db_session(setup_database, connection):
|
||||||
"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()
|
transaction = connection.begin()
|
||||||
|
yield scoped_session(
|
||||||
options = dict(bind=connection, binds={})
|
sessionmaker(autocommit=False, autoflush=False, bind=connection)
|
||||||
session = _db.create_scoped_session(options=options)
|
)
|
||||||
|
|
||||||
_db.session = session
|
|
||||||
|
|
||||||
yield session
|
|
||||||
|
|
||||||
transaction.rollback()
|
transaction.rollback()
|
||||||
connection.close()
|
|
||||||
session.remove()
|
|
||||||
|
|||||||
@ -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()
|
|
||||||
@ -24,7 +24,7 @@ fileConfig(config.config_file_name)
|
|||||||
path = os.path.dirname(os.path.dirname(__file__))
|
path = os.path.dirname(os.path.dirname(__file__))
|
||||||
sys.path.insert(0, path)
|
sys.path.insert(0, path)
|
||||||
sys.path.insert(0, os.path.join(path, "app"))
|
sys.path.insert(0, os.path.join(path, "app"))
|
||||||
from app.model import Base
|
from app.models import Base
|
||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
# can be acquired:
|
# can be acquired:
|
||||||
|
|||||||
25
poetry.lock
generated
25
poetry.lock
generated
@ -353,6 +353,27 @@ category = "main"
|
|||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
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]]
|
[[package]]
|
||||||
name = "python-vlc"
|
name = "python-vlc"
|
||||||
version = "3.0.12118"
|
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-win32.whl", hash = "sha256:9e80b408d8de09d4e708d5d84c3ceaf3603292ff8f5e566ae44bb0320fa59c33"},
|
||||||
{file = "PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d"},
|
{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 = [
|
python-vlc = [
|
||||||
{file = "python-vlc-3.0.12118.tar.gz", hash = "sha256:566f2f7c303f6800851cacc016df1c6eeec094ad63e0a49d87db9d698094f1fb"},
|
{file = "python-vlc-3.0.12118.tar.gz", hash = "sha256:566f2f7c303f6800851cacc016df1c6eeec094ad63e0a49d87db9d698094f1fb"},
|
||||||
{file = "python_vlc-3.0.12118-py3-none-any.whl", hash = "sha256:f88be06c6f819a4db2de1c586b193b5df1410ff10fca33b8c6f4e56037c46f7b"},
|
{file = "python_vlc-3.0.12118-py3-none-any.whl", hash = "sha256:f88be06c6f819a4db2de1c586b193b5df1410ff10fca33b8c6f4e56037c46f7b"},
|
||||||
|
|||||||
@ -20,6 +20,7 @@ PyQt5-sip = "^12.9.0"
|
|||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
mypy = "^0.931"
|
mypy = "^0.931"
|
||||||
|
pytest = "^7.0.0"
|
||||||
ipdb = "^0.13.9"
|
ipdb = "^0.13.9"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from model import Playlists, Session
|
from app.models import Playlists, Session
|
||||||
|
|
||||||
|
|
||||||
def test_get_colour():
|
def test_get_colour(db_session):
|
||||||
with Session() as session:
|
x = Playlists.get_all_playlists(db_session)
|
||||||
x = Playlists.get_all_playlists(session)
|
|
||||||
assert False
|
assert False
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user