From 166730b4618de42c0f640d3ce04fba6c7f61b9d7 Mon Sep 17 00:00:00 2001 From: Olezhich Date: Wed, 24 Sep 2025 15:28:25 +0300 Subject: [PATCH] added album status logic --- audiostats/application/__init__.py | 1 - audiostats/application/dto_mappers.py | 22 +- audiostats/db/models.py | 6 +- audiostats/db/repositories.py | 26 ++- audiostats/domain/__init__.py | 1 + .../models.py => domain/enums.py} | 1 - audiostats/handlers/__init__.py | 2 +- audiostats/handlers/models.py | 13 +- poetry.lock | 212 ++---------------- pyproject.toml | 9 +- tests/__init__.py | 2 +- tests/conftest.py | 11 +- tests/db_fixture.py | 103 ++++----- 13 files changed, 130 insertions(+), 279 deletions(-) create mode 100644 audiostats/domain/__init__.py rename audiostats/{application/models.py => domain/enums.py} (99%) diff --git a/audiostats/application/__init__.py b/audiostats/application/__init__.py index b2c762e..e69de29 100644 --- a/audiostats/application/__init__.py +++ b/audiostats/application/__init__.py @@ -1 +0,0 @@ -from .models import Status, Success \ No newline at end of file diff --git a/audiostats/application/dto_mappers.py b/audiostats/application/dto_mappers.py index c5bb593..d980637 100644 --- a/audiostats/application/dto_mappers.py +++ b/audiostats/application/dto_mappers.py @@ -1,6 +1,6 @@ -from audiostats.db import Album, Track +from audiostats.db.models import Album, Track -from audiostats.handlers import AlbumDTO, TrackDTO +from audiostats.handlers import AlbumDTO, TrackDTO, StatusDTO def update_track_orm_f_dto(old : Track, new : TrackDTO) -> None: old.title = new.title @@ -31,4 +31,20 @@ def create_album_dto_f_orm(album : Album): number=track.number, path=track.path, offset=track.offset, - duration=track.duration) for track in album.tracks]) \ No newline at end of file + duration=track.duration) for track in album.tracks], + statuses=[StatusDTO(status=status.status, + success=status.success) for status in album.album_statuses]) + +def diff_album_meta(old : Album, new : AlbumDTO) -> bool: + return any([old.title != new.title, + old.performer != new.performer, + old.year != new.year, + old.path != new.path, + old.cover != new.cover]) + +def diff_track(old : Track, new : TrackDTO) -> bool: + return any([old.title != new.title, + old.number != new.number, + old.path != new.path, + old.offset != new.offset, + old.duration != new.duration]) \ No newline at end of file diff --git a/audiostats/db/models.py b/audiostats/db/models.py index 59d9f18..fc4a37f 100644 --- a/audiostats/db/models.py +++ b/audiostats/db/models.py @@ -1,9 +1,9 @@ from datetime import datetime -from sqlalchemy import String, Integer, UniqueConstraint, ForeignKey, Float, Enum, DateTime +from sqlalchemy import String, Integer, UniqueConstraint, ForeignKey, Float, Enum, DateTime, func from sqlalchemy.orm import declarative_base, Mapped, mapped_column, relationship -from audiostats.application import Status, Success +from audiostats.domain import Status, Success Base = declarative_base() @@ -82,7 +82,7 @@ class AlbumStatus(Base): id : Mapped[int] = mapped_column(Integer, primary_key=True) album_id : Mapped[int] = mapped_column(Integer, ForeignKey('albums.id', ondelete='CASCADE'), index=True) - time_stamp : Mapped[datetime] = mapped_column(DateTime, nullable=False) + time_stamp : Mapped[datetime] = mapped_column(DateTime, nullable=False, server_default=func.now(), default=func.now()) status : Mapped[Status] = mapped_column(Enum(Status), nullable=False) success : Mapped[Success] = mapped_column(Enum(Success), nullable=False) album : Mapped["Album"] = relationship('Album', back_populates='album_statuses', lazy='noload') diff --git a/audiostats/db/repositories.py b/audiostats/db/repositories.py index 33f8f43..30a9f57 100644 --- a/audiostats/db/repositories.py +++ b/audiostats/db/repositories.py @@ -1,12 +1,14 @@ import logging + from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload +from audiostats.domain import Status, Success from .models import Album, AlbumStatus from audiostats.handlers import AlbumDTO -from audiostats.application.dto_mappers import create_album_dto_f_orm, update_album_orm_meta_f_dto, update_track_orm_f_dto, create_track_orm_f_dto +from audiostats.application.dto_mappers import create_album_dto_f_orm, update_album_orm_meta_f_dto, update_track_orm_f_dto, create_track_orm_f_dto, diff_track, diff_album_meta logger = logging.getLogger(__name__) @@ -17,11 +19,14 @@ def __init__(self, session : AsyncSession): async def upsert(self, album_data : AlbumDTO): album = await self.find_by_title_performer(album_data.title, album_data.performer) - # album_status = AlbumStatus() + album_status = None - if not album: + if not album: #if new album album = Album() + album_status = Status.ADDED self._session.add(album) + elif diff_album_meta(album, album_data): #if album meta modified + album_status = Status.MODIFIED update_album_orm_meta_f_dto(album, album_data) @@ -29,15 +34,24 @@ async def upsert(self, album_data : AlbumDTO): for dto in album_data.tracks: if dto.title in old_tracks_by_title: old_track = old_tracks_by_title.pop(dto.title) + if diff_track(old_track, dto): + album_status = Status.MODIFIED update_track_orm_f_dto(old_track, dto) else: + if not album_status: + album_status = Status.MODIFIED track = create_track_orm_f_dto(dto) track.album = album album.tracks.append(track) for track in old_tracks_by_title.values(): + album_status = Status.MODIFIED await self._session.delete(track) + if album_status: + status = AlbumStatus(album=album, status=album_status, success=Success.SUCCESS) + self._session.add(status) + logger.info(f'Album upserted: {album_data}') async def find_by_title_performer(self, title : str, performer : str | None) -> Album | None: @@ -53,3 +67,9 @@ async def all(self) -> list[Album]: selectinload(Album.tracks) )) return [create_album_dto_f_orm(album) for album in result.all()] + + async def all_w_status(self) -> list[Album]: + result = await self._session.scalars(select(Album).options( + selectinload(Album.tracks) + ).options(selectinload(Album.album_statuses))) + return [create_album_dto_f_orm(album) for album in result.all()] diff --git a/audiostats/domain/__init__.py b/audiostats/domain/__init__.py new file mode 100644 index 0000000..e21cd6c --- /dev/null +++ b/audiostats/domain/__init__.py @@ -0,0 +1 @@ +from .enums import Status, Success \ No newline at end of file diff --git a/audiostats/application/models.py b/audiostats/domain/enums.py similarity index 99% rename from audiostats/application/models.py rename to audiostats/domain/enums.py index 3cb3d1b..7453fb7 100644 --- a/audiostats/application/models.py +++ b/audiostats/domain/enums.py @@ -8,4 +8,3 @@ class Success(StrEnum): SUCCESS = 'success' WARNING = 'warning' ERROR = 'error' - diff --git a/audiostats/handlers/__init__.py b/audiostats/handlers/__init__.py index 4f4f69f..a9557c7 100644 --- a/audiostats/handlers/__init__.py +++ b/audiostats/handlers/__init__.py @@ -1,2 +1,2 @@ from .plst_handler import PlayListHandler -from .models import AlbumDTO, TrackDTO \ No newline at end of file +from .models import AlbumDTO, TrackDTO, StatusDTO \ No newline at end of file diff --git a/audiostats/handlers/models.py b/audiostats/handlers/models.py index fed1a12..2e03e8f 100644 --- a/audiostats/handlers/models.py +++ b/audiostats/handlers/models.py @@ -1,5 +1,14 @@ -from dataclasses import dataclass +from dataclasses import dataclass, field +from audiostats.domain import Status, Success + +@dataclass(slots=True) +class StatusDTO: + status : Status + success : Success + + def __repr__(self): + return f'' @dataclass(slots=True) class TrackDTO: @@ -20,10 +29,12 @@ class AlbumDTO: path : str | None cover : str | None tracks : list[TrackDTO] + statuses : list[StatusDTO] = field(default_factory=list) def __repr__(self): return f'''\n''' diff --git a/poetry.lock b/poetry.lock index e107c66..d612d10 100644 --- a/poetry.lock +++ b/poetry.lock @@ -165,7 +165,7 @@ version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" -groups = ["ML", "dev"] +groups = ["ML"] files = [ {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, @@ -274,7 +274,7 @@ version = "3.4.3" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["ML", "dev"] +groups = ["ML"] files = [ {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, @@ -496,27 +496,18 @@ files = [ ] [[package]] -name = "docker" -version = "7.1.0" -description = "A Python library for the Docker Engine API." +name = "dotenv" +version = "0.9.9" +description = "Deprecated package" optional = false -python-versions = ">=3.8" +python-versions = "*" groups = ["dev"] files = [ - {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, - {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, + {file = "dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9"}, ] [package.dependencies] -pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} -requests = ">=2.26.0" -urllib3 = ">=1.26.0" - -[package.extras] -dev = ["coverage (==7.2.7)", "pytest (==7.4.2)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.1.0)", "ruff (==0.1.8)"] -docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] -ssh = ["paramiko (>=2.4.3)"] -websockets = ["websocket-client (>=1.3.0)"] +python-dotenv = "*" [[package]] name = "greenlet" @@ -592,7 +583,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["ML", "dev"] +groups = ["ML"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -1161,44 +1152,13 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "pywin32" -version = "311" -description = "Python for Window Extensions" -optional = false -python-versions = "*" -groups = ["dev"] -markers = "sys_platform == \"win32\"" -files = [ - {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, - {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, - {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, - {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, - {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, - {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, - {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, - {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, - {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, - {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, - {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, - {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, - {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, - {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, - {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, - {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, - {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, - {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, - {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, - {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, -] - [[package]] name = "requests" version = "2.32.5" description = "Python HTTP for Humans." optional = false python-versions = ">=3.9" -groups = ["ML", "dev"] +groups = ["ML"] files = [ {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, @@ -1545,61 +1505,6 @@ files = [ [package.dependencies] audioop-lts = {version = "*", markers = "python_version >= \"3.13\""} -[[package]] -name = "testcontainers" -version = "4.12.0" -description = "Python library for throwaway instances of anything that can run in a Docker container" -optional = false -python-versions = "<4.0,>=3.9" -groups = ["dev"] -files = [ - {file = "testcontainers-4.12.0-py3-none-any.whl", hash = "sha256:26caef57e642d5e8c5fcc593881cf7df3ab0f0dc9170fad22765b184e226ab15"}, - {file = "testcontainers-4.12.0.tar.gz", hash = "sha256:13ee89cae995e643f225665aad8b200b25c4f219944a6f9c0b03249ec3f31b8d"}, -] - -[package.dependencies] -docker = "*" -python-dotenv = "*" -typing-extensions = "*" -urllib3 = "*" -wrapt = "*" - -[package.extras] -arangodb = ["python-arango (>=7.8,<8.0)"] -aws = ["boto3", "httpx"] -azurite = ["azure-storage-blob (>=12.19,<13.0)"] -chroma = ["chromadb-client (>=1.0.0,<2.0.0)"] -clickhouse = ["clickhouse-driver"] -cosmosdb = ["azure-cosmos"] -db2 = ["ibm_db_sa ; platform_machine != \"aarch64\" and platform_machine != \"arm64\"", "sqlalchemy"] -generic = ["httpx", "redis"] -google = ["google-cloud-datastore (>=2)", "google-cloud-pubsub (>=2)"] -influxdb = ["influxdb", "influxdb-client"] -k3s = ["kubernetes", "pyyaml"] -keycloak = ["python-keycloak"] -localstack = ["boto3"] -mailpit = ["cryptography"] -minio = ["minio"] -mongodb = ["pymongo"] -mssql = ["pymssql ; platform_machine != \"arm64\" or python_version >= \"3.10\"", "sqlalchemy"] -mysql = ["pymysql[rsa]", "sqlalchemy"] -nats = ["nats-py"] -neo4j = ["neo4j"] -openfga = ["openfga-sdk ; python_version >= \"3.10\""] -opensearch = ["opensearch-py"] -oracle = ["oracledb", "sqlalchemy"] -oracle-free = ["oracledb", "sqlalchemy"] -qdrant = ["qdrant-client"] -rabbitmq = ["pika"] -redis = ["redis"] -registry = ["bcrypt"] -scylla = ["cassandra-driver (==3.29.1)"] -selenium = ["selenium"] -sftp = ["cryptography"] -test-module-import = ["httpx"] -trino = ["trino"] -weaviate = ["weaviate-client (>=4.5.4,<5.0.0)"] - [[package]] name = "threadpoolctl" version = "3.6.0" @@ -1645,7 +1550,7 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" -groups = ["main", "ML", "db", "dev"] +groups = ["main", "ML", "db"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, @@ -1657,7 +1562,7 @@ version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["ML", "dev"] +groups = ["ML"] files = [ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, @@ -1669,98 +1574,7 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "wrapt" -version = "1.17.3" -description = "Module for decorators, wrappers and monkey patching." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, - {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, - {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, - {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, - {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, - {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, - {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, - {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, - {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, - {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, - {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, - {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, - {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, - {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, - {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, - {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, - {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, - {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, - {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, - {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, - {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, - {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, - {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, - {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, - {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, - {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, - {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, - {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, - {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, - {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, - {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c"}, - {file = "wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b"}, - {file = "wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa"}, - {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7"}, - {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4"}, - {file = "wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10"}, - {file = "wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6"}, - {file = "wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454"}, - {file = "wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e"}, - {file = "wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f"}, - {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056"}, - {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804"}, - {file = "wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977"}, - {file = "wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116"}, - {file = "wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f"}, - {file = "wrapt-1.17.3-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00"}, - {file = "wrapt-1.17.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56"}, - {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5"}, - {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22"}, - {file = "wrapt-1.17.3-cp38-cp38-win32.whl", hash = "sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c"}, - {file = "wrapt-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d"}, - {file = "wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a"}, - {file = "wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139"}, - {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df"}, - {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b"}, - {file = "wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81"}, - {file = "wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f"}, - {file = "wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f"}, - {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, - {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, -] - [metadata] lock-version = "2.1" python-versions = ">=3.12,<4.0" -content-hash = "55f58d4277eb799072f2ec1f723ee933b55d7668342c2f6f110e1944c19e21b8" +content-hash = "483aabdbb8ca42dccf64e6d4f49362af5758448962b58a3c85861742cb915836" diff --git a/pyproject.toml b/pyproject.toml index 378c992..f9c1861 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,5 +31,12 @@ alembic = "^1.16.4" pytest = "^8.4.1" pytest-cov = "^6.2.1" pytest-asyncio = "^1.1.0" -testcontainers = "^4.12.0" +dotenv = "^0.9.9" + +[tool.pytest.ini_options] +testpaths = ["tests/"] +addopts = ["--cov=audiostats", + "--log-cli-level=INFO"] + + diff --git a/tests/__init__.py b/tests/__init__.py index 53f8b38..44cd5ed 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1 @@ -from .db_fixture import test_engine, test_session_factory#, setup_database \ No newline at end of file +# from .db_fixture import test_engine, test_session_factory#, setup_database \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 68769c9..a59eb20 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,9 +5,9 @@ from cuetools import TrackData -from audiostats.handlers import PlayListHandler,AlbumDTO, TrackDTO +from audiostats.handlers import PlayListHandler,AlbumDTO, TrackDTO, StatusDTO from audiostats.handlers.plst_handler import LIBROSA_AVAILABLE - +from audiostats.domain import Status, Success @pytest.fixture def plst_handler_instance(): @@ -124,4 +124,9 @@ def processed_album_dtos(): album_list.append(album2) album_list.append(album3) album_list.append(album4) - return album_list \ No newline at end of file + return album_list + +@pytest.fixture() +def processed_album_dtos_w_status(processed_album_dtos): + for i in processed_album_dtos: + i.statuses=[StatusDTO(status=Status.ADDED, success=Success.SUCCESS)] \ No newline at end of file diff --git a/tests/db_fixture.py b/tests/db_fixture.py index 95e6ffd..2f97e48 100644 --- a/tests/db_fixture.py +++ b/tests/db_fixture.py @@ -1,72 +1,51 @@ -import logging - -import pytest -from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine -from sqlalchemy.ext.asyncio import async_sessionmaker - -from testcontainers.postgres import PostgresContainer - -from audiostats.db.models import Base - -logger = logging.getLogger(__name__) - -POSTGRES_CONTAINER = None -TEST_ENGINE = None - -@pytest.fixture(scope="session") -def event_loop(): - import asyncio - loop = asyncio.new_event_loop() - yield loop - loop.close() - -@pytest.fixture(scope="session") -async def test_engine(): - global POSTGRES_CONTAINER, TEST_ENGINE - POSTGRES_CONTAINER = PostgresContainer("postgres:15") - POSTGRES_CONTAINER.start() - DATABASE_URL = POSTGRES_CONTAINER.get_connection_url() \ - .replace("postgresql://", "postgresql+asyncpg://")\ - .replace("postgresql+psycopg2://", "postgresql+asyncpg://") - engine = create_async_engine(DATABASE_URL, echo=False) - - async with engine.begin() as conn: - await conn.run_sync(Base.metadata.create_all) - TEST_ENGINE = engine - return engine - -@pytest.fixture(scope="session") -async def test_session_factory(test_engine): - engine = test_engine - return async_sessionmaker(bind=await engine, expire_on_commit=False) - -@pytest.fixture(scope="session", autouse=True) -async def cleanup_test_resources(): - yield - global TEST_ENGINE, POSTGRES_CONTAINER - if TEST_ENGINE: - await TEST_ENGINE.dispose() - if POSTGRES_CONTAINER: - POSTGRES_CONTAINER.stop() - +# import logging +# +# import pytest +# from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine +# from sqlalchemy.ext.asyncio import async_sessionmaker +# +# from testcontainers.postgres import PostgresContainer +# +# from audiostats.db.models import Base +# +# logger = logging.getLogger(__name__) +# +# POSTGRES_CONTAINER = None +# TEST_ENGINE = None +# +# @pytest.fixture(scope="session") +# def event_loop(): +# import asyncio +# loop = asyncio.new_event_loop() +# yield loop +# loop.close() +# # @pytest.fixture(scope="session") -# def test_engine(): -# global POSTGRES_CONTAINER +# async def test_engine(): +# global POSTGRES_CONTAINER, TEST_ENGINE # POSTGRES_CONTAINER = PostgresContainer("postgres:15") # POSTGRES_CONTAINER.start() # DATABASE_URL = POSTGRES_CONTAINER.get_connection_url() \ # .replace("postgresql://", "postgresql+asyncpg://")\ # .replace("postgresql+psycopg2://", "postgresql+asyncpg://") # engine = create_async_engine(DATABASE_URL, echo=False) -# yield engine -# asyncio.run(engine.dispose()) -# POSTGRES_CONTAINER.stop() +# +# async with engine.begin() as conn: +# await conn.run_sync(Base.metadata.create_all) +# TEST_ENGINE = engine +# return engine # # @pytest.fixture(scope="session") -# def test_session_factory(test_engine): -# async def setup(): -# async with test_engine.begin() as conn: -# await conn.run_sync(Base.metadata.create_all) -# asyncio.run(setup()) -# return async_sessionmaker(bind=test_engine, expire_on_commit=False) +# async def test_session_factory(test_engine): +# engine = test_engine +# return async_sessionmaker(bind=await engine, expire_on_commit=False) +# +# @pytest.fixture(scope="session", autouse=True) +# async def cleanup_test_resources(): +# yield +# global TEST_ENGINE, POSTGRES_CONTAINER +# if TEST_ENGINE: +# await TEST_ENGINE.dispose() +# if POSTGRES_CONTAINER: +# POSTGRES_CONTAINER.stop()