From f234e60e6549da1a7d7a63921c0c71c46112c703 Mon Sep 17 00:00:00 2001 From: Artem Kashaev Date: Mon, 1 Dec 2025 16:35:09 +0500 Subject: [PATCH] refactor: reorganize import statements for consistency across multiple files --- README.md | 1 - app/core/cache.py | 3 +-- app/core/database.py | 3 +-- app/core/middleware/cache_monitor.py | 3 +-- app/core/security.py | 3 +-- app/models/activity.py | 6 ++++-- app/models/deal.py | 3 ++- app/models/organization_member.py | 3 ++- app/services/task_service.py | 4 ++++ pyproject.toml | 8 -------- tests/api/v1/conftest.py | 5 ++--- tests/api/v1/task_activity_shared.py | 3 +-- tests/api/v1/test_activities.py | 3 +-- tests/api/v1/test_analytics.py | 5 ++--- tests/api/v1/test_auth.py | 7 +++---- tests/api/v1/test_contacts.py | 7 +++---- tests/api/v1/test_deals.py | 5 ++--- tests/api/v1/test_organizations.py | 9 ++++----- tests/api/v1/test_tasks.py | 3 +-- tests/services/test_activity_service.py | 5 ++--- tests/services/test_analytics_service.py | 5 ++--- tests/services/test_auth_service.py | 3 +-- tests/services/test_contact_service.py | 7 +++---- tests/services/test_deal_service.py | 7 +++---- tests/services/test_organization_service.py | 3 +-- tests/services/test_task_service.py | 7 +++---- 26 files changed, 50 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index c24fb4f..b9a01dd 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,6 @@ uvx pytest - `uv run ruff check app tests` — основной линтер (PEP8, сортировка импортов, дополнительные правила). - `uv run ruff format app tests` — автоформатирование (аналог black) для единообразного стиля. -- `uv run isort .` — отдельная сортировка импортов (профиль `black`). - `uv run mypy app services tests` — статическая проверка типов (строгий режим + плагин pydantic). В CI/PR рекомендуется запускать команды именно в этом порядке, чтобы быстрее находить проблемы. diff --git a/app/core/cache.py b/app/core/cache.py index 1ddf7e4..8dd004b 100644 --- a/app/core/cache.py +++ b/app/core/cache.py @@ -9,11 +9,10 @@ from collections.abc import Awaitable, Callable from typing import Any import redis.asyncio as redis +from app.core.config import settings from redis.asyncio.client import Redis from redis.exceptions import RedisError -from app.core.config import settings - logger = logging.getLogger(__name__) diff --git a/app/core/database.py b/app/core/database.py index 063090e..b80f051 100644 --- a/app/core/database.py +++ b/app/core/database.py @@ -4,9 +4,8 @@ from __future__ import annotations from collections.abc import AsyncGenerator -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine - from app.core.config import settings +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine engine = create_async_engine(settings.database_url, echo=settings.sqlalchemy_echo) AsyncSessionMaker = async_sessionmaker(bind=engine, expire_on_commit=False) diff --git a/app/core/middleware/cache_monitor.py b/app/core/middleware/cache_monitor.py index 5ea57be..7fb1b0f 100644 --- a/app/core/middleware/cache_monitor.py +++ b/app/core/middleware/cache_monitor.py @@ -4,10 +4,9 @@ from __future__ import annotations import logging -from starlette.types import ASGIApp, Receive, Scope, Send - from app.core.cache import cache_manager from app.core.config import settings +from starlette.types import ASGIApp, Receive, Scope, Send logger = logging.getLogger(__name__) diff --git a/app/core/security.py b/app/core/security.py index 23b61f0..e2daf66 100644 --- a/app/core/security.py +++ b/app/core/security.py @@ -7,9 +7,8 @@ from datetime import datetime, timedelta, timezone from typing import Any import jwt -from passlib.context import CryptContext # type: ignore - from app.core.config import settings +from passlib.context import CryptContext # type: ignore class PasswordHasher: diff --git a/app/models/activity.py b/app/models/activity.py index e62f4d8..f344c70 100644 --- a/app/models/activity.py +++ b/app/models/activity.py @@ -7,10 +7,12 @@ from enum import StrEnum from typing import Any from pydantic import BaseModel, ConfigDict, Field -from sqlalchemy import DateTime, Enum as SqlEnum, ForeignKey, Integer, func, text +from sqlalchemy import DateTime, ForeignKey, Integer, func, text +from sqlalchemy import Enum as SqlEnum from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column, relationship -from sqlalchemy.types import JSON as SA_JSON, TypeDecorator +from sqlalchemy.types import JSON as SA_JSON +from sqlalchemy.types import TypeDecorator from app.models.base import Base, enum_values diff --git a/app/models/deal.py b/app/models/deal.py index c55c130..48b0ac4 100644 --- a/app/models/deal.py +++ b/app/models/deal.py @@ -7,7 +7,8 @@ from decimal import Decimal from enum import StrEnum from pydantic import BaseModel, ConfigDict -from sqlalchemy import DateTime, Enum as SqlEnum, ForeignKey, Integer, Numeric, String, func +from sqlalchemy import DateTime, ForeignKey, Integer, Numeric, String, func +from sqlalchemy import Enum as SqlEnum from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base, enum_values diff --git a/app/models/organization_member.py b/app/models/organization_member.py index 3314b2e..79ab7e1 100644 --- a/app/models/organization_member.py +++ b/app/models/organization_member.py @@ -6,7 +6,8 @@ from datetime import datetime from enum import StrEnum from pydantic import BaseModel, ConfigDict -from sqlalchemy import DateTime, Enum as SqlEnum, ForeignKey, Integer, UniqueConstraint, func +from sqlalchemy import DateTime, ForeignKey, Integer, UniqueConstraint, func +from sqlalchemy import Enum as SqlEnum from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base, enum_values diff --git a/app/services/task_service.py b/app/services/task_service.py index a6e0ba4..a95b764 100644 --- a/app/services/task_service.py +++ b/app/services/task_service.py @@ -13,7 +13,11 @@ from app.models.task import Task, TaskCreate from app.repositories.activity_repo import ActivityOrganizationMismatchError, ActivityRepository from app.repositories.task_repo import ( TaskAccessError as RepoTaskAccessError, +) +from app.repositories.task_repo import ( TaskOrganizationMismatchError as RepoTaskOrganizationMismatchError, +) +from app.repositories.task_repo import ( TaskQueryParams, TaskRepository, ) diff --git a/pyproject.toml b/pyproject.toml index 24bea47..56498cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,14 +25,6 @@ dev = [ "aiosqlite>=0.20.0", ] -[tool.isort] -profile = "black" -line_length = 100 -combine_as_imports = true -default_section = "THIRDPARTY" -known_first_party = ["app", "tests"] -skip_glob = ["migrations/*"] - [tool.mypy] python_version = "3.14" plugins = ["pydantic.mypy"] diff --git a/tests/api/v1/conftest.py b/tests/api/v1/conftest.py index a2d6953..59f39d1 100644 --- a/tests/api/v1/conftest.py +++ b/tests/api/v1/conftest.py @@ -6,13 +6,12 @@ from collections.abc import AsyncGenerator import pytest import pytest_asyncio -from httpx import ASGITransport, AsyncClient -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine - from app.api.deps import get_cache_backend, get_db_session from app.core.security import password_hasher from app.main import create_app from app.models import Base +from httpx import ASGITransport, AsyncClient +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from tests.utils.fake_redis import InMemoryRedis diff --git a/tests/api/v1/task_activity_shared.py b/tests/api/v1/task_activity_shared.py index 35d24b0..d7896c5 100644 --- a/tests/api/v1/task_activity_shared.py +++ b/tests/api/v1/task_activity_shared.py @@ -5,14 +5,13 @@ from __future__ import annotations from dataclasses import dataclass from datetime import timedelta -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - from app.core.security import jwt_service from app.models.contact import Contact from app.models.deal import Deal from app.models.organization import Organization from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker @dataclass(slots=True) diff --git a/tests/api/v1/test_activities.py b/tests/api/v1/test_activities.py index 27cfe66..ca9b0ca 100644 --- a/tests/api/v1/test_activities.py +++ b/tests/api/v1/test_activities.py @@ -5,10 +5,9 @@ from __future__ import annotations from datetime import datetime, timedelta, timezone import pytest +from app.models.activity import Activity, ActivityType from httpx import AsyncClient from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - -from app.models.activity import Activity, ActivityType from tests.api.v1.task_activity_shared import auth_headers, make_token, prepare_scenario diff --git a/tests/api/v1/test_analytics.py b/tests/api/v1/test_analytics.py index 2312412..f3f3078 100644 --- a/tests/api/v1/test_analytics.py +++ b/tests/api/v1/test_analytics.py @@ -7,15 +7,14 @@ from datetime import datetime, timedelta, timezone from decimal import Decimal import pytest -from httpx import AsyncClient -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - from app.core.security import jwt_service from app.models.contact import Contact from app.models.deal import Deal, DealStage, DealStatus from app.models.organization import Organization from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User +from httpx import AsyncClient +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker @dataclass(slots=True) diff --git a/tests/api/v1/test_auth.py b/tests/api/v1/test_auth.py index 7194527..6d4b25b 100644 --- a/tests/api/v1/test_auth.py +++ b/tests/api/v1/test_auth.py @@ -3,14 +3,13 @@ from __future__ import annotations import pytest -from httpx import AsyncClient -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - from app.core.security import password_hasher from app.models.organization import Organization from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User +from httpx import AsyncClient +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker @pytest.mark.asyncio diff --git a/tests/api/v1/test_contacts.py b/tests/api/v1/test_contacts.py index bafa062..e0377ee 100644 --- a/tests/api/v1/test_contacts.py +++ b/tests/api/v1/test_contacts.py @@ -3,13 +3,12 @@ from __future__ import annotations import pytest -from httpx import AsyncClient -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - from app.models.contact import Contact from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User +from httpx import AsyncClient +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from tests.api.v1.task_activity_shared import auth_headers, make_token, prepare_scenario diff --git a/tests/api/v1/test_deals.py b/tests/api/v1/test_deals.py index 74b0a06..366008a 100644 --- a/tests/api/v1/test_deals.py +++ b/tests/api/v1/test_deals.py @@ -5,12 +5,11 @@ from __future__ import annotations from decimal import Decimal import pytest +from app.models.activity import Activity, ActivityType +from app.models.deal import Deal, DealStage, DealStatus from httpx import AsyncClient from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - -from app.models.activity import Activity, ActivityType -from app.models.deal import Deal, DealStage, DealStatus from tests.api.v1.task_activity_shared import auth_headers, make_token, prepare_scenario diff --git a/tests/api/v1/test_organizations.py b/tests/api/v1/test_organizations.py index 34cc440..ec27e8d 100644 --- a/tests/api/v1/test_organizations.py +++ b/tests/api/v1/test_organizations.py @@ -8,11 +8,6 @@ from typing import cast import pytest import pytest_asyncio -from httpx import ASGITransport, AsyncClient -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.schema import Table - from app.api.deps import get_db_session from app.core.security import jwt_service from app.main import create_app @@ -20,6 +15,10 @@ from app.models import Base from app.models.organization import Organization from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User +from httpx import ASGITransport, AsyncClient +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.schema import Table @pytest_asyncio.fixture() diff --git a/tests/api/v1/test_tasks.py b/tests/api/v1/test_tasks.py index f2c4008..f2b9176 100644 --- a/tests/api/v1/test_tasks.py +++ b/tests/api/v1/test_tasks.py @@ -5,10 +5,9 @@ from __future__ import annotations from datetime import datetime, timedelta, timezone import pytest +from app.models.task import Task from httpx import AsyncClient from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker - -from app.models.task import Task from tests.api.v1.task_activity_shared import ( auth_headers, create_deal, diff --git a/tests/services/test_activity_service.py b/tests/services/test_activity_service.py index 88ca3c7..107e2fa 100644 --- a/tests/services/test_activity_service.py +++ b/tests/services/test_activity_service.py @@ -7,9 +7,6 @@ from collections.abc import AsyncGenerator import pytest import pytest_asyncio -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.pool import StaticPool - from app.models.activity import Activity, ActivityType from app.models.base import Base from app.models.contact import Contact @@ -25,6 +22,8 @@ from app.services.activity_service import ( ActivityValidationError, ) from app.services.organization_service import OrganizationContext +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.pool import StaticPool @pytest_asyncio.fixture() diff --git a/tests/services/test_analytics_service.py b/tests/services/test_analytics_service.py index 1db84cc..93512ba 100644 --- a/tests/services/test_analytics_service.py +++ b/tests/services/test_analytics_service.py @@ -8,9 +8,6 @@ from decimal import Decimal import pytest import pytest_asyncio -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.pool import StaticPool - from app.models import Base from app.models.contact import Contact from app.models.deal import Deal, DealStage, DealStatus @@ -19,6 +16,8 @@ from app.models.organization_member import OrganizationMember, OrganizationRole from app.models.user import User from app.repositories.analytics_repo import AnalyticsRepository from app.services.analytics_service import AnalyticsService, invalidate_analytics_cache +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.pool import StaticPool from tests.utils.fake_redis import InMemoryRedis diff --git a/tests/services/test_auth_service.py b/tests/services/test_auth_service.py index 8a86635..5a23a58 100644 --- a/tests/services/test_auth_service.py +++ b/tests/services/test_auth_service.py @@ -6,12 +6,11 @@ from typing import cast from unittest.mock import MagicMock import pytest # type: ignore[import-not-found] -from sqlalchemy.ext.asyncio import AsyncSession - from app.core.security import JWTService, PasswordHasher from app.models.user import User from app.repositories.user_repo import UserRepository from app.services.auth_service import AuthService, InvalidCredentialsError, InvalidRefreshTokenError +from sqlalchemy.ext.asyncio import AsyncSession class StubUserRepository(UserRepository): diff --git a/tests/services/test_contact_service.py b/tests/services/test_contact_service.py index 66122a0..6a9046f 100644 --- a/tests/services/test_contact_service.py +++ b/tests/services/test_contact_service.py @@ -7,10 +7,6 @@ from collections.abc import AsyncGenerator import pytest import pytest_asyncio -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.pool import StaticPool - from app.models.base import Base from app.models.contact import Contact, ContactCreate from app.models.deal import Deal @@ -26,6 +22,9 @@ from app.services.contact_service import ( ContactUpdateData, ) from app.services.organization_service import OrganizationContext +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.pool import StaticPool @pytest_asyncio.fixture() diff --git a/tests/services/test_deal_service.py b/tests/services/test_deal_service.py index 3fca4a2..11d525d 100644 --- a/tests/services/test_deal_service.py +++ b/tests/services/test_deal_service.py @@ -8,10 +8,6 @@ from decimal import Decimal import pytest # type: ignore[import-not-found] import pytest_asyncio # type: ignore[import-not-found] -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.pool import StaticPool - from app.models.activity import Activity, ActivityType from app.models.base import Base from app.models.contact import Contact @@ -29,6 +25,9 @@ from app.services.deal_service import ( DealUpdateData, ) from app.services.organization_service import OrganizationContext +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.pool import StaticPool @pytest_asyncio.fixture() diff --git a/tests/services/test_organization_service.py b/tests/services/test_organization_service.py index 28dc604..73bf21c 100644 --- a/tests/services/test_organization_service.py +++ b/tests/services/test_organization_service.py @@ -6,8 +6,6 @@ from typing import cast from unittest.mock import MagicMock import pytest # type: ignore[import-not-found] -from sqlalchemy.ext.asyncio import AsyncSession - from app.models.organization import Organization from app.models.organization_member import OrganizationMember, OrganizationRole from app.repositories.org_repo import OrganizationRepository @@ -19,6 +17,7 @@ from app.services.organization_service import ( OrganizationMemberAlreadyExistsError, OrganizationService, ) +from sqlalchemy.ext.asyncio import AsyncSession class StubOrganizationRepository(OrganizationRepository): diff --git a/tests/services/test_task_service.py b/tests/services/test_task_service.py index 578a360..e667519 100644 --- a/tests/services/test_task_service.py +++ b/tests/services/test_task_service.py @@ -8,10 +8,6 @@ from datetime import datetime, timedelta, timezone import pytest import pytest_asyncio -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.pool import StaticPool - from app.models.activity import Activity, ActivityType from app.models.base import Base from app.models.contact import Contact @@ -29,6 +25,9 @@ from app.services.task_service import ( TaskService, TaskUpdateData, ) +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.pool import StaticPool @pytest_asyncio.fixture()