refactor: enforce PLC0415 (import-outside-top-level) for source code
Enable ruff PLC0415 rule for all source files (tests excluded via per-file-ignores). Move 136 inline imports to top-level across 33 files. 8 imports suppressed with noqa for legitimate reasons: circular dependencies (client/__init__.py, context.py), optional dependency guards (app.py document processors, auth/userinfo_routes.py), and post-env-setup imports (smithery_main.py). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
81efa6e263
commit
a11ae9c027
@@ -20,9 +20,15 @@ import time
|
||||
from importlib.metadata import version
|
||||
from typing import Any
|
||||
|
||||
from qdrant_client.models import Filter
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
from nextcloud_mcp_server.config_validators import AuthMode, detect_auth_mode
|
||||
from nextcloud_mcp_server.vector.placeholder import get_placeholder_filter
|
||||
from nextcloud_mcp_server.vector.qdrant_client import get_qdrant_client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -196,16 +202,12 @@ async def get_server_status(request: Request) -> JSONResponse:
|
||||
# Public endpoint - no authentication required
|
||||
|
||||
# Get configuration
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
# Calculate uptime
|
||||
uptime_seconds = int(time.time() - _server_start_time)
|
||||
|
||||
# Determine auth mode using proper mode detection
|
||||
from nextcloud_mcp_server.config_validators import AuthMode, detect_auth_mode
|
||||
|
||||
mode = detect_auth_mode(settings)
|
||||
|
||||
# Map deployment mode to auth_mode for API response
|
||||
@@ -266,8 +268,6 @@ async def get_vector_sync_status(request: Request) -> JSONResponse:
|
||||
"""
|
||||
# Public endpoint - no authentication required
|
||||
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
if not settings.vector_sync_enabled:
|
||||
return JSONResponse(
|
||||
@@ -299,11 +299,6 @@ async def get_vector_sync_status(request: Request) -> JSONResponse:
|
||||
# Get Qdrant client and query indexed count
|
||||
indexed_count = 0
|
||||
try:
|
||||
from qdrant_client.models import Filter
|
||||
|
||||
from nextcloud_mcp_server.vector.placeholder import get_placeholder_filter
|
||||
from nextcloud_mcp_server.vector.qdrant_client import get_qdrant_client
|
||||
|
||||
qdrant_client = await get_qdrant_client()
|
||||
|
||||
# Count documents in collection, excluding placeholders
|
||||
@@ -375,8 +370,6 @@ async def get_user_session(request: Request) -> JSONResponse:
|
||||
# Check if offline access is enabled
|
||||
# Use settings.enable_offline_access which handles both ENABLE_BACKGROUND_OPERATIONS (new)
|
||||
# and ENABLE_OFFLINE_ACCESS (deprecated) environment variables
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
enable_offline_access = settings.enable_offline_access
|
||||
|
||||
|
||||
@@ -15,18 +15,16 @@ import logging
|
||||
import re
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import httpx
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from ..http import nextcloud_httpx_client
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nextcloud_mcp_server.auth.storage import RefreshTokenStorage
|
||||
|
||||
from nextcloud_mcp_server.api.management import _sanitize_error_for_client
|
||||
from nextcloud_mcp_server.auth.storage import RefreshTokenStorage
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
from ..http import nextcloud_httpx_client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -158,7 +156,7 @@ def _extract_basic_auth(
|
||||
return username, password, None
|
||||
|
||||
|
||||
async def _get_app_password_storage(request: Request) -> "RefreshTokenStorage":
|
||||
async def _get_app_password_storage(request: Request) -> RefreshTokenStorage:
|
||||
"""Get or initialize RefreshTokenStorage for app password operations.
|
||||
|
||||
Checks app.state.storage first, then falls back to creating from environment.
|
||||
@@ -170,8 +168,6 @@ async def _get_app_password_storage(request: Request) -> "RefreshTokenStorage":
|
||||
Returns:
|
||||
Initialized RefreshTokenStorage instance
|
||||
"""
|
||||
from nextcloud_mcp_server.auth.storage import RefreshTokenStorage
|
||||
|
||||
storage = getattr(request.app.state, "storage", None)
|
||||
|
||||
if not storage:
|
||||
@@ -202,8 +198,6 @@ async def provision_app_password(request: Request) -> JSONResponse:
|
||||
- Only the user who owns the password can provision it
|
||||
- Rate limited to prevent brute-force attacks
|
||||
"""
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
# Get user_id from path
|
||||
path_user_id = request.path_params.get("user_id")
|
||||
if not path_user_id:
|
||||
@@ -364,8 +358,6 @@ async def delete_app_password(request: Request) -> JSONResponse:
|
||||
|
||||
Requires BasicAuth with the user's credentials.
|
||||
"""
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
# Get user_id from path
|
||||
path_user_id = request.path_params.get("user_id")
|
||||
if not path_user_id:
|
||||
|
||||
@@ -11,13 +11,10 @@ All endpoints require OAuth bearer token authentication via UnifiedTokenVerifier
|
||||
|
||||
import base64
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import Any
|
||||
|
||||
import pymupdf
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
from qdrant_client.models import FieldCondition, Filter, MatchValue
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
@@ -29,6 +26,17 @@ from nextcloud_mcp_server.api.management import (
|
||||
extract_bearer_token,
|
||||
validate_token_and_get_user,
|
||||
)
|
||||
from nextcloud_mcp_server.client import NextcloudClient
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
from nextcloud_mcp_server.embedding.service import get_embedding_service
|
||||
from nextcloud_mcp_server.search import (
|
||||
BM25HybridSearchAlgorithm,
|
||||
SemanticSearchAlgorithm,
|
||||
)
|
||||
from nextcloud_mcp_server.search.context import get_chunk_with_context
|
||||
from nextcloud_mcp_server.vector.placeholder import get_placeholder_filter
|
||||
from nextcloud_mcp_server.vector.qdrant_client import get_qdrant_client
|
||||
from nextcloud_mcp_server.vector.visualization import compute_pca_coordinates
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -68,8 +76,6 @@ async def unified_search(request: Request) -> JSONResponse:
|
||||
|
||||
Requires OAuth bearer token for user filtering.
|
||||
"""
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
if not settings.vector_sync_enabled:
|
||||
return JSONResponse(
|
||||
@@ -144,12 +150,6 @@ async def unified_search(request: Request) -> JSONResponse:
|
||||
if fusion not in valid_fusions:
|
||||
fusion = "rrf"
|
||||
|
||||
# Execute search using the appropriate algorithm
|
||||
from nextcloud_mcp_server.search import (
|
||||
BM25HybridSearchAlgorithm,
|
||||
SemanticSearchAlgorithm,
|
||||
)
|
||||
|
||||
# Select search algorithm
|
||||
if algorithm == "semantic":
|
||||
search_algo = SemanticSearchAlgorithm(score_threshold=score_threshold)
|
||||
@@ -254,17 +254,9 @@ async def unified_search(request: Request) -> JSONResponse:
|
||||
# Optional PCA coordinates
|
||||
if include_pca and len(paginated_results) >= 2:
|
||||
try:
|
||||
from nextcloud_mcp_server.vector.visualization import (
|
||||
compute_pca_coordinates,
|
||||
)
|
||||
|
||||
if search_algo.query_embedding is not None:
|
||||
query_embedding = search_algo.query_embedding
|
||||
else:
|
||||
from nextcloud_mcp_server.embedding.service import (
|
||||
get_embedding_service,
|
||||
)
|
||||
|
||||
embedding_service = get_embedding_service()
|
||||
query_embedding = await embedding_service.embed(query)
|
||||
|
||||
@@ -305,8 +297,6 @@ async def vector_search(request: Request) -> JSONResponse:
|
||||
|
||||
Requires OAuth bearer token for user filtering.
|
||||
"""
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
if not settings.vector_sync_enabled:
|
||||
return JSONResponse(
|
||||
@@ -354,12 +344,6 @@ async def vector_search(request: Request) -> JSONResponse:
|
||||
if fusion not in valid_fusions:
|
||||
fusion = "rrf"
|
||||
|
||||
# Execute search using the appropriate algorithm
|
||||
from nextcloud_mcp_server.search import (
|
||||
BM25HybridSearchAlgorithm,
|
||||
SemanticSearchAlgorithm,
|
||||
)
|
||||
|
||||
# Select search algorithm
|
||||
if algorithm == "semantic":
|
||||
search_algo = SemanticSearchAlgorithm(score_threshold=score_threshold)
|
||||
@@ -428,18 +412,10 @@ async def vector_search(request: Request) -> JSONResponse:
|
||||
# Compute PCA coordinates for visualization using shared function
|
||||
if include_pca and len(all_results) >= 2:
|
||||
try:
|
||||
from nextcloud_mcp_server.vector.visualization import (
|
||||
compute_pca_coordinates,
|
||||
)
|
||||
|
||||
# Get query embedding from search algorithm or generate it
|
||||
if search_algo.query_embedding is not None:
|
||||
query_embedding = search_algo.query_embedding
|
||||
else:
|
||||
from nextcloud_mcp_server.embedding.service import (
|
||||
get_embedding_service,
|
||||
)
|
||||
|
||||
embedding_service = get_embedding_service()
|
||||
query_embedding = await embedding_service.embed(query)
|
||||
|
||||
@@ -549,9 +525,6 @@ async def get_chunk_context(request: Request) -> JSONResponse:
|
||||
raise ValueError("Nextcloud host not configured")
|
||||
|
||||
# Initialize authenticated Nextcloud client
|
||||
from nextcloud_mcp_server.client import NextcloudClient
|
||||
from nextcloud_mcp_server.search.context import get_chunk_with_context
|
||||
|
||||
async with NextcloudClient.from_token(
|
||||
base_url=nextcloud_host, token=token, username=user_id
|
||||
) as nc_client:
|
||||
@@ -581,14 +554,6 @@ async def get_chunk_context(request: Request) -> JSONResponse:
|
||||
|
||||
if doc_type == "file":
|
||||
try:
|
||||
from qdrant_client.models import FieldCondition, Filter, MatchValue
|
||||
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
from nextcloud_mcp_server.vector.placeholder import (
|
||||
get_placeholder_filter,
|
||||
)
|
||||
from nextcloud_mcp_server.vector.qdrant_client import get_qdrant_client
|
||||
|
||||
settings = get_settings()
|
||||
qdrant_client = await get_qdrant_client()
|
||||
|
||||
@@ -735,8 +700,6 @@ async def get_pdf_preview(request: Request) -> JSONResponse:
|
||||
raise ValueError("Nextcloud host not configured")
|
||||
|
||||
# Download PDF via WebDAV using user's token
|
||||
from nextcloud_mcp_server.client import NextcloudClient
|
||||
|
||||
async with NextcloudClient.from_token(
|
||||
base_url=nextcloud_host, token=token, username=user_id
|
||||
) as nc_client:
|
||||
|
||||
@@ -18,6 +18,7 @@ from nextcloud_mcp_server.api.management import (
|
||||
extract_bearer_token,
|
||||
validate_token_and_get_user,
|
||||
)
|
||||
from nextcloud_mcp_server.client.webhooks import WebhooksClient
|
||||
|
||||
from ..http import nextcloud_httpx_client
|
||||
|
||||
@@ -115,8 +116,6 @@ async def list_webhooks(request: Request) -> JSONResponse:
|
||||
)
|
||||
|
||||
try:
|
||||
from nextcloud_mcp_server.client.webhooks import WebhooksClient
|
||||
|
||||
# Get Bearer token from request
|
||||
token = extract_bearer_token(request)
|
||||
if not token:
|
||||
@@ -180,8 +179,6 @@ async def create_webhook(request: Request) -> JSONResponse:
|
||||
)
|
||||
|
||||
try:
|
||||
from nextcloud_mcp_server.client.webhooks import WebhooksClient
|
||||
|
||||
# Parse request body
|
||||
body = await request.json()
|
||||
event = body.get("event")
|
||||
@@ -256,8 +253,6 @@ async def delete_webhook(request: Request) -> JSONResponse:
|
||||
)
|
||||
|
||||
try:
|
||||
from nextcloud_mcp_server.client.webhooks import WebhooksClient
|
||||
|
||||
# Get webhook_id from path parameter
|
||||
webhook_id = request.path_params.get("webhook_id")
|
||||
if not webhook_id:
|
||||
|
||||
Reference in New Issue
Block a user