mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-31 04:57:23 +08:00
refactor: unify transfer chain data ports
This commit is contained in:
+10
-10
@@ -23,8 +23,8 @@ from app.chain.media import MediaChain
|
||||
from app.chain.storage import StorageChain
|
||||
from app.chain.subscribe import SubscribeChain
|
||||
from app.application.chain.data import (
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
TransferHistoryPortProxy as TransferHistoryOper,
|
||||
get_chain_download_history_port,
|
||||
get_chain_transfer_history_port,
|
||||
)
|
||||
from app.application.configuration import (
|
||||
get_chain_runtime_config_snapshot,
|
||||
@@ -417,7 +417,7 @@ class FileFilterMixin:
|
||||
|
||||
@staticmethod
|
||||
def _is_overwrite_declined(task: TransferTask, transferinfo: TransferInfo,
|
||||
transferhis: TransferHistoryOper) -> bool:
|
||||
transferhis: Any) -> bool:
|
||||
"""
|
||||
判断本次未入库是否为「同路径已有成功记录 + 覆盖模式裁定不覆盖」。
|
||||
|
||||
@@ -859,7 +859,7 @@ class HistoryMatchMixin:
|
||||
|
||||
def _resolve_history_from_download_files(
|
||||
self,
|
||||
downloadhis: DownloadHistoryOper,
|
||||
downloadhis: Any,
|
||||
download_files: List[DownloadFiles],
|
||||
file_path: Optional[Path] = None,
|
||||
save_path: Optional[Path] = None,
|
||||
@@ -889,7 +889,7 @@ class HistoryMatchMixin:
|
||||
|
||||
def _resolve_download_history(
|
||||
self,
|
||||
downloadhis: DownloadHistoryOper,
|
||||
downloadhis: Any,
|
||||
file_path: Path,
|
||||
bluray_dir: bool = False,
|
||||
download_hash: Optional[str] = None,
|
||||
@@ -1148,7 +1148,7 @@ class ManualHistoryMixin:
|
||||
def _get_manual_transfer_history(
|
||||
self,
|
||||
fileitem: FileItem,
|
||||
transfer_history_oper: TransferHistoryOper,
|
||||
transfer_history_oper: Any,
|
||||
include_move_dest: bool = False,
|
||||
) -> Optional[TransferHistory]:
|
||||
"""查询文件源路径历史,并兼容从成功移动后的目标现址重新整理。"""
|
||||
@@ -1178,7 +1178,7 @@ class ManualHistoryMixin:
|
||||
:param fileitems: 待查询的文件或目录项
|
||||
:return: 去重后的成功整理记录
|
||||
"""
|
||||
transfer_history_oper = TransferHistoryOper()
|
||||
transfer_history_oper = get_chain_transfer_history_port()
|
||||
histories: Dict[int, TransferHistory] = {}
|
||||
for fileitem in fileitems or []:
|
||||
if not fileitem or not fileitem.path:
|
||||
@@ -1212,7 +1212,7 @@ class ManualHistoryMixin:
|
||||
@staticmethod
|
||||
def _delete_manual_transfer_history(
|
||||
history: TransferHistory,
|
||||
transfer_history_oper: TransferHistoryOper,
|
||||
transfer_history_oper: Any,
|
||||
) -> Tuple[bool, str]:
|
||||
"""删除手动重整历史;非成功移动记录同时清理可能存在的旧目标。"""
|
||||
if (
|
||||
@@ -1385,7 +1385,7 @@ class FailedRetryMixin:
|
||||
)
|
||||
return
|
||||
|
||||
history = TransferHistoryOper().get(history_id)
|
||||
history = get_chain_transfer_history_port().get(history_id)
|
||||
if not history:
|
||||
self.post_message(
|
||||
Message(
|
||||
@@ -1478,7 +1478,7 @@ class FailedRetryMixin:
|
||||
:param media_id: 数据源原生 ID,必须与 media_source 成对提供
|
||||
"""
|
||||
# 查询历史记录
|
||||
history: TransferHistory = TransferHistoryOper().get(logid)
|
||||
history: TransferHistory = get_chain_transfer_history_port().get(logid)
|
||||
if not history:
|
||||
logger.error(f"整理记录不存在,ID:{logid}")
|
||||
return False, "整理记录不存在"
|
||||
|
||||
+11
-11
@@ -23,9 +23,9 @@ from app.domain.meta.metabase import MetaBase
|
||||
from app.domain.meta.metamusic import MetaMusic
|
||||
from app.domain.metainfo import MetaInfoPath
|
||||
from app.application.chain.data import (
|
||||
DownloadHistoryPortProxy as DownloadHistoryOper,
|
||||
TransferPendingPortProxy as TransferPendingOper,
|
||||
TransferHistoryPortProxy as TransferHistoryOper,
|
||||
get_chain_download_history_port,
|
||||
get_chain_transfer_history_port,
|
||||
get_chain_transfer_pending_port,
|
||||
)
|
||||
DownloadHistory = Any
|
||||
from app.application.configuration import get_configured_system_config
|
||||
@@ -142,7 +142,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
# 整理失败通知聚合器
|
||||
self.failure_notification_aggregator = TransferFailureNotificationAggregator()
|
||||
# 待整理文件落盘登记,用于进程重启后回放内存队列里未完成的任务
|
||||
self._pendingoper = TransferPendingOper()
|
||||
self._pendingoper = get_chain_transfer_pending_port()
|
||||
# 转移成功的文件清单
|
||||
self._success_target_files: Dict[Tuple, List[str]] = {}
|
||||
# 批次级刮削缓冲,避免同一批多文件入库重复触发目录刮削
|
||||
@@ -419,7 +419,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
username=task.username,
|
||||
)
|
||||
|
||||
transferhis = TransferHistoryOper()
|
||||
transferhis = get_chain_transfer_history_port()
|
||||
target_dir_path = self.__get_transfer_target_dir_path(transferinfo)
|
||||
job_id = self.jobview.get_job_id(task)
|
||||
|
||||
@@ -1265,7 +1265,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
"""
|
||||
try:
|
||||
# 识别
|
||||
transferhis = TransferHistoryOper()
|
||||
transferhis = get_chain_transfer_history_port()
|
||||
# 显式标注联合:下面既会赋回音乐识别结果(MusicInfo),也会赋回影视识别
|
||||
# 结果(MediaInfo),不标注时会被推断成其中一种,另一种就成了假错误
|
||||
mediainfo: Optional[Union[MediaInfo, MusicInfo]] = task.mediainfo
|
||||
@@ -1647,7 +1647,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
continue
|
||||
|
||||
# 查询下载记录识别情况
|
||||
downloadhis: DownloadHistory = DownloadHistoryOper().get_by_hash(
|
||||
downloadhis: DownloadHistory = get_chain_download_history_port().get_by_hash(
|
||||
torrent.hash
|
||||
)
|
||||
# 下载记录中的媒体类型作为整理类型来源,无下载记录时留空由文件后缀兜底
|
||||
@@ -2265,7 +2265,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
def _build_main_meta(
|
||||
main_fileitem: FileItem,
|
||||
main_bluray_dir: bool,
|
||||
download_history_oper: DownloadHistoryOper,
|
||||
download_history_oper: Any,
|
||||
) -> Optional[MetaBase]:
|
||||
"""
|
||||
构建主视频元数据。
|
||||
@@ -2357,7 +2357,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
if not items:
|
||||
return [], {}
|
||||
|
||||
download_history_oper = DownloadHistoryOper()
|
||||
download_history_oper = get_chain_download_history_port()
|
||||
inherited_map: Dict[Tuple[str, str], MetaBase] = {}
|
||||
main_items_by_dir, extra_items_by_dir = _build_directory_index(items)
|
||||
main_items = [
|
||||
@@ -2557,7 +2557,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
# 成功但源文件已变化放行交 overwrite_mode 决断);手动整理可清理失败记录,
|
||||
# 或按用户确认清理成功记录。
|
||||
if (not force or reorganize) and not preview:
|
||||
transfer_history_oper = TransferHistoryOper()
|
||||
transfer_history_oper = get_chain_transfer_history_port()
|
||||
transferd = self._get_manual_transfer_history(
|
||||
fileitem=file_item,
|
||||
transfer_history_oper=transfer_history_oper,
|
||||
@@ -2627,7 +2627,7 @@ class TransferChain(FileFilterMixin, ScrapeBatchMixin, EpisodeFormatMixin, Histo
|
||||
continue
|
||||
|
||||
# 提前获取下载历史,以便获取自定义识别词
|
||||
downloadhis = DownloadHistoryOper()
|
||||
downloadhis = get_chain_download_history_port()
|
||||
download_history = self._resolve_download_history(
|
||||
downloadhis=downloadhis,
|
||||
file_path=file_path,
|
||||
|
||||
@@ -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 调用;阶段 11 已清除系统配置 getter 的 Oper 形别名;阶段 12 已完成工作流域的显式 Chain 数据端口迁移;阶段 13 已收口用户、交互与消息链的数据端口;阶段 14 已收口音乐订阅数据端口;阶段 15 已收口站点数据端口;阶段 16 已收口媒体服务器数据端口;阶段 17 已收口下载数据端口;阶段 18 已收口主订阅数据端口。
|
||||
> 实施进度:阶段 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 形别名;阶段 12 已完成工作流域的显式 Chain 数据端口迁移;阶段 13 已收口用户、交互与消息链的数据端口;阶段 14 已收口音乐订阅数据端口;阶段 15 已收口站点数据端口;阶段 16 已收口媒体服务器数据端口;阶段 17 已收口下载数据端口;阶段 18 已收口主订阅数据端口;阶段 19 已收口整理数据端口。
|
||||
|
||||
## 当前复核结论(2026-08-24)
|
||||
|
||||
@@ -203,6 +203,15 @@
|
||||
- 兼容边界不变:三个 DB Oper、Proxy 类、订阅 Chain 公开方法、订阅字段和事件合同、V2/V3 插件调用
|
||||
方式均未修改。
|
||||
|
||||
### 长期整改阶段 19:整理 Chain 数据端口收口(2026-08-24)
|
||||
|
||||
- `TransferChain` 与 `_transfer` mixin 原先把 pending、下载历史和整理历史三个 `*PortProxy` 别名为
|
||||
数据库 Oper;现在 worker 回放、查重、历史解析、手动重整和失败重试统一调用对应 `get_chain_*_port()`。
|
||||
- 整理主流程、同步附属文件、音乐整理和手动历史测试改为替换命名 getter;架构门禁同时覆盖主链和
|
||||
mixin,禁止重新引入三个 Proxy。
|
||||
- 兼容边界不变:三个 DB Oper、Proxy 类、整理公开入口、队列和生命周期、历史字段、事件 payload 以及
|
||||
V2/V3 插件调用方式均未修改。
|
||||
|
||||
### 总体判断
|
||||
|
||||
当前架构总体合理,已经从跨层混合的遗留单体收敛为**边界清晰的模块化单体**:
|
||||
|
||||
@@ -131,7 +131,7 @@ Session. `app/db/adapters/` is the concrete persistence-adapter layer: it may
|
||||
depend on Application-owned Protocols, UoW/Session and Oper implementations.
|
||||
This deliberate dependency inversion is the only `DB implementation ->
|
||||
Application contract` direction; Application must remain free of DB imports.
|
||||
Migrated workflow, user, interaction, messaging, music, site, media-server, download and subscribe
|
||||
Migrated workflow, user, interaction, messaging, music, site, media-server, download, subscribe and transfer
|
||||
Chain consumers use the named `get_chain_*_port()` functions from
|
||||
`app/application/chain/data.py`; they must not alias migration-time `*PortProxy`
|
||||
classes back to database Oper names. Those proxy classes remain compatibility
|
||||
|
||||
@@ -543,6 +543,31 @@ def test_subscribe_chain_uses_explicit_data_port_getters():
|
||||
assert violations == []
|
||||
|
||||
|
||||
def test_transfer_chains_use_explicit_data_port_getters():
|
||||
"""整理主链与 mixin 不得把迁移期 PortProxy 伪装成数据库 Oper。"""
|
||||
paths = [APP_ROOT / "chain" / "transfer.py", APP_ROOT / "chain" / "_transfer.py"]
|
||||
forbidden = {
|
||||
"DownloadHistoryPortProxy",
|
||||
"TransferHistoryPortProxy",
|
||||
"TransferPendingPortProxy",
|
||||
}
|
||||
violations: list[str] = []
|
||||
for path in paths:
|
||||
tree = ast.parse(path.read_text(encoding="utf-8-sig"), filename=str(path))
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(node, ast.ImportFrom):
|
||||
continue
|
||||
if node.module != "app.application.chain.data":
|
||||
continue
|
||||
for alias in node.names:
|
||||
if alias.name in forbidden:
|
||||
violations.append(
|
||||
f"{path.relative_to(PROJECT_ROOT).as_posix()}:{node.lineno}:{alias.name}"
|
||||
)
|
||||
|
||||
assert violations == []
|
||||
|
||||
|
||||
def test_plugin_components_do_not_reexport_legacy_abi_names():
|
||||
"""新插件组件只提供 canonical 能力,不得复制旧 Helper、Manager 或 Oper 导出。"""
|
||||
violations: list[str] = []
|
||||
|
||||
@@ -59,12 +59,12 @@ def _patch_transfer_planning(monkeypatch, chain, fileitem, history, planned, del
|
||||
delete=lambda history_id: deleted.append(("history", history_id)),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: history_oper,
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: history_oper)
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: history_oper)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -72,7 +72,7 @@ def _patch_transfer_planning(monkeypatch, chain, fileitem, history, planned, del
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
|
||||
@@ -535,10 +535,10 @@ def test_success_file_aggregation_is_isolated_between_music_jobs_in_same_directo
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace())
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace())
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.add_transfer_success",
|
||||
lambda **kwargs: SimpleNamespace(id=1),
|
||||
@@ -767,8 +767,8 @@ def test_downloader_process_forwards_music_history_type(tmp_path, monkeypatch):
|
||||
],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper.get_by_hash",
|
||||
lambda _, download_hash: history,
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(get_by_hash=lambda download_hash: history),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
chain,
|
||||
|
||||
@@ -137,7 +137,7 @@ class TestTransferFailedRetryButtons(unittest.TestCase):
|
||||
settings, "AI_AGENT_ENABLE", True
|
||||
):
|
||||
with patch(
|
||||
"app.chain._transfer.TransferHistoryOper"
|
||||
"app.chain._transfer.get_chain_transfer_history_port"
|
||||
) as history_oper_cls, patch(
|
||||
"app.chain._transfer.build_manual_redo_prompt",
|
||||
return_value="retry transfer prompt",
|
||||
@@ -217,7 +217,7 @@ class TestTransferFailedRetryButtons(unittest.TestCase):
|
||||
settings, "AI_AGENT_ENABLE", True
|
||||
):
|
||||
with patch(
|
||||
"app.chain._transfer.TransferHistoryOper"
|
||||
"app.chain._transfer.get_chain_transfer_history_port"
|
||||
) as history_oper_cls, patch(
|
||||
"app.chain._transfer.build_manual_redo_prompt",
|
||||
side_effect=build_manual_redo_prompt,
|
||||
|
||||
@@ -426,7 +426,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper", return_value=SimpleNamespace()
|
||||
"app.chain.transfer.get_chain_transfer_history_port", return_value=SimpleNamespace()
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_success",
|
||||
lambda **kwargs: SimpleNamespace(id=1),
|
||||
@@ -472,8 +472,8 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
system_config_oper = SimpleNamespace(get=lambda key: None)
|
||||
|
||||
with patch("app.chain.transfer.TransferHistoryOper", return_value=transfer_history_oper), \
|
||||
patch("app.chain.transfer.DownloadHistoryOper", return_value=download_history_oper), \
|
||||
with patch("app.chain.transfer.get_chain_transfer_history_port", return_value=transfer_history_oper), \
|
||||
patch("app.chain.transfer.get_chain_download_history_port", return_value=download_history_oper), \
|
||||
patch("app.chain.transfer.get_configured_system_config", return_value=system_config_oper), \
|
||||
patch("app.chain.transfer.MetaInfoPath", lambda *args, **kwargs: FakeMeta(14)):
|
||||
state, errmsg = chain.do_transfer(
|
||||
@@ -647,7 +647,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
system_config_oper = SimpleNamespace(get=lambda key: None)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -715,10 +715,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
_reset_failed_retries(fileitem.path, fileitem.storage)
|
||||
try:
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -794,10 +794,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
):
|
||||
record_transfer_failure(fileitem.path, fileitem.storage)
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -850,7 +850,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
failed_history_oper = SimpleNamespace()
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=failed_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -890,7 +890,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
need_notify=False,
|
||||
)
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper", return_value=SimpleNamespace()
|
||||
"app.chain.transfer.get_chain_transfer_history_port", return_value=SimpleNamespace()
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_success",
|
||||
lambda **kwargs: SimpleNamespace(id=2),
|
||||
@@ -920,7 +920,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
transfer_history_oper = SimpleNamespace()
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -962,7 +962,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
self.assertTrue(chain.jobview.add_task(task))
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=SimpleNamespace(),
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -1005,7 +1005,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
self.assertTrue(chain.jobview.add_task(task))
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=SimpleNamespace(),
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -1081,10 +1081,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -1180,10 +1180,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
storage_chain = SimpleNamespace(get_item=lambda fileitem: subtitle_fileitem)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -1261,10 +1261,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -1366,10 +1366,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
return_value=download_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
@@ -1464,7 +1464,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
]
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper", return_value=SimpleNamespace()
|
||||
"app.chain.transfer.get_chain_transfer_history_port", return_value=SimpleNamespace()
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_success",
|
||||
lambda **kwargs: SimpleNamespace(id=1),
|
||||
@@ -1530,7 +1530,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper", return_value=SimpleNamespace()
|
||||
"app.chain.transfer.get_chain_transfer_history_port", return_value=SimpleNamespace()
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_success",
|
||||
lambda **kwargs: SimpleNamespace(id=1),
|
||||
|
||||
@@ -104,10 +104,10 @@ def test_conflicting_download_history_recognizes_movie_by_file_meta(monkeypatch)
|
||||
try_remove_job=lambda task: None,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_type_tmdbid=lambda **kwargs: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_type_tmdbid=lambda **kwargs: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_type_tmdbid=lambda **kwargs: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.MediaChain",
|
||||
lambda: SimpleNamespace(
|
||||
@@ -187,12 +187,12 @@ def test_movie_collection_conflict_only_drops_automatic_media(
|
||||
|
||||
chain._TransferChain__handle_transfer = fake_handle_transfer
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain.transfer.DownloadHistoryOper", lambda: history_oper)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: history_oper)
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain.transfer.get_chain_download_history_port", lambda: history_oper)
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: history_oper)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.get_configured_system_config",
|
||||
lambda: SimpleNamespace(get=lambda key: None),
|
||||
|
||||
@@ -153,7 +153,7 @@ def test_default_callback_skips_history_and_notification_when_overwrite_declined
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -199,7 +199,7 @@ def test_default_callback_keeps_original_failure_semantics_without_success_histo
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
@@ -251,7 +251,7 @@ def test_default_callback_delegates_primary_failure_to_durable_writer():
|
||||
|
||||
chain.durable_event_writer.transfer_result.side_effect = durable_transfer_result
|
||||
with patch(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
return_value=transfer_history_oper,
|
||||
), patch(
|
||||
"app.chain.transfer.add_transfer_fail",
|
||||
|
||||
@@ -139,12 +139,12 @@ def test_sync_extra_subtitle_inherits_matching_video_episode(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -152,7 +152,7 @@ def test_sync_extra_subtitle_inherits_matching_video_episode(monkeypatch):
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -236,12 +236,12 @@ def test_single_subtitle_transfer_reuses_same_name_video_episode(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -249,7 +249,7 @@ def test_single_subtitle_transfer_reuses_same_name_video_episode(monkeypatch):
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -351,12 +351,12 @@ def test_single_video_transfer_lists_parent_once_for_same_name_extra(monkeypatch
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -364,7 +364,7 @@ def test_single_video_transfer_lists_parent_once_for_same_name_extra(monkeypatch
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -449,12 +449,12 @@ def test_episode_format_filters_extra_files_before_sync_planning(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -462,7 +462,7 @@ def test_episode_format_filters_extra_files_before_sync_planning(monkeypatch):
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -536,12 +536,12 @@ def test_episode_format_keeps_matching_extra_files_following_main(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -549,7 +549,7 @@ def test_episode_format_keeps_matching_extra_files_following_main(monkeypatch):
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -632,12 +632,12 @@ def test_single_matching_subtitle_uses_unmatched_video_only_as_context(monkeypat
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -645,7 +645,7 @@ def test_single_matching_subtitle_uses_unmatched_video_only_as_context(monkeypat
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
@@ -728,12 +728,12 @@ def test_cleanup_dest_fileitem_is_deleted_only_after_allowed_items_exist(monkeyp
|
||||
|
||||
monkeypatch.setattr(chain, "_TransferChain__handle_transfer", fake_handle_transfer)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace(get_by_src=lambda src, storage=None: None))
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.DownloadHistoryOper",
|
||||
"app.chain.transfer.get_chain_download_history_port",
|
||||
lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
@@ -741,7 +741,7 @@ def test_cleanup_dest_fileitem_is_deleted_only_after_allowed_items_exist(monkeyp
|
||||
get_by_path=lambda path: None,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.DownloadHistoryOper", lambda: SimpleNamespace(
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_download_history_port", lambda: SimpleNamespace(
|
||||
get_by_hash=lambda download_hash: None,
|
||||
get_file_by_fullpath=lambda fullpath: None,
|
||||
get_files_by_savepath=lambda savepath: [],
|
||||
|
||||
@@ -76,10 +76,10 @@ def test_transfer_stops_when_automatic_category_has_no_tmdb_result(monkeypatch)
|
||||
chain = object.__new__(TransferChain)
|
||||
chain.jobview = SimpleNamespace(try_remove_job=lambda _task: None)
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.TransferHistoryOper",
|
||||
"app.chain.transfer.get_chain_transfer_history_port",
|
||||
lambda: SimpleNamespace(),
|
||||
)
|
||||
monkeypatch.setattr("app.chain._transfer.TransferHistoryOper", lambda: SimpleNamespace())
|
||||
monkeypatch.setattr("app.chain._transfer.get_chain_transfer_history_port", lambda: SimpleNamespace())
|
||||
monkeypatch.setattr(
|
||||
"app.chain.transfer.MediaChain",
|
||||
lambda: SimpleNamespace(
|
||||
|
||||
Reference in New Issue
Block a user