From 5f948878a84ab01982f271cd17e128acfd12e8dd Mon Sep 17 00:00:00 2001 From: rookiestar28 Date: Thu, 23 Apr 2026 23:37:06 +0800 Subject: [PATCH] refactor(imports): consolidate hotspot fallback helpers --- api/presets.py | 58 ++++++++----- api/tools.py | 69 ++++++++------- api/webhook.py | 97 ++++++++++++++-------- services/surface_guard.py | 25 ++++-- tests/test_r170_import_fallback_cleanup.py | 44 ++++++++++ 5 files changed, 196 insertions(+), 97 deletions(-) create mode 100644 tests/test_r170_import_fallback_cleanup.py diff --git a/api/presets.py b/api/presets.py index b583a01..91374ad 100644 --- a/api/presets.py +++ b/api/presets.py @@ -8,29 +8,41 @@ import os import time from typing import Optional -try: - from ..services.access_control import require_admin_token, resolve_token_info - from ..services.aiohttp_compat import import_aiohttp_web - from ..services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) - from ..services.presets import Preset, preset_store - from ..services.tenant_context import TenantBoundaryError, request_tenant_scope -except ImportError: - # Fallback for ComfyUI's non-package loader or ad-hoc imports. - from services.access_control import require_admin_token, resolve_token_info - from services.aiohttp_compat import import_aiohttp_web - from services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) - from services.presets import Preset, preset_store - from services.tenant_context import TenantBoundaryError, request_tenant_scope +if __package__ and "." in __package__: + from ..services.import_fallback import import_attrs_dual +else: + from services.import_fallback import import_attrs_dual # type: ignore + +(require_admin_token, resolve_token_info) = import_attrs_dual( + __package__, + "..services.access_control", + "services.access_control", + ("require_admin_token", "resolve_token_info"), +) +(import_aiohttp_web,) = import_attrs_dual( + __package__, + "..services.aiohttp_compat", + "services.aiohttp_compat", + ("import_aiohttp_web",), +) +(AuthTier, RiskTier, RoutePlane, endpoint_metadata) = import_attrs_dual( + __package__, + "..services.endpoint_manifest", + "services.endpoint_manifest", + ("AuthTier", "RiskTier", "RoutePlane", "endpoint_metadata"), +) +(Preset, preset_store) = import_attrs_dual( + __package__, + "..services.presets", + "services.presets", + ("Preset", "preset_store"), +) +(TenantBoundaryError, request_tenant_scope) = import_attrs_dual( + __package__, + "..services.tenant_context", + "services.tenant_context", + ("TenantBoundaryError", "request_tenant_scope"), +) logger = logging.getLogger("ComfyUI-OpenClaw.api.presets") web = import_aiohttp_web() diff --git a/api/tools.py b/api/tools.py index 917d698..11bdc7d 100644 --- a/api/tools.py +++ b/api/tools.py @@ -8,33 +8,47 @@ from __future__ import annotations import json import logging -try: - from ..services.access_control import require_admin_token, resolve_token_info - from ..services.aiohttp_compat import import_aiohttp_web - from ..services.audit import emit_audit_event - from ..services.tool_runner import get_tool_runner, is_tools_enabled -except ImportError: - from services.access_control import require_admin_token # type: ignore - from services.access_control import resolve_token_info # type: ignore - from services.aiohttp_compat import import_aiohttp_web # type: ignore - from services.audit import emit_audit_event # type: ignore - from services.tool_runner import get_tool_runner, is_tools_enabled - -# R98: Endpoint Metadata if __package__ and "." in __package__: - from ..services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) + from ..services.import_fallback import import_attrs_dual else: - from services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) + from services.import_fallback import import_attrs_dual # type: ignore + +(require_admin_token, resolve_token_info) = import_attrs_dual( + __package__, + "..services.access_control", + "services.access_control", + ("require_admin_token", "resolve_token_info"), +) +(import_aiohttp_web,) = import_attrs_dual( + __package__, + "..services.aiohttp_compat", + "services.aiohttp_compat", + ("import_aiohttp_web",), +) +(emit_audit_event,) = import_attrs_dual( + __package__, + "..services.audit", + "services.audit", + ("emit_audit_event",), +) +(get_tool_runner, is_tools_enabled) = import_attrs_dual( + __package__, + "..services.tool_runner", + "services.tool_runner", + ("get_tool_runner", "is_tools_enabled"), +) +(AuthTier, RiskTier, RoutePlane, endpoint_metadata) = import_attrs_dual( + __package__, + "..services.endpoint_manifest", + "services.endpoint_manifest", + ("AuthTier", "RiskTier", "RoutePlane", "endpoint_metadata"), +) +(check_surface,) = import_attrs_dual( + __package__, + "..services.surface_guard", + "services.surface_guard", + ("check_surface",), +) logger = logging.getLogger("ComfyUI-OpenClaw.api.tools") web = import_aiohttp_web() @@ -87,11 +101,6 @@ async def tools_run_handler(request: web.Request) -> web.Response: Requires: Admin Token. """ # S62: Block tool execution in public+split mode - try: - # CRITICAL: package-relative import must stay first in ComfyUI runtime. - from ..services.surface_guard import check_surface - except ImportError: - from services.surface_guard import check_surface # type: ignore blocked = check_surface("tool_execution", request) if blocked: return blocked diff --git a/api/webhook.py b/api/webhook.py index 043d5e0..960578c 100644 --- a/api/webhook.py +++ b/api/webhook.py @@ -14,43 +14,68 @@ from __future__ import annotations import json import logging -try: - from .errors import APIError, ErrorCode, create_error_response -except ImportError: - # Build-time / Test fallback - from api.errors import APIError, ErrorCode, create_error_response +if __package__ and "." in __package__: + from ..services.import_fallback import import_attrs_dual +else: + from services.import_fallback import import_attrs_dual # type: ignore -try: - from ..models.schemas import MAX_BODY_SIZE, WebhookJobRequest - from ..services.aiohttp_compat import import_aiohttp_web - from ..services.metrics import metrics - from ..services.rate_limit import build_rate_limit_response, check_rate_limit - from ..services.trace import get_effective_trace_id - from ..services.webhook_auth import get_auth_summary, require_auth -except ImportError: - from models.schemas import MAX_BODY_SIZE, WebhookJobRequest - from services.aiohttp_compat import import_aiohttp_web # type: ignore - from services.metrics import metrics - from services.rate_limit import build_rate_limit_response, check_rate_limit - from services.trace import get_effective_trace_id - from services.webhook_auth import get_auth_summary, require_auth - -try: - from ..services.diagnostics_flags import diagnostics - from ..services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) -except ImportError: - from services.diagnostics_flags import diagnostics - from services.endpoint_manifest import ( - AuthTier, - RiskTier, - RoutePlane, - endpoint_metadata, - ) +(APIError, ErrorCode, create_error_response) = import_attrs_dual( + __package__, + ".errors", + "api.errors", + ("APIError", "ErrorCode", "create_error_response"), +) +( + MAX_BODY_SIZE, + WebhookJobRequest, +) = import_attrs_dual( + __package__, + "..models.schemas", + "models.schemas", + ("MAX_BODY_SIZE", "WebhookJobRequest"), +) +(import_aiohttp_web,) = import_attrs_dual( + __package__, + "..services.aiohttp_compat", + "services.aiohttp_compat", + ("import_aiohttp_web",), +) +(metrics,) = import_attrs_dual( + __package__, + "..services.metrics", + "services.metrics", + ("metrics",), +) +(build_rate_limit_response, check_rate_limit) = import_attrs_dual( + __package__, + "..services.rate_limit", + "services.rate_limit", + ("build_rate_limit_response", "check_rate_limit"), +) +(get_effective_trace_id,) = import_attrs_dual( + __package__, + "..services.trace", + "services.trace", + ("get_effective_trace_id",), +) +(get_auth_summary, require_auth) = import_attrs_dual( + __package__, + "..services.webhook_auth", + "services.webhook_auth", + ("get_auth_summary", "require_auth"), +) +(diagnostics,) = import_attrs_dual( + __package__, + "..services.diagnostics_flags", + "services.diagnostics_flags", + ("diagnostics",), +) +(AuthTier, RiskTier, RoutePlane, endpoint_metadata) = import_attrs_dual( + __package__, + "..services.endpoint_manifest", + "services.endpoint_manifest", + ("AuthTier", "RiskTier", "RoutePlane", "endpoint_metadata"), +) # R46: Scoped logger for safe-by-default redaction logger = diagnostics.get_logger("ComfyUI-OpenClaw.api.webhook", "webhook") diff --git a/services/surface_guard.py b/services/surface_guard.py index f560599..4c1b3e7 100644 --- a/services/surface_guard.py +++ b/services/surface_guard.py @@ -15,10 +15,17 @@ from __future__ import annotations import logging import os -try: - from .aiohttp_compat import import_aiohttp_web -except ImportError: - from aiohttp_compat import import_aiohttp_web # type: ignore +if __package__ and "." in __package__: + from ..services.import_fallback import import_attrs_dual +else: + from services.import_fallback import import_attrs_dual # type: ignore + +(import_aiohttp_web,) = import_attrs_dual( + __package__, + ".aiohttp_compat", + "services.aiohttp_compat", + ("import_aiohttp_web",), +) web = import_aiohttp_web() @@ -30,10 +37,12 @@ def _is_fail_closed_profile() -> bool: profile = os.environ.get("OPENCLAW_DEPLOYMENT_PROFILE", "local").lower() if profile == "public": return True - try: - from .runtime_profile import is_hardened_mode - except ImportError: - from runtime_profile import is_hardened_mode # type: ignore + (is_hardened_mode,) = import_attrs_dual( + __package__, + ".runtime_profile", + "services.runtime_profile", + ("is_hardened_mode",), + ) return bool(is_hardened_mode()) diff --git a/tests/test_r170_import_fallback_cleanup.py b/tests/test_r170_import_fallback_cleanup.py new file mode 100644 index 0000000..d6d96e9 --- /dev/null +++ b/tests/test_r170_import_fallback_cleanup.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from pathlib import Path +import unittest + + +REPO_ROOT = Path(__file__).resolve().parents[1] + +TARGETS = { + "api/webhook.py": { + "must_contain": ("import_attrs_dual",), + "must_not_contain": ("except ImportError",), + }, + "api/presets.py": { + "must_contain": ("import_attrs_dual",), + "must_not_contain": ("except ImportError",), + }, + "api/tools.py": { + "must_contain": ("import_attrs_dual", "check_surface"), + "must_not_contain": ("except ImportError",), + }, + "services/surface_guard.py": { + "must_contain": ("import_attrs_dual",), + "must_not_contain": ( + "from aiohttp_compat import import_aiohttp_web", + "from runtime_profile import is_hardened_mode", + ), + }, +} + + +class TestR170ImportFallbackCleanup(unittest.TestCase): + def test_target_modules_use_shared_import_fallback_helpers(self): + for rel_path, expectations in TARGETS.items(): + with self.subTest(path=rel_path): + text = (REPO_ROOT / rel_path).read_text(encoding="utf-8") + for needle in expectations["must_contain"]: + self.assertIn(needle, text) + for needle in expectations["must_not_contain"]: + self.assertNotIn(needle, text) + + +if __name__ == "__main__": + unittest.main()