dev #12
|
|
@ -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 рекомендуется запускать команды именно в этом порядке, чтобы быстрее находить проблемы.
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue