diff --git a/app/api/security.py b/app/api/security.py index 4637994..1b2ef91 100644 --- a/app/api/security.py +++ b/app/api/security.py @@ -18,14 +18,12 @@ runs in production - not a replacement. from __future__ import annotations import hmac -from typing import Awaitable, Callable +from collections.abc import Awaitable, Callable from fastapi import FastAPI, Request, Response from fastapi.responses import JSONResponse from starlette.types import ASGIApp -from app.config import settings as _module_settings - EXEMPT_PATHS: tuple[str, ...] = ("/", "/docs", "/redoc", "/openapi.json") EXEMPT_SUFFIXES: tuple[str, ...] = ("/health",) diff --git a/app/indexing/embeddings.py b/app/indexing/embeddings.py index 3aa1c75..a55246c 100644 --- a/app/indexing/embeddings.py +++ b/app/indexing/embeddings.py @@ -7,8 +7,8 @@ implementation and supports dense + sparse output. We fall back to from __future__ import annotations +from collections.abc import Sequence from functools import lru_cache -from typing import Sequence import numpy as np diff --git a/app/indexing/opensearch_client.py b/app/indexing/opensearch_client.py index cb7fc4e..91e2240 100644 --- a/app/indexing/opensearch_client.py +++ b/app/indexing/opensearch_client.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Iterable from functools import lru_cache -from typing import Any, Iterable +from typing import Any from opensearchpy import OpenSearch, RequestsHttpConnection from opensearchpy.helpers import bulk diff --git a/app/indexing/qdrant_client.py b/app/indexing/qdrant_client.py index 77eca7b..d3ba14e 100644 --- a/app/indexing/qdrant_client.py +++ b/app/indexing/qdrant_client.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Sequence from functools import lru_cache -from typing import Any, Sequence +from typing import Any from qdrant_client import QdrantClient from qdrant_client.http import models as qm diff --git a/app/indexing/reranker.py b/app/indexing/reranker.py index f127ed4..c6f1781 100644 --- a/app/indexing/reranker.py +++ b/app/indexing/reranker.py @@ -7,8 +7,8 @@ Designed to degrade gracefully: from __future__ import annotations +from collections.abc import Sequence from functools import lru_cache -from typing import Sequence from app.config import settings from app.logging_config import get_logger diff --git a/app/ingestion/chunker.py b/app/ingestion/chunker.py index 1761d2d..a62bd2c 100644 --- a/app/ingestion/chunker.py +++ b/app/ingestion/chunker.py @@ -20,7 +20,6 @@ from typing import Any from app.config import settings from app.ingestion.docling_extractor import ( ExtractedBlock, - ExtractedFigure, ExtractedTable, ExtractionResult, ) diff --git a/app/logging_config.py b/app/logging_config.py index d06e564..9b3f152 100644 --- a/app/logging_config.py +++ b/app/logging_config.py @@ -29,8 +29,7 @@ def configure_logging() -> None: ] structlog.configure( - processors=shared_processors - + [structlog.stdlib.ProcessorFormatter.wrap_for_formatter], + processors=[*shared_processors, structlog.stdlib.ProcessorFormatter.wrap_for_formatter], logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, diff --git a/app/main.py b/app/main.py index 698c295..ca887c5 100644 --- a/app/main.py +++ b/app/main.py @@ -2,8 +2,8 @@ from __future__ import annotations +from collections.abc import AsyncIterator from contextlib import asynccontextmanager -from typing import AsyncIterator from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware diff --git a/pyproject.toml b/pyproject.toml index 38897e7..1165cf6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,7 +90,16 @@ target-version = "py311" [tool.ruff.lint] select = ["E", "F", "I", "B", "UP", "N", "PL", "RUF"] -ignore = ["E501", "PLR0913", "PLR2004"] +ignore = [ + "E501", + "PLC0415", # optional/heavy imports are intentionally lazy in runtime and tests + "PLR0913", + "PLR2004", + "PLW0603", # lazy DB/session singletons are explicit module state + "RUF001", # Russian OCR/test strings intentionally contain Cyrillic characters + "RUF002", + "RUF100", # keep explanatory noqa markers for rules not enabled locally +] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/scripts/benchmark_reranker.py b/scripts/benchmark_reranker.py index 9466eda..c0e53c2 100644 --- a/scripts/benchmark_reranker.py +++ b/scripts/benchmark_reranker.py @@ -57,7 +57,7 @@ def percentile(values: list[float], q: float) -> float: if not values: return 0.0 s = sorted(values) - idx = max(0, min(len(s) - 1, int(round((q / 100.0) * (len(s) - 1))))) + idx = max(0, min(len(s) - 1, round((q / 100.0) * (len(s) - 1)))) return s[idx] diff --git a/scripts/locustfile_search.py b/scripts/locustfile_search.py index d4ef22e..fab74df 100644 --- a/scripts/locustfile_search.py +++ b/scripts/locustfile_search.py @@ -20,7 +20,6 @@ import random from locust import HttpUser, between, task - QUERIES = [ "ГОСТ 21.501-93 рабочие чертежи", "класс бетона B25", diff --git a/tests/test_api_health.py b/tests/test_api_health.py index 60f206c..34ca0bb 100644 --- a/tests/test_api_health.py +++ b/tests/test_api_health.py @@ -13,7 +13,6 @@ Postgres / MinIO / OpenSearch / Qdrant / Redis. Verifies: from __future__ import annotations import pytest - from fastapi.testclient import TestClient from app.api.schemas import ComponentHealth diff --git a/tests/test_api_security.py b/tests/test_api_security.py index 4d086c4..5cd496c 100644 --- a/tests/test_api_security.py +++ b/tests/test_api_security.py @@ -5,10 +5,8 @@ from __future__ import annotations import importlib import pytest - from fastapi.testclient import TestClient - KEY = "test-secret-key-DO-NOT-USE-IN-PROD" @@ -82,9 +80,9 @@ def test_protected_route_rejects_missing_key(secured_app, monkeypatch): def test_protected_route_accepts_x_api_key_header(secured_app, monkeypatch): + from app.api.schemas import SearchResponse from app.config import settings from app.indexing import hybrid_search - from app.api.schemas import SearchResponse monkeypatch.setattr( hybrid_search, @@ -114,9 +112,9 @@ def test_protected_route_accepts_x_api_key_header(secured_app, monkeypatch): def test_protected_route_accepts_bearer_token(secured_app, monkeypatch): + from app.api.schemas import SearchResponse from app.config import settings from app.indexing import hybrid_search - from app.api.schemas import SearchResponse monkeypatch.setattr( hybrid_search, diff --git a/tests/test_routes_search.py b/tests/test_routes_search.py index 7cfa45b..e67eb90 100644 --- a/tests/test_routes_search.py +++ b/tests/test_routes_search.py @@ -10,7 +10,6 @@ from __future__ import annotations import uuid import pytest - from fastapi.testclient import TestClient from app.api.schemas import (