mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
fix(plugin): preserve market package generation
This commit is contained in:
@@ -86,6 +86,7 @@ class PluginMetadataMapper:
|
|||||||
plugin.history = info.get("history") or {}
|
plugin.history = info.get("history") or {}
|
||||||
plugin.release = bool(info.get("release"))
|
plugin.release = bool(info.get("release"))
|
||||||
plugin.repo_url = market
|
plugin.repo_url = market
|
||||||
|
plugin.package_version = package_version
|
||||||
plugin.is_local = False
|
plugin.is_local = False
|
||||||
plugin.add_time = add_time
|
plugin.add_time = add_time
|
||||||
return plugin
|
return plugin
|
||||||
|
|||||||
+14
-2
@@ -1,7 +1,7 @@
|
|||||||
from enum import Enum as _Enum
|
from enum import Enum as _Enum
|
||||||
from typing import Literal, Optional, List, Dict, Union
|
from typing import Dict, List, Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, RootModel, field_validator
|
from pydantic import BaseModel, Field, PrivateAttr, RootModel, field_validator
|
||||||
|
|
||||||
from app.schemas.common import JsonData
|
from app.schemas.common import JsonData
|
||||||
|
|
||||||
@@ -62,6 +62,8 @@ class Plugin(BaseModel):
|
|||||||
"""
|
"""
|
||||||
插件信息
|
插件信息
|
||||||
"""
|
"""
|
||||||
|
_package_version: Optional[str] = PrivateAttr(default=None)
|
||||||
|
|
||||||
id: str = None
|
id: str = None
|
||||||
# 插件名称
|
# 插件名称
|
||||||
plugin_name: Optional[str] = None
|
plugin_name: Optional[str] = None
|
||||||
@@ -124,6 +126,16 @@ class Plugin(BaseModel):
|
|||||||
# 实例实现模式;存量物理分身为空
|
# 实例实现模式;存量物理分身为空
|
||||||
instance_mode: Optional[str] = None
|
instance_mode: Optional[str] = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def package_version(self) -> Optional[str]:
|
||||||
|
"""读取仅供宿主内部候选选择使用的插件包代际。"""
|
||||||
|
return self._package_version
|
||||||
|
|
||||||
|
@package_version.setter
|
||||||
|
def package_version(self, value: Optional[str]) -> None:
|
||||||
|
"""保存插件包代际,但不把它暴露到 API 响应模型。"""
|
||||||
|
self._package_version = value
|
||||||
|
|
||||||
|
|
||||||
class PluginRuntimeSummary(BaseModel):
|
class PluginRuntimeSummary(BaseModel):
|
||||||
"""插件后台收敛状态和前端刷新代次。"""
|
"""插件后台收敛状态和前端刷新代次。"""
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from types import SimpleNamespace
|
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
from app.application.plugin.catalog import PluginCatalogService
|
from app.application.plugin.catalog import PluginCatalogService
|
||||||
|
from app.runtime.extensions.plugin.metadata import PluginMetadataMapper
|
||||||
|
from app.schemas.plugin import Plugin
|
||||||
|
|
||||||
|
|
||||||
def _plugin(
|
def _plugin(
|
||||||
@@ -13,14 +14,15 @@ def _plugin(
|
|||||||
version: str,
|
version: str,
|
||||||
repo_url: str,
|
repo_url: str,
|
||||||
package_version: str | None = "v3",
|
package_version: str | None = "v3",
|
||||||
):
|
) -> Plugin:
|
||||||
"""构造目录合并测试使用的最小插件 DTO。"""
|
"""构造目录合并测试使用的最小插件 DTO。"""
|
||||||
return SimpleNamespace(
|
plugin = Plugin(
|
||||||
id=plugin_id,
|
id=plugin_id,
|
||||||
plugin_version=version,
|
plugin_version=version,
|
||||||
repo_url=repo_url,
|
repo_url=repo_url,
|
||||||
package_version=package_version,
|
|
||||||
)
|
)
|
||||||
|
plugin.package_version = package_version
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
def _service(**overrides) -> PluginCatalogService:
|
def _service(**overrides) -> PluginCatalogService:
|
||||||
@@ -132,6 +134,33 @@ def test_load_maps_market_entries_with_installed_snapshot():
|
|||||||
assert mapper.call_args_list[1].args[3:] == (["Installed"], 1, "v3")
|
assert mapper.call_args_list[1].args[3:] == (["Installed"], 1, "v3")
|
||||||
|
|
||||||
|
|
||||||
|
def test_metadata_mapper_preserves_package_generation_without_serializing_it():
|
||||||
|
"""市场映射必须保留候选代际,同时不能扩张插件 API 响应。"""
|
||||||
|
mapper = PluginMetadataMapper(
|
||||||
|
plugin_instance=lambda _plugin_id: None,
|
||||||
|
plugin_class=lambda _plugin_id: None,
|
||||||
|
annotate_system_version=lambda info: info,
|
||||||
|
is_package_compatible=lambda _info, _version: True,
|
||||||
|
auth_checker=lambda _plugin, _source: True,
|
||||||
|
version_compare=lambda _left, _operator, _right: False,
|
||||||
|
log=Mock(),
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin = mapper.map(
|
||||||
|
plugin_id="Demo",
|
||||||
|
plugin_info={"name": "Demo", "version": "3.0.0"},
|
||||||
|
market="https://market-a",
|
||||||
|
installed_plugins=[],
|
||||||
|
add_time=1,
|
||||||
|
package_version="v3",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert plugin is not None
|
||||||
|
assert plugin.package_version == "v3"
|
||||||
|
assert "package_version" not in plugin.model_dump()
|
||||||
|
assert "package_version" not in Plugin.model_json_schema()["properties"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_async_collect_isolates_failure_and_completes_progress():
|
async def test_async_collect_isolates_failure_and_completes_progress():
|
||||||
"""异步市场单任务失败时保留成功结果,并把进度推进到完成态。"""
|
"""异步市场单任务失败时保留成功结果,并把进度推进到完成态。"""
|
||||||
|
|||||||
Reference in New Issue
Block a user