From df3f9349a4659030e670e7164f6a64cb92c046cf Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sat, 11 Jul 2026 19:44:44 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D1=83=20?= =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?room=5Fid,=20group=5Fid=20=D0=B8=20lecturer=5Fid=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20patch=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/event/event.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/event/event.py b/tests/event/event.py index 84ef9b2b..bbdf057e 100644 --- a/tests/event/event.py +++ b/tests/event/event.py @@ -198,6 +198,7 @@ def test_delete(client_auth: TestClient, dbsession: Session, room_path, lecturer def test_update_all(client_auth: TestClient, dbsession: Session): + import pytest # Create room = Room(name="5-07" + datetime.datetime.utcnow().isoformat(), direction="North") lecturer = Lecturer(first_name="s", middle_name="s", last_name="s") @@ -214,6 +215,7 @@ def test_update_all(client_auth: TestClient, dbsession: Session): "start_ts": "2022-08-26T22:32:38.575Z", "end_ts": "2022-08-26T22:32:38.575Z", } + pytest.set_trace() response = client_auth.post(RESOURCE, json=request_obj) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() @@ -237,15 +239,21 @@ def test_update_all(client_auth: TestClient, dbsession: Session): assert response_obj["end_ts"][:20] == request_obj["end_ts"][:20] # Update + another_room = Room(name="5-07" + datetime.datetime.utcnow().isoformat(), direction="North") + another_lecturer = Lecturer(first_name="s", middle_name="s", last_name="s") + another_group = Group(name="", number="202" + datetime.datetime.utcnow().isoformat()) + dbsession.add_all((another_room, another_group, another_lecturer)) + dbsession.commit() request_obj_2 = { "name": "frfrf", - "room_id": [room.id], - "group_id": [group.id], - "lecturer_id": [lecturer.id], + "room_id": [another_room.id], + "group_id": [another_group.id], + "lecturer_id": [another_lecturer.id], "start_ts": "2022-08-26T22:32:38.575Z", "end_ts": "2022-08-26T22:32:38.575Z", } response = client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + pytest.set_trace() assert response.status_code == 200 response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() From db4436888835e6730a070ecc7e0193883701639e Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sat, 11 Jul 2026 19:45:51 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=84=D0=B8=D0=BA=D1=81=D1=82=D1=83=D1=80?= =?UTF-8?q?=D0=B0=20db=5Fcontainer,=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D1=82=D0=B8=D1=8F=20=D0=B8=20=D0=BD=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B8=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=D0=B9=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/conftest.py | 51 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 096339a1..0bcdd944 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,6 +11,50 @@ from calendar_backend.models.db import Event, Group, Lecturer, Room from calendar_backend.routes import app from calendar_backend.settings import get_settings +from _pytest.monkeypatch import MonkeyPatch +from alembic import command +from alembic.config import Config as AlembicConfig +from pathlib import Path +from testcontainers.postgres import PostgresContainer + + +class PostgresConfig: + """Дата-класс со значениями для контейнера с тестовой БД и для alembic-миграции.""" + + container_name: str = "modal-service-api_test" + username: str = "postgres" + host: str = "localhost" + external_port: int = 5432 + image: str = "postgres:15" + host_auth_method: str = "trust" + alembic_ini: str = Path(__file__).resolve().parent.parent / "alembic.ini" + + @classmethod + def get_url(cls) -> str: + """Возвращает URI для подключения к БД.""" + return f"postgresql://{cls.username}@{cls.host}:{cls.external_port}/postgres" + + + +@pytest.fixture(scope="session") +def db_container(): + """Фикстура настройки БД для тестов в Docker-контейнере.""" + container = ( + PostgresContainer( + image=PostgresConfig.image, username=PostgresConfig.username, dbname=PostgresConfig.container_name + ) + .with_bind_ports(5432, PostgresConfig.external_port) + .with_env("POSTGRES_HOST_AUTH_METHOD", PostgresConfig.host_auth_method) + ) + container.start() + alembic_ini = PostgresConfig.alembic_ini + cfg = AlembicConfig(str(alembic_ini.resolve())) + cfg.set_main_option("script_location", "%(here)s/migrations") + command.upgrade(cfg, "head") + try: + yield PostgresConfig.get_url() + finally: + container.stop() @pytest.fixture() @@ -21,7 +65,7 @@ def client(): @pytest.fixture() def client_auth(mocker: MockerFixture): - user_mock = mocker.patch('auth_lib.fastapi.UnionAuth.__call__') + user_mock = mocker.patch('auth_lib.fastapi.UnionAuth.__call__', autospec=True) user_mock.return_value = { "session_scopes": [{"id": 0, "name": "string", "comment": "string"}], "user_scopes": [{"id": 0, "name": "string", "comment": "string"}], @@ -35,9 +79,8 @@ def client_auth(mocker: MockerFixture): @pytest.fixture() -def dbsession(): - settings = get_settings() - engine = create_engine(str(settings.DB_DSN), isolation_level='AUTOCOMMIT') +def dbsession(db_container): + engine = create_engine(str(db_container), isolation_level='AUTOCOMMIT') TestingSessionLocal = sessionmaker(bind=engine) DeclarativeBase.metadata.create_all(bind=engine) return TestingSessionLocal() From 8a0493a847663bb59804ae54ecb21e5809a22c19 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sat, 11 Jul 2026 23:44:21 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=80=D0=B0=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B8=20=D1=83=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=80=D1=83=D1=87=D0=BA=D0=B8=20patch-event-id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- calendar_backend/routes/event/event.py | 49 ++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/calendar_backend/routes/event/event.py b/calendar_backend/routes/event/event.py index 1af85121..65d539fa 100644 --- a/calendar_backend/routes/event/event.py +++ b/calendar_backend/routes/event/event.py @@ -1,6 +1,7 @@ import logging from datetime import date, timedelta from typing import Literal +from itertools import zip_longest from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends, Query, status @@ -8,9 +9,9 @@ from fastapi_sqlalchemy import db from pydantic import TypeAdapter -from calendar_backend.exceptions import NotEnoughCriteria +from calendar_backend.exceptions import NotEnoughCriteria, ObjectNotFound from calendar_backend.methods import list_calendar -from calendar_backend.models import Event, Group, Lecturer, Room +from calendar_backend.models import Event, Group, Lecturer, Room, EventsRooms, EventsGroups, EventsLecturers from calendar_backend.routes.models import EventGet from calendar_backend.routes.models.event import ( EventPatch, @@ -199,7 +200,49 @@ async def patch_event_by_name( async def patch_event( id: int, event_inp: EventPatch, _=Depends(UnionAuth(scopes=["timetable.event.update"])) ) -> EventGet: - patched = Event.update(id, session=db.session, **event_inp.model_dump(exclude_unset=True)) + + # проверяем, что событие с таким id существует + Events = db.session.query(Event).filter(Event.id == id).one_or_none() + if not Events: + raise ObjectNotFound(type=type(Events), ids=id) + + event_upd_data = event_inp.model_dump(exclude_unset=True) + # получаем списки id всех существующих аудиторий, групп и лекторов + all_rooms = [room.id for room in db.session.query(Room).all()] + all_groups = [group.id for group in db.session.query(Group).all()] + all_lecturers = [lecturer.id for lecturer in db.session.query(Lecturer).all()] + # проверяем cуществование заданных в body (room_, group_, lecturer_)*id + for r, g, l in zip_longest(event_upd_data.get("room_id"), event_upd_data.get("group_id"), event_upd_data.get("lecturer_id"), fillvalue=None): + if r not in all_rooms: + raise ObjectNotFound(type=type(Room), ids=r) + if g not in all_groups: + raise ObjectNotFound(type=type(Group), ids=g) + if l not in all_lecturers: + raise ObjectNotFound(type=type(Lecturer), ids=l) + + def add_new_remove_old_ids(dbsession, event_id, artefact: str, event_instance, negotiator_instance) -> None: + """Вспомогательная фукнция описывающая удаление старых и добавление новых (room_, group_, lecturer_)*id - артефактов""" + # получаем множество артефактов события + event_artefacts = {room.id for room in getattr(event_instance, f"{artefact}")} + # получаем множетсво страрых артефактов + old_artefacts = event_artefacts - set(event_upd_data.get(f"{artefact}_id")) + # получаем множество новых артефактов + new_artefacts = set(event_upd_data.get(f"{artefact}_id")) - event_artefacts + # получаем артефакты к удалению(уникальные старые) + to_remove = old_artefacts - new_artefacts + # получаем артефакты к созданию(уникальные новые) + to_add = new_artefacts - old_artefacts + + if to_remove: + dbsession.query(negotiator_instance).filter(negotiator_instance.event_id==event_id, getattr(negotiator_instance, f"{artefact}_id").in_(to_remove)).delete() + if to_add: + dbsession.bulk_insert_mappings(negotiator_instance, [{"event_id" : f"{event_id}", f"{artefact}_id" : id_to_add} for id_to_add in to_add]) + + add_new_remove_old_ids(db.session, id, "room", Events, EventsRooms) + add_new_remove_old_ids(db.session, id, "group", Events, EventsGroups) + add_new_remove_old_ids(db.session, id, "lecturer", Events, EventsLecturers) + + patched = Event.update(id, session=db.session, **event_upd_data) db.session.commit() return EventGet.model_validate(patched) From f5b4019a85c6273c433376cd31fb80f62e6dd7e2 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sat, 11 Jul 2026 23:48:37 +0300 Subject: [PATCH 04/11] Cosmetic fix --- calendar_backend/routes/event/event.py | 27 +++++++++++++++----------- tests/conftest.py | 11 ++++------- tests/event/event.py | 3 --- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/calendar_backend/routes/event/event.py b/calendar_backend/routes/event/event.py index 65d539fa..0bb93df6 100644 --- a/calendar_backend/routes/event/event.py +++ b/calendar_backend/routes/event/event.py @@ -1,7 +1,7 @@ import logging from datetime import date, timedelta -from typing import Literal from itertools import zip_longest +from typing import Literal from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends, Query, status @@ -11,7 +11,7 @@ from calendar_backend.exceptions import NotEnoughCriteria, ObjectNotFound from calendar_backend.methods import list_calendar -from calendar_backend.models import Event, Group, Lecturer, Room, EventsRooms, EventsGroups, EventsLecturers +from calendar_backend.models import Event, EventsGroups, EventsLecturers, EventsRooms, Group, Lecturer, Room from calendar_backend.routes.models import EventGet from calendar_backend.routes.models.event import ( EventPatch, @@ -200,7 +200,6 @@ async def patch_event_by_name( async def patch_event( id: int, event_inp: EventPatch, _=Depends(UnionAuth(scopes=["timetable.event.update"])) ) -> EventGet: - # проверяем, что событие с таким id существует Events = db.session.query(Event).filter(Event.id == id).one_or_none() if not Events: @@ -211,14 +210,16 @@ async def patch_event( all_rooms = [room.id for room in db.session.query(Room).all()] all_groups = [group.id for group in db.session.query(Group).all()] all_lecturers = [lecturer.id for lecturer in db.session.query(Lecturer).all()] - # проверяем cуществование заданных в body (room_, group_, lecturer_)*id - for r, g, l in zip_longest(event_upd_data.get("room_id"), event_upd_data.get("group_id"), event_upd_data.get("lecturer_id"), fillvalue=None): + # проверяем cуществование заданных в body (room_, group_, lecturer_)*id + for r, g, l in zip_longest( + event_upd_data.get("room_id"), event_upd_data.get("group_id"), event_upd_data.get("lecturer_id"), fillvalue=None + ): if r not in all_rooms: - raise ObjectNotFound(type=type(Room), ids=r) + raise ObjectNotFound(type=type(Room), ids=r) if g not in all_groups: - raise ObjectNotFound(type=type(Group), ids=g) + raise ObjectNotFound(type=type(Group), ids=g) if l not in all_lecturers: - raise ObjectNotFound(type=type(Lecturer), ids=l) + raise ObjectNotFound(type=type(Lecturer), ids=l) def add_new_remove_old_ids(dbsession, event_id, artefact: str, event_instance, negotiator_instance) -> None: """Вспомогательная фукнция описывающая удаление старых и добавление новых (room_, group_, lecturer_)*id - артефактов""" @@ -227,16 +228,20 @@ def add_new_remove_old_ids(dbsession, event_id, artefact: str, event_instance, n # получаем множетсво страрых артефактов old_artefacts = event_artefacts - set(event_upd_data.get(f"{artefact}_id")) # получаем множество новых артефактов - new_artefacts = set(event_upd_data.get(f"{artefact}_id")) - event_artefacts + new_artefacts = set(event_upd_data.get(f"{artefact}_id")) - event_artefacts # получаем артефакты к удалению(уникальные старые) to_remove = old_artefacts - new_artefacts # получаем артефакты к созданию(уникальные новые) to_add = new_artefacts - old_artefacts if to_remove: - dbsession.query(negotiator_instance).filter(negotiator_instance.event_id==event_id, getattr(negotiator_instance, f"{artefact}_id").in_(to_remove)).delete() + dbsession.query(negotiator_instance).filter( + negotiator_instance.event_id == event_id, getattr(negotiator_instance, f"{artefact}_id").in_(to_remove) + ).delete() if to_add: - dbsession.bulk_insert_mappings(negotiator_instance, [{"event_id" : f"{event_id}", f"{artefact}_id" : id_to_add} for id_to_add in to_add]) + dbsession.bulk_insert_mappings( + negotiator_instance, [{"event_id": f"{event_id}", f"{artefact}_id": id_to_add} for id_to_add in to_add] + ) add_new_remove_old_ids(db.session, id, "room", Events, EventsRooms) add_new_remove_old_ids(db.session, id, "group", Events, EventsGroups) diff --git a/tests/conftest.py b/tests/conftest.py index 0bcdd944..15edb73f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,21 +1,19 @@ from datetime import datetime +from pathlib import Path import pytest +from alembic import command +from alembic.config import Config as AlembicConfig from fastapi.testclient import TestClient from pytest_mock import MockerFixture from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from starlette import status +from testcontainers.postgres import PostgresContainer from calendar_backend.models.base import DeclarativeBase from calendar_backend.models.db import Event, Group, Lecturer, Room from calendar_backend.routes import app -from calendar_backend.settings import get_settings -from _pytest.monkeypatch import MonkeyPatch -from alembic import command -from alembic.config import Config as AlembicConfig -from pathlib import Path -from testcontainers.postgres import PostgresContainer class PostgresConfig: @@ -35,7 +33,6 @@ def get_url(cls) -> str: return f"postgresql://{cls.username}@{cls.host}:{cls.external_port}/postgres" - @pytest.fixture(scope="session") def db_container(): """Фикстура настройки БД для тестов в Docker-контейнере.""" diff --git a/tests/event/event.py b/tests/event/event.py index bbdf057e..99fe6272 100644 --- a/tests/event/event.py +++ b/tests/event/event.py @@ -198,7 +198,6 @@ def test_delete(client_auth: TestClient, dbsession: Session, room_path, lecturer def test_update_all(client_auth: TestClient, dbsession: Session): - import pytest # Create room = Room(name="5-07" + datetime.datetime.utcnow().isoformat(), direction="North") lecturer = Lecturer(first_name="s", middle_name="s", last_name="s") @@ -215,7 +214,6 @@ def test_update_all(client_auth: TestClient, dbsession: Session): "start_ts": "2022-08-26T22:32:38.575Z", "end_ts": "2022-08-26T22:32:38.575Z", } - pytest.set_trace() response = client_auth.post(RESOURCE, json=request_obj) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() @@ -253,7 +251,6 @@ def test_update_all(client_auth: TestClient, dbsession: Session): "end_ts": "2022-08-26T22:32:38.575Z", } response = client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) - pytest.set_trace() assert response.status_code == 200 response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() From e4617b7242995015db36cf537d863ee13e4b2bd7 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 12:07:22 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20testcontainers=20=D0=B2=20requirements.dev.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.dev.txt b/requirements.dev.txt index b36fa3d1..48b06faf 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -5,3 +5,4 @@ pytest-mock black==23.11.0 isort autoflake +pytest.set_trace() From c45daee41e253a582d4dda6057678a70860dd011 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 12:14:21 +0300 Subject: [PATCH 06/11] fix --- requirements.dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.dev.txt b/requirements.dev.txt index 48b06faf..aff4c04b 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -5,4 +5,4 @@ pytest-mock black==23.11.0 isort autoflake -pytest.set_trace() +testcontainers[postgres] From d9a358b4eefa55ac374bdb27bb2062af7018066e Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 12:18:21 +0300 Subject: [PATCH 07/11] fix --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 15edb73f..9dc2d593 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,7 +22,7 @@ class PostgresConfig: container_name: str = "modal-service-api_test" username: str = "postgres" host: str = "localhost" - external_port: int = 5432 + external_port: int = 5433 image: str = "postgres:15" host_auth_method: str = "trust" alembic_ini: str = Path(__file__).resolve().parent.parent / "alembic.ini" From 9df110eef353c426e297e82187f3308e809a5b41 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 13:51:05 +0300 Subject: [PATCH 08/11] fix conftest.py --- tests/conftest.py | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9dc2d593..66dbfd6a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,9 @@ from datetime import datetime from pathlib import Path +from functools import lru_cache import pytest +from pytest import MonkeyPatch from alembic import command from alembic.config import Config as AlembicConfig from fastapi.testclient import TestClient @@ -13,13 +15,13 @@ from calendar_backend.models.base import DeclarativeBase from calendar_backend.models.db import Event, Group, Lecturer, Room -from calendar_backend.routes import app +from calendar_backend.settings import Settings class PostgresConfig: """Дата-класс со значениями для контейнера с тестовой БД и для alembic-миграции.""" - container_name: str = "modal-service-api_test" + container_name: str = "timetable-api-test" username: str = "postgres" host: str = "localhost" external_port: int = 5433 @@ -34,7 +36,36 @@ def get_url(cls) -> str: @pytest.fixture(scope="session") -def db_container(): +def session_mp(): + mp = MonkeyPatch() + yield mp + mp.undo() + + +@pytest.fixture(scope="session") +def get_settings_mock(session_mp): + """Переопределение get_settings в calendar_backend/settings.py.""" + + @lru_cache + def get_test_settings(): + test_settings = Settings() + test_settings.DB_DSN = PostgresConfig.get_url() + return test_settings + + dsn_mock = session_mp.setattr("calendar_backend.settings.get_settings", get_test_settings) + return dsn_mock + + +@pytest.fixture(scope="session") +def get_app_with_test_settings(get_settings_mock): + """Загрузка app с тестовыми настройками.""" + from calendar_backend.routes import app + + return app + + +@pytest.fixture(scope="session") +def db_container(get_settings_mock): """Фикстура настройки БД для тестов в Docker-контейнере.""" container = ( PostgresContainer( @@ -55,13 +86,14 @@ def db_container(): @pytest.fixture() -def client(): +def client(get_app_with_test_settings): + app = get_app_with_test_settings client = TestClient(app) return client @pytest.fixture() -def client_auth(mocker: MockerFixture): +def client_auth(mocker: MockerFixture, get_app_with_test_settings): user_mock = mocker.patch('auth_lib.fastapi.UnionAuth.__call__', autospec=True) user_mock.return_value = { "session_scopes": [{"id": 0, "name": "string", "comment": "string"}], @@ -71,6 +103,7 @@ def client_auth(mocker: MockerFixture): "id": 0, "email": "string", } + app = get_app_with_test_settings client = TestClient(app) return client @@ -80,7 +113,7 @@ def dbsession(db_container): engine = create_engine(str(db_container), isolation_level='AUTOCOMMIT') TestingSessionLocal = sessionmaker(bind=engine) DeclarativeBase.metadata.create_all(bind=engine) - return TestingSessionLocal() + yield TestingSessionLocal() @pytest.fixture() From 1e5e5cb06ca05c77d9819c2399bfe69633078822 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 13:55:11 +0300 Subject: [PATCH 09/11] fix conftest.py --- tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 66dbfd6a..8dbdb6b3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,12 +1,12 @@ from datetime import datetime -from pathlib import Path from functools import lru_cache +from pathlib import Path import pytest -from pytest import MonkeyPatch from alembic import command from alembic.config import Config as AlembicConfig from fastapi.testclient import TestClient +from pytest import MonkeyPatch from pytest_mock import MockerFixture from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker From 05158f2d0234ca5f17c2cf9f41e5468f585d54a5 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 15:09:06 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D1=81=D1=83=D1=89?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B2=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?lectuer,=20group=20=D0=B8=20room=20=D1=81=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- calendar_backend/routes/event/event.py | 37 +++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/calendar_backend/routes/event/event.py b/calendar_backend/routes/event/event.py index 0bb93df6..e5b26d86 100644 --- a/calendar_backend/routes/event/event.py +++ b/calendar_backend/routes/event/event.py @@ -204,22 +204,29 @@ async def patch_event( Events = db.session.query(Event).filter(Event.id == id).one_or_none() if not Events: raise ObjectNotFound(type=type(Events), ids=id) - + import pytest + pytest.set_trace() event_upd_data = event_inp.model_dump(exclude_unset=True) - # получаем списки id всех существующих аудиторий, групп и лекторов - all_rooms = [room.id for room in db.session.query(Room).all()] - all_groups = [group.id for group in db.session.query(Group).all()] - all_lecturers = [lecturer.id for lecturer in db.session.query(Lecturer).all()] - # проверяем cуществование заданных в body (room_, group_, lecturer_)*id - for r, g, l in zip_longest( - event_upd_data.get("room_id"), event_upd_data.get("group_id"), event_upd_data.get("lecturer_id"), fillvalue=None - ): - if r not in all_rooms: - raise ObjectNotFound(type=type(Room), ids=r) - if g not in all_groups: - raise ObjectNotFound(type=type(Group), ids=g) - if l not in all_lecturers: - raise ObjectNotFound(type=type(Lecturer), ids=l) + + upd_rooms = set(event_upd_data.get("room_id")) + db_rooms = {room.id for room in db.session.query(Room).filter(Room.id.in_(upd_rooms)).all()} + no_exist_rooms = upd_rooms - db_rooms + if no_exist_rooms: + raise ObjectNotFound(type=type(Room), ids=list(no_exist_rooms)) + + upd_groups= set(event_upd_data.get("group_id")) + db_groups = {group.id for group in db.session.query(Group).filter(Group.id.in_(upd_groups)).all()} + no_exist_groups = upd_groups - db_groups + if no_exist_groups: + raise ObjectNotFound(type=type(Group), ids=list(no_exist_groups)) + + + upd_lecturers = set(event_upd_data.get("lecturer_id")) + db_lecturers = {lecturer.id for lecturer in db.session.query(Lecturer).filter(Lecturer.id.in_(upd_lecturers)).all()} + no_exist_lecturers = upd_lecturers - db_lecturers + if no_exist_lecturers: + raise ObjectNotFound(type=type(Lecturer), ids=list(no_exist_lecturers)) + def add_new_remove_old_ids(dbsession, event_id, artefact: str, event_instance, negotiator_instance) -> None: """Вспомогательная фукнция описывающая удаление старых и добавление новых (room_, group_, lecturer_)*id - артефактов""" From b03fb1b33b5621c79537fdd004c0e7accd93c460 Mon Sep 17 00:00:00 2001 From: NamazovMaksim Date: Sun, 12 Jul 2026 15:13:19 +0300 Subject: [PATCH 11/11] fix --- calendar_backend/routes/event/event.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/calendar_backend/routes/event/event.py b/calendar_backend/routes/event/event.py index e5b26d86..a8c7c924 100644 --- a/calendar_backend/routes/event/event.py +++ b/calendar_backend/routes/event/event.py @@ -1,6 +1,5 @@ import logging from datetime import date, timedelta -from itertools import zip_longest from typing import Literal from auth_lib.fastapi import UnionAuth @@ -204,30 +203,26 @@ async def patch_event( Events = db.session.query(Event).filter(Event.id == id).one_or_none() if not Events: raise ObjectNotFound(type=type(Events), ids=id) - import pytest - pytest.set_trace() event_upd_data = event_inp.model_dump(exclude_unset=True) - + upd_rooms = set(event_upd_data.get("room_id")) db_rooms = {room.id for room in db.session.query(Room).filter(Room.id.in_(upd_rooms)).all()} - no_exist_rooms = upd_rooms - db_rooms + no_exist_rooms = upd_rooms - db_rooms if no_exist_rooms: raise ObjectNotFound(type=type(Room), ids=list(no_exist_rooms)) - - upd_groups= set(event_upd_data.get("group_id")) + + upd_groups = set(event_upd_data.get("group_id")) db_groups = {group.id for group in db.session.query(Group).filter(Group.id.in_(upd_groups)).all()} no_exist_groups = upd_groups - db_groups if no_exist_groups: raise ObjectNotFound(type=type(Group), ids=list(no_exist_groups)) - upd_lecturers = set(event_upd_data.get("lecturer_id")) db_lecturers = {lecturer.id for lecturer in db.session.query(Lecturer).filter(Lecturer.id.in_(upd_lecturers)).all()} no_exist_lecturers = upd_lecturers - db_lecturers if no_exist_lecturers: raise ObjectNotFound(type=type(Lecturer), ids=list(no_exist_lecturers)) - def add_new_remove_old_ids(dbsession, event_id, artefact: str, event_instance, negotiator_instance) -> None: """Вспомогательная фукнция описывающая удаление старых и добавление новых (room_, group_, lecturer_)*id - артефактов""" # получаем множество артефактов события