refactor: use explicit system config getter

This commit is contained in:
jxxghp
2026-08-24 04:04:35 +08:00
parent 4dd2d7fed2
commit 8555d0da3e
28 changed files with 111 additions and 76 deletions
+4 -4
View File
@@ -23,7 +23,7 @@ import jwt
from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import LlmProviderAction, SystemConfigKey
from app.foundation.singleton import Singleton
@@ -1510,7 +1510,7 @@ class LLMProviderManager(metaclass=Singleton):
@staticmethod
def _read_agent_config() -> dict[str, Any]:
"""读取 AI Agent 配置信息。"""
config = SystemConfigOper().get(SystemConfigKey.AIAgentConfig)
config = get_configured_system_config().get(SystemConfigKey.AIAgentConfig)
if isinstance(config, dict):
return config
return {}
@@ -1520,10 +1520,10 @@ class LLMProviderManager(metaclass=Singleton):
"""
使用异步持久化写回 provider 鉴权配置。
`SystemConfigOper().get()` 读取的是内存缓存,这里保留同步调用;
`get_configured_system_config().get()` 读取的是内存缓存,这里保留同步调用;
但写入需要落库,因此统一走 `async_set()`。
"""
await SystemConfigOper().async_set(
await get_configured_system_config().async_set(
SystemConfigKey.AIAgentConfig,
copy.deepcopy(value) or None,
)
+3 -3
View File
@@ -12,7 +12,7 @@ from dataclasses import dataclass
from typing import Any, Optional
from urllib.parse import urljoin
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.agent import (
AgentMcpServerConfig,
@@ -456,7 +456,7 @@ class AgentMcpManager:
def get_servers(self) -> list[AgentMcpServerConfig]:
"""读取已保存的外部 MCP 服务器配置。"""
raw_servers = SystemConfigOper().get(SystemConfigKey.AIAgentMcpServers) or []
raw_servers = get_configured_system_config().get(SystemConfigKey.AIAgentMcpServers) or []
if not isinstance(raw_servers, list):
return []
servers: list[AgentMcpServerConfig] = []
@@ -470,7 +470,7 @@ class AgentMcpManager:
async def save_servers(self, servers: list[AgentMcpServerConfig]) -> bool:
"""保存外部 MCP 服务器配置。"""
normalized_servers = [self.normalize_server(server).model_dump() for server in servers]
return await SystemConfigOper().async_set(
return await get_configured_system_config().async_set(
SystemConfigKey.AIAgentMcpServers,
normalized_servers or None,
)
+7 -7
View File
@@ -6,7 +6,7 @@ from typing import Any, Dict, Iterable, Optional
from app.runtime.events import eventmanager
from app.application.agentdata import SubscribePort as SubscribeOper
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.application.rules import RuleHelper
from app.application.rules import RuleParser
from app.application.rules import BUILTIN_RULE_SET
@@ -252,13 +252,13 @@ async def collect_rule_group_usages(
"""收集规则组在全局配置和订阅上的引用情况。"""
target_names = set(group_names or [])
search_groups = set(
SystemConfigOper().get(SystemConfigKey.SearchFilterRuleGroups) or []
get_configured_system_config().get(SystemConfigKey.SearchFilterRuleGroups) or []
)
subscribe_groups = set(
SystemConfigOper().get(SystemConfigKey.SubscribeFilterRuleGroups) or []
get_configured_system_config().get(SystemConfigKey.SubscribeFilterRuleGroups) or []
)
best_version_groups = set(
SystemConfigOper().get(SystemConfigKey.BestVersionFilterRuleGroups) or []
get_configured_system_config().get(SystemConfigKey.BestVersionFilterRuleGroups) or []
)
usage_map = {
@@ -428,7 +428,7 @@ async def save_system_config(
]
normalized_value = normalized_value or None
success = await SystemConfigOper().async_set(key, normalized_value)
success = await get_configured_system_config().async_set(key, normalized_value)
if success:
await eventmanager.async_send_event(
etype=EventType.ConfigChanged,
@@ -475,7 +475,7 @@ async def rename_rule_group_references(old_name: str, new_name: str) -> dict:
SystemConfigKey.SubscribeFilterRuleGroups,
SystemConfigKey.BestVersionFilterRuleGroups,
):
original = SystemConfigOper().get(config_key) or []
original = get_configured_system_config().get(config_key) or []
updated = replace_group_name_in_list(original, old_name, new_name)
if updated != original:
await save_system_config(config_key, updated)
@@ -513,7 +513,7 @@ async def remove_rule_group_references(group_name: str) -> dict:
SystemConfigKey.SubscribeFilterRuleGroups,
SystemConfigKey.BestVersionFilterRuleGroups,
):
original = SystemConfigOper().get(config_key) or []
original = get_configured_system_config().get(config_key) or []
updated = [value for value in original if value != group_name]
if updated != original:
await save_system_config(config_key, updated)
+4 -4
View File
@@ -11,7 +11,7 @@ from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.plugin.runtime import get_plugin_manager
from app.application.plugin.install import PluginInstallCommand
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.adapters.external.server import MoviePilotServerHelper
from app.adapters.external.market import PluginHelper
from app.adapters.system.plugin.package import PluginPackageManager
@@ -327,7 +327,7 @@ async def install_plugin_runtime(
async def save_installed_plugins(plugin_ids: list[str]) -> object:
"""保存智能体安装用例确认后的插件列表。"""
return await SystemConfigOper().async_set(
return await get_configured_system_config().async_set(
SystemConfigKey.UserInstalledPlugins,
plugin_ids,
)
@@ -377,7 +377,7 @@ async def install_plugin_runtime(
return result
result = await PluginInstallCommand(
installed_plugins_reader=lambda: SystemConfigOper().get(
installed_plugins_reader=lambda: get_configured_system_config().get(
SystemConfigKey.UserInstalledPlugins
) or [],
installed_plugins_writer=save_installed_plugins,
@@ -422,7 +422,7 @@ async def uninstall_plugin_runtime(plugin_id: str) -> dict[str, Any]:
instance_ids = "".join(item.instance_id for item in source_instances)
raise ValueError(f"请先卸载该插件的分身:{instance_ids}")
config_oper = SystemConfigOper()
config_oper = get_configured_system_config()
install_plugins = config_oper.get(SystemConfigKey.UserInstalledPlugins) or []
if plugin_id in install_plugins:
install_plugins = [
@@ -7,7 +7,7 @@ from pydantic import BaseModel
from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import SystemConfigKey
@@ -39,7 +39,7 @@ class QueryCustomIdentifiersTool(MoviePilotTool):
@staticmethod
def _load_custom_identifiers():
"""从内存配置缓存中读取自定义识别词。"""
return SystemConfigOper().get(SystemConfigKey.CustomIdentifiers)
return get_configured_system_config().get(SystemConfigKey.CustomIdentifiers)
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
+2 -2
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel
from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import SystemConfigKey
@@ -34,7 +34,7 @@ class QueryDownloadersTool(MoviePilotTool):
@staticmethod
def _load_downloaders_config():
"""从内存配置缓存中读取下载器配置。"""
return SystemConfigOper().get(SystemConfigKey.Downloaders)
return get_configured_system_config().get(SystemConfigKey.Downloaders)
@staticmethod
def _sanitize_downloaders_config(downloaders_config: list) -> list:
@@ -17,7 +17,7 @@ from app.agent.tools.impl._system_setting_utils import (
)
from app.application.configuration import (
SystemConfigReader,
get_configured_system_config as SystemConfigOper,
get_configured_system_config,
get_runtime_settings,
)
from app.runtime.log import logger
@@ -103,7 +103,7 @@ class QuerySystemSettingsTool(MoviePilotTool):
def _get_system_config(self) -> SystemConfigReader:
"""返回显式注入端口,旧构造形态则延迟读取组合根服务。"""
return self._system_config or SystemConfigOper()
return self._system_config or get_configured_system_config()
async def _run_confirmed(self, **kwargs) -> str:
"""仅供宿主在消费有效确认后执行一次未脱敏读取。"""
+2 -2
View File
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag
from app.chain.search import SearchChain
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.application.site.sites import SitesHelper # pylint: disable=import-error,no-name-in-module
from app.runtime.log import logger
from app.schemas.types import MediaSource, MediaType, SystemConfigKey
@@ -63,7 +63,7 @@ class SearchTorrentsTool(MoviePilotTool):
@staticmethod
def _load_configured_sites() -> List[int]:
"""同步读取默认搜索站点列表。"""
return SystemConfigOper().get(SystemConfigKey.IndexerSites) or []
return get_configured_system_config().get(SystemConfigKey.IndexerSites) or []
async def run(self, media_source: MediaSource, media_id: str,
media_type: Optional[str] = None, area: Optional[str] = None,
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.agent.tools.tags import ToolTag
from app.domain.metainfo import clear_rust_parse_options_cache
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import SystemConfigKey
@@ -80,7 +80,7 @@ class UpdateCustomIdentifiersTool(MoviePilotTool):
# 过滤空字符串
identifiers = [i for i in identifiers if i is not None]
system_config_oper = SystemConfigOper()
system_config_oper = get_configured_system_config()
# 保存
value = identifiers if identifiers else None
@@ -19,7 +19,7 @@ from app.agent.tools.impl._system_setting_utils import (
from app.runtime.events import eventmanager
from app.application.configuration import (
SystemConfigService,
get_configured_system_config as SystemConfigOper,
get_configured_system_config,
get_runtime_settings,
)
from app.application.plugin.runtime import plugin_system_config_mutation
@@ -109,7 +109,7 @@ class UpdateSystemSettingsTool(MoviePilotTool):
def _get_system_config(self) -> SystemConfigService:
"""返回显式注入服务,旧构造形态则延迟读取组合根服务。"""
return self._system_config or SystemConfigOper()
return self._system_config or get_configured_system_config()
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据更新参数生成友好的提示消息。"""
+1 -9
View File
@@ -92,12 +92,6 @@ else:
"""返回快照字段,兼容整理链的响应转换。"""
return dict(self.__dict__)
# 旧测试与第三方扩展可能替换该名字;它现在只是应用配置端口的本地别名,
# 不再指向数据库 Oper。
SystemConfigOper = get_configured_system_config
_DEFAULT_SYSTEM_CONFIG_PROVIDER = get_configured_system_config
@dataclass(frozen=True, slots=True)
class _SubscribePostCommitContext:
"""订阅提交后副作用所需的不可变业务快照。"""
@@ -142,9 +136,7 @@ class _SubscribeCreateContext:
def _system_config():
"""返回配置端口,并兼容旧测试对本地别名的替换"""
if SystemConfigOper is not _DEFAULT_SYSTEM_CONFIG_PROVIDER:
return SystemConfigOper()
"""返回启动组合根登记的配置端口。"""
return get_configured_system_config()
+2 -2
View File
@@ -4,7 +4,7 @@ from typing import Tuple, List
from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import MediaType
from app.adapters.network.http import RequestUtils, AsyncRequestUtils
@@ -62,7 +62,7 @@ class HaiDanSpider:
return None
def __init__(self, indexer: dict):
self.systemconfig = SystemConfigOper()
self.systemconfig = get_configured_system_config()
if indexer:
self._indexerid = indexer.get('id')
self._url = indexer.get('domain')
+2 -2
View File
@@ -3,7 +3,7 @@ from typing import Tuple, List, Optional
from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import MediaType
from app.adapters.network.http import RequestUtils, AsyncRequestUtils
@@ -69,7 +69,7 @@ class HddolbySpider:
return cls._size
def __init__(self, indexer: dict):
self.systemconfig = SystemConfigOper()
self.systemconfig = get_configured_system_config()
if indexer:
self._indexerid = indexer.get('id')
self._domain = indexer.get('domain')
+2 -2
View File
@@ -7,7 +7,7 @@ from urllib.parse import urlparse
from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import MediaType
from app.adapters.network.http import RequestUtils, AsyncRequestUtils
@@ -67,7 +67,7 @@ class MTorrentSpider:
return cls._size
def __init__(self, indexer: dict):
self.systemconfig = SystemConfigOper()
self.systemconfig = get_configured_system_config()
if indexer:
self._indexerid = indexer.get('id')
self._url = indexer.get('domain')
+2 -2
View File
@@ -5,7 +5,7 @@ from typing import List, Optional, Tuple
from app.runtime.settings import RuntimeSettingsCompat
settings = RuntimeSettingsCompat()
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.runtime.log import logger
from app.schemas.types import MediaType
from app.adapters.network.http import RequestUtils, AsyncRequestUtils
@@ -51,7 +51,7 @@ class RousiSpider:
return cls._size
def __init__(self, indexer: dict):
self.systemconfig = SystemConfigOper()
self.systemconfig = get_configured_system_config()
if indexer:
self._indexerid = indexer.get('id')
self._url = indexer.get('domain')
+3 -3
View File
@@ -12,7 +12,7 @@ from app.schemas.mediaserver import MediaServerLibrary as _SchemaMediaServerLibr
from app.schemas.mediaserver import MediaServerPlayItem as _SchemaMediaServerPlayItem
from app.schemas.mediaserver import RefreshMediaItem as _SchemaRefreshMediaItem
from app.schemas.mediaserver import WebhookEventInfo as _SchemaWebhookEventInfo
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.application.mediaserver import MediaServerIdentityHelper, MusicMediaServerHelper
from app.runtime.log import logger
from app.modules.ugreen.api import Api
@@ -116,12 +116,12 @@ class Ugreen:
@staticmethod
def __load_all_session_cache() -> dict:
sessions = SystemConfigOper().get(SystemConfigKey.UgreenSessionCache)
sessions = get_configured_system_config().get(SystemConfigKey.UgreenSessionCache)
return sessions if isinstance(sessions, dict) else {}
@staticmethod
def __save_all_session_cache(sessions: dict):
SystemConfigOper().set(SystemConfigKey.UgreenSessionCache, sessions)
get_configured_system_config().set(SystemConfigKey.UgreenSessionCache, sessions)
def __remove_persisted_session(self):
cache_key = self.__session_cache_key()
+2 -2
View File
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
from typing import Any, ClassVar, Union
from app.chain import ChainBase
from app.application.configuration import get_configured_system_config as SystemConfigOper
from app.application.configuration import get_configured_system_config
from app.schemas.workflow import ActionContext
from app.schemas.workflow import ActionParams
from app.schemas.workflow import ActionResult
@@ -37,7 +37,7 @@ class BaseAction(ABC):
self._action_id = action_id
self._done_flag = False
self._message = ""
self.systemconfigoper = SystemConfigOper()
self.systemconfigoper = get_configured_system_config()
@classmethod
def get_contract(cls) -> dict:
@@ -6,7 +6,7 @@
> 审计范围:宿主后端;排除 `app/plugins/**` 运行时插件副本
> 规范优先级:`AGENTS.md``docs/rules/` 高于本文
> 相关文档:`docs/architecture-overview.md``docs/refactor/backend-architecture-governance.md``docs/refactor/backend-module-refactor-compatibility.md`
> 实施进度:阶段 0~6 的宿主架构能力已完成收口;API/Application 公共复杂度基线已清零,启动组合根的 SystemConfigOper 构造点已由 14 降至 1;API 进程内后台任务已完成首批统一登记,插件仓适配和 Outbox 外围扩展仍按风险切片推进。Model/Base 查询与写装饰器、legacy 隐式会话外壳均已清零,插件 SDK 也不再导出宿主 Model。2026-08-23 的长期整改阶段 0 已恢复宿主、启动性能、官方插件和 SDK 契约门禁的可信基线;阶段 1a 已补齐 TaskRegistry owner 零债务门禁和诚实的关停超时语义;阶段 1b1 已收口整理 worker、pending 回放、失败通知、进程内 AI 重试、插件监控与事件投递的生命周期所有权;2026-08-24 的阶段 2 已将 212 个已观察宿主模块方法的 legacy aggregation 清零,并补齐可执行 fanout 与下载器文件 DTO 边界;阶段 3 已将消息交互和远程命令的订阅删除统一到 Application/UoW/outbox,宿主不再调用裸线程统计入口;阶段 4 已统一七种消息渠道的宿主回环与后台执行边界;阶段 5 已补齐事件窗口聚合任务的生命周期所有权;阶段 6 已统一插件文件操作的取消完成语义;阶段 7 已统一插件协程补偿的终态等待;阶段 8 已统一宿主同步函数的异步线程池入口;阶段 9 已统一工作流运行时的宿主获取路径;阶段 10 已统一模块、插件与调度运行时的显式 getter 调用。
> 实施进度:阶段 0~6 的宿主架构能力已完成收口;API/Application 公共复杂度基线已清零,启动组合根的 SystemConfigOper 构造点已由 14 降至 1;API 进程内后台任务已完成首批统一登记,插件仓适配和 Outbox 外围扩展仍按风险切片推进。Model/Base 查询与写装饰器、legacy 隐式会话外壳均已清零,插件 SDK 也不再导出宿主 Model。2026-08-23 的长期整改阶段 0 已恢复宿主、启动性能、官方插件和 SDK 契约门禁的可信基线;阶段 1a 已补齐 TaskRegistry owner 零债务门禁和诚实的关停超时语义;阶段 1b1 已收口整理 worker、pending 回放、失败通知、进程内 AI 重试、插件监控与事件投递的生命周期所有权;2026-08-24 的阶段 2 已将 212 个已观察宿主模块方法的 legacy aggregation 清零,并补齐可执行 fanout 与下载器文件 DTO 边界;阶段 3 已将消息交互和远程命令的订阅删除统一到 Application/UoW/outbox,宿主不再调用裸线程统计入口;阶段 4 已统一七种消息渠道的宿主回环与后台执行边界;阶段 5 已补齐事件窗口聚合任务的生命周期所有权;阶段 6 已统一插件文件操作的取消完成语义;阶段 7 已统一插件协程补偿的终态等待;阶段 8 已统一宿主同步函数的异步线程池入口;阶段 9 已统一工作流运行时的宿主获取路径;阶段 10 已统一模块、插件与调度运行时的显式 getter 调用;阶段 11 已清除系统配置 getter 的 Oper 形别名
## 当前复核结论(2026-08-24
@@ -129,6 +129,17 @@
- 兼容边界不变:Application 的 `ModuleManager``Scheduler` 类形 Facade 和 concrete 插件管理器类路径
继续保留,旧插件、V1/V2/V3 索引加载及 SDK/Compat 映射无需迁移;本阶段仅统一宿主生产路径。
### 长期整改阶段 11:系统配置端口命名统一(2026-08-24)
- Agent、Chain、Module 和 Workflow 的 17 个 canonical 文件原先把
`get_configured_system_config()` 别名或赋值为 `SystemConfigOper`,使 Application 配置端口在调用处
看起来仍像数据库 Oper。宿主生产路径现统一显式调用 getter,测试也改为替换真实组合根接缝。
- 架构门禁禁止为 `get_configured_system_config` 建立别名,也禁止把它赋给本地
`SystemConfigOper`;真正的 `app.db.oper.systemconfig.SystemConfigOper` 只留在 DB 实现、startup 装配和
testing bootstrap,不再形成第二种 canonical 获取方式。
- 兼容边界不变:DB Oper 类、`app.db.oper` 懒导出、SDK/Compat 旧路径和 V1/V2/V3 插件加载均未改动;
已注入 `SystemConfigReader/SystemConfigService` 的 Agent 工具构造合同保持原样。
### 总体判断
当前架构总体合理,已经从跨层混合的遗留单体收敛为**边界清晰的模块化单体**:
+7 -6
View File
@@ -107,12 +107,13 @@ API dependencies must narrow that object to a domain runtime (for example,
`AgentChatRuntime`) instead of adding a string key to a global service map.
Legacy registries may delegate the same object while domains migrate, but they
must not construct a second set of service instances.
Canonical host consumers of the process-wide module, plugin and scheduler
runtimes must call `get_module_manager()`, `get_plugin_manager()` and
`get_scheduler()` explicitly. The class-shaped `ModuleManager` and `Scheduler`
application facades, and concrete plugin manager class paths, remain compatibility
boundaries for plugins and startup composition; host code must not import those
facades or alias a getter back to a manager class name.
Canonical host consumers of the process-wide module, plugin, scheduler and
system-configuration runtimes must call `get_module_manager()`,
`get_plugin_manager()`, `get_scheduler()` and `get_configured_system_config()`
explicitly. The class-shaped `ModuleManager` and `Scheduler` application facades,
the concrete plugin manager class paths and DB `SystemConfigOper` remain
compatibility or composition boundaries; host code must not import those facades
or alias a getter back to a manager/Oper class name.
API, Scheduler and Chain deployment values are exposed as frozen snapshots from
`HostRuntime.configuration`; canonical callers must not add a fresh direct
`settings` import when the required field belongs to an existing snapshot.
+2 -2
View File
@@ -303,7 +303,7 @@ def test_install_plugin_runtime_reloads_in_threadpool() -> None:
with (
patch(
"app.agent.tools.impl._plugin_tool_utils.SystemConfigOper",
"app.agent.tools.impl._plugin_tool_utils.get_configured_system_config",
return_value=config_oper,
),
patch(
@@ -394,7 +394,7 @@ def test_sealed_agent_uninstall_rejects_before_persistence() -> None:
return_value=plugin_manager,
),
patch(
"app.agent.tools.impl._plugin_tool_utils.SystemConfigOper",
"app.agent.tools.impl._plugin_tool_utils.get_configured_system_config",
return_value=config_oper,
) as config_provider,
pytest.raises(PluginMutationRejectedError),
@@ -1,5 +1,7 @@
"""Agent 资源流程工具权限测试。"""
# pylint: disable=no-name-in-module
import asyncio
import json
from types import SimpleNamespace
@@ -308,7 +310,7 @@ def test_query_downloaders_hides_sensitive_fields_for_non_admin_user():
]
with patch(
"app.agent.tools.impl.query_downloaders.SystemConfigOper"
"app.agent.tools.impl.query_downloaders.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = downloaders
result = asyncio.run(tool.run())
@@ -345,7 +347,7 @@ def test_query_downloaders_keeps_full_fields_for_admin_context():
]
with patch(
"app.agent.tools.impl.query_downloaders.SystemConfigOper"
"app.agent.tools.impl.query_downloaders.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = downloaders
result = asyncio.run(tool.run())
+7 -7
View File
@@ -35,7 +35,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
tool = QuerySystemSettingsTool(session_id="session-1", user_id="10001")
with patch(
"app.agent.tools.impl.query_system_settings.SystemConfigOper"
"app.agent.tools.impl.query_system_settings.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = [{"name": "qb", "enabled": True}]
result = asyncio.run(tool.run(setting_key="Downloaders"))
@@ -54,7 +54,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
tool = QuerySystemSettingsTool(session_id="session-1", user_id="10001")
with patch(
"app.agent.tools.impl.query_system_settings.SystemConfigOper"
"app.agent.tools.impl.query_system_settings.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = [
{
@@ -84,7 +84,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
tool.set_agent_context({"is_admin": True})
with patch(
"app.agent.tools.impl.query_system_settings.SystemConfigOper"
"app.agent.tools.impl.query_system_settings.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = [
{"name": "site-a", "apikey": "site-api-key"}
@@ -156,7 +156,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
tool = QuerySystemSettingsTool(session_id="session-1", user_id="10001")
with patch(
"app.agent.tools.impl.query_system_settings.SystemConfigOper"
"app.agent.tools.impl.query_system_settings.get_configured_system_config"
) as system_config_oper:
system_config_oper.return_value.get.return_value = []
result = asyncio.run(tool.run(group="systemconfig"))
@@ -231,7 +231,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
config_oper.async_set = AsyncMock(return_value=True)
with patch(
"app.agent.tools.impl.update_system_settings.SystemConfigOper",
"app.agent.tools.impl.update_system_settings.get_configured_system_config",
return_value=config_oper,
), patch(
"app.agent.tools.impl.update_system_settings.eventmanager.async_send_event",
@@ -264,7 +264,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
config_oper.async_set = AsyncMock(return_value=True)
with patch(
"app.agent.tools.impl.update_system_settings.SystemConfigOper",
"app.agent.tools.impl.update_system_settings.get_configured_system_config",
return_value=config_oper,
), patch(
"app.agent.tools.impl.update_system_settings.eventmanager.async_send_event",
@@ -297,7 +297,7 @@ class TestAgentSystemSettingsTools(unittest.TestCase):
config_oper.async_set = AsyncMock(return_value=True)
with patch(
"app.agent.tools.impl.update_system_settings.SystemConfigOper",
"app.agent.tools.impl.update_system_settings.get_configured_system_config",
return_value=config_oper,
), patch(
"app.agent.tools.impl.update_system_settings.eventmanager.async_send_event",
+22 -1
View File
@@ -368,6 +368,18 @@ def test_host_code_uses_explicit_runtime_facade_getters():
continue
tree = ast.parse(path.read_text(encoding="utf-8-sig"), filename=str(path))
for node in ast.walk(tree):
if isinstance(node, ast.Assign) and isinstance(node.value, ast.Name):
target_names = {
target.id for target in node.targets if isinstance(target, ast.Name)
}
if (
"SystemConfigOper" in target_names
and node.value.id == "get_configured_system_config"
):
violations.append(
f"{relative.as_posix()}:{node.lineno}:SystemConfigOper"
)
continue
if not isinstance(node, ast.ImportFrom) or not node.module:
continue
forbidden_names = forbidden_imports.get(node.module, set())
@@ -377,7 +389,16 @@ def test_host_code_uses_explicit_runtime_facade_getters():
and alias.name == "get_plugin_manager"
and alias.asname is not None
)
if alias.name in forbidden_names or class_shaped_plugin_getter:
class_shaped_config_getter = (
node.module == "app.application.configuration"
and alias.name == "get_configured_system_config"
and alias.asname is not None
)
if (
alias.name in forbidden_names
or class_shaped_plugin_getter
or class_shaped_config_getter
):
imported_name = alias.asname or alias.name
violations.append(
f"{relative.as_posix()}:{node.lineno}:{imported_name}"
+3 -1
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# pylint: disable=no-name-in-module
import pytest
from app.modules.indexer.spider import haidan as haidan_module
@@ -21,7 +23,7 @@ def _build_indexer() -> dict:
@pytest.fixture()
def haidan_spider(monkeypatch):
"""构造不依赖真实数据库配置的 HaiDanSpider。"""
monkeypatch.setattr(haidan_module, "SystemConfigOper", lambda: None)
monkeypatch.setattr(haidan_module, "get_configured_system_config", lambda: None)
return HaiDanSpider(_build_indexer())
+3 -1
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# pylint: disable=no-name-in-module
import pytest
from app.modules.indexer.spider import hddolby as hddolby_module
@@ -21,7 +23,7 @@ def _build_indexer() -> dict:
@pytest.fixture()
def hddolby_spider(monkeypatch):
"""构造不依赖真实数据库配置的 HddolbySpider。"""
monkeypatch.setattr(hddolby_module, "SystemConfigOper", lambda: None)
monkeypatch.setattr(hddolby_module, "get_configured_system_config", lambda: None)
return HddolbySpider(_build_indexer())
+3 -1
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# pylint: disable=no-name-in-module
import pytest
from app.modules.indexer.spider import mtorrent as mtorrent_module
@@ -21,7 +23,7 @@ def _build_indexer() -> dict:
@pytest.fixture()
def mteam_spider(monkeypatch):
"""构造不依赖真实数据库配置的 MTorrentSpider。"""
monkeypatch.setattr(mtorrent_module, "SystemConfigOper", lambda: None)
monkeypatch.setattr(mtorrent_module, "get_configured_system_config", lambda: None)
return MTorrentSpider(_build_indexer())
+3 -1
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# pylint: disable=no-name-in-module
import pytest
from app.modules.indexer.spider import rousi as rousi_module
@@ -21,7 +23,7 @@ def _build_indexer() -> dict:
@pytest.fixture()
def rousi_spider(monkeypatch):
"""构造不依赖真实数据库配置的 RousiSpider。"""
monkeypatch.setattr(rousi_module, "SystemConfigOper", lambda: None)
monkeypatch.setattr(rousi_module, "get_configured_system_config", lambda: None)
return RousiSpider(_build_indexer())
+1 -1
View File
@@ -1056,7 +1056,7 @@ class SubscribeChainTest(TestCase):
with patch.object(SUBSCRIBE_CHAIN_MODULE, "SubscribeOper", _SubscribeOper), patch.object(
SUBSCRIBE_CHAIN_MODULE,
"SystemConfigOper",
"get_configured_system_config",
_SystemConfigOper,
), patch.object(
SUBSCRIBE_CHAIN_MODULE,