mirror of
https://github.com/langgenius/dify.git
synced 2026-04-15 18:06:36 +08:00
fix: fix sqlalchemy.orm.exc.DetachedInstanceError (#34845)
This commit is contained in:
parent
02c1bfc3e7
commit
41eeb1f2e7
@ -1,14 +1,13 @@
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
|
|
||||||
from extensions.ext_database import db
|
from core.db.session_factory import session_factory
|
||||||
from models.account import TenantPluginAutoUpgradeStrategy
|
from models.account import TenantPluginAutoUpgradeStrategy
|
||||||
|
|
||||||
|
|
||||||
class PluginAutoUpgradeService:
|
class PluginAutoUpgradeService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_strategy(tenant_id: str) -> TenantPluginAutoUpgradeStrategy | None:
|
def get_strategy(tenant_id: str) -> TenantPluginAutoUpgradeStrategy | None:
|
||||||
with sessionmaker(bind=db.engine).begin() as session:
|
with session_factory.create_session() as session:
|
||||||
return session.scalar(
|
return session.scalar(
|
||||||
select(TenantPluginAutoUpgradeStrategy)
|
select(TenantPluginAutoUpgradeStrategy)
|
||||||
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
||||||
@ -24,7 +23,7 @@ class PluginAutoUpgradeService:
|
|||||||
exclude_plugins: list[str],
|
exclude_plugins: list[str],
|
||||||
include_plugins: list[str],
|
include_plugins: list[str],
|
||||||
) -> bool:
|
) -> bool:
|
||||||
with sessionmaker(bind=db.engine).begin() as session:
|
with session_factory.create_session() as session:
|
||||||
exist_strategy = session.scalar(
|
exist_strategy = session.scalar(
|
||||||
select(TenantPluginAutoUpgradeStrategy)
|
select(TenantPluginAutoUpgradeStrategy)
|
||||||
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
||||||
@ -51,7 +50,7 @@ class PluginAutoUpgradeService:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exclude_plugin(tenant_id: str, plugin_id: str) -> bool:
|
def exclude_plugin(tenant_id: str, plugin_id: str) -> bool:
|
||||||
with sessionmaker(bind=db.engine).begin() as session:
|
with session_factory.create_session() as session:
|
||||||
exist_strategy = session.scalar(
|
exist_strategy = session.scalar(
|
||||||
select(TenantPluginAutoUpgradeStrategy)
|
select(TenantPluginAutoUpgradeStrategy)
|
||||||
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
.where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id)
|
||||||
|
|||||||
@ -6,23 +6,23 @@ MODULE = "services.plugin.plugin_auto_upgrade_service"
|
|||||||
|
|
||||||
|
|
||||||
def _patched_session():
|
def _patched_session():
|
||||||
"""Patch sessionmaker(bind=db.engine).begin() to return a mock session as context manager."""
|
"""Patch session_factory.create_session() to return a mock session as context manager."""
|
||||||
session = MagicMock()
|
session = MagicMock()
|
||||||
mock_sessionmaker = MagicMock()
|
session.__enter__ = MagicMock(return_value=session)
|
||||||
mock_sessionmaker.return_value.begin.return_value.__enter__ = MagicMock(return_value=session)
|
session.__exit__ = MagicMock(return_value=False)
|
||||||
mock_sessionmaker.return_value.begin.return_value.__exit__ = MagicMock(return_value=False)
|
mock_factory = MagicMock()
|
||||||
patcher = patch(f"{MODULE}.sessionmaker", mock_sessionmaker)
|
mock_factory.create_session.return_value = session
|
||||||
db_patcher = patch(f"{MODULE}.db")
|
patcher = patch(f"{MODULE}.session_factory", mock_factory)
|
||||||
return patcher, db_patcher, session
|
return patcher, session
|
||||||
|
|
||||||
|
|
||||||
class TestGetStrategy:
|
class TestGetStrategy:
|
||||||
def test_returns_strategy_when_found(self):
|
def test_returns_strategy_when_found(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
strategy = MagicMock()
|
strategy = MagicMock()
|
||||||
session.scalar.return_value = strategy
|
session.scalar.return_value = strategy
|
||||||
|
|
||||||
with p1, p2:
|
with p1:
|
||||||
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
||||||
|
|
||||||
result = PluginAutoUpgradeService.get_strategy("t1")
|
result = PluginAutoUpgradeService.get_strategy("t1")
|
||||||
@ -30,10 +30,10 @@ class TestGetStrategy:
|
|||||||
assert result is strategy
|
assert result is strategy
|
||||||
|
|
||||||
def test_returns_none_when_not_found(self):
|
def test_returns_none_when_not_found(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
session.scalar.return_value = None
|
session.scalar.return_value = None
|
||||||
|
|
||||||
with p1, p2:
|
with p1:
|
||||||
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
||||||
|
|
||||||
result = PluginAutoUpgradeService.get_strategy("t1")
|
result = PluginAutoUpgradeService.get_strategy("t1")
|
||||||
@ -43,10 +43,10 @@ class TestGetStrategy:
|
|||||||
|
|
||||||
class TestChangeStrategy:
|
class TestChangeStrategy:
|
||||||
def test_creates_new_strategy(self):
|
def test_creates_new_strategy(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
session.scalar.return_value = None
|
session.scalar.return_value = None
|
||||||
|
|
||||||
with p1, p2, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
with p1, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
||||||
strat_cls.return_value = MagicMock()
|
strat_cls.return_value = MagicMock()
|
||||||
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
||||||
|
|
||||||
@ -63,11 +63,11 @@ class TestChangeStrategy:
|
|||||||
session.add.assert_called_once()
|
session.add.assert_called_once()
|
||||||
|
|
||||||
def test_updates_existing_strategy(self):
|
def test_updates_existing_strategy(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
existing = MagicMock()
|
existing = MagicMock()
|
||||||
session.scalar.return_value = existing
|
session.scalar.return_value = existing
|
||||||
|
|
||||||
with p1, p2:
|
with p1:
|
||||||
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService
|
||||||
|
|
||||||
result = PluginAutoUpgradeService.change_strategy(
|
result = PluginAutoUpgradeService.change_strategy(
|
||||||
@ -89,12 +89,11 @@ class TestChangeStrategy:
|
|||||||
|
|
||||||
class TestExcludePlugin:
|
class TestExcludePlugin:
|
||||||
def test_creates_default_strategy_when_none_exists(self):
|
def test_creates_default_strategy_when_none_exists(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
session.scalar.return_value = None
|
session.scalar.return_value = None
|
||||||
|
|
||||||
with (
|
with (
|
||||||
p1,
|
p1,
|
||||||
p2,
|
|
||||||
patch(f"{MODULE}.select"),
|
patch(f"{MODULE}.select"),
|
||||||
patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls,
|
patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls,
|
||||||
patch(f"{MODULE}.PluginAutoUpgradeService.change_strategy") as cs,
|
patch(f"{MODULE}.PluginAutoUpgradeService.change_strategy") as cs,
|
||||||
@ -110,13 +109,13 @@ class TestExcludePlugin:
|
|||||||
cs.assert_called_once()
|
cs.assert_called_once()
|
||||||
|
|
||||||
def test_appends_to_exclude_list_in_exclude_mode(self):
|
def test_appends_to_exclude_list_in_exclude_mode(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
existing = MagicMock()
|
existing = MagicMock()
|
||||||
existing.upgrade_mode = "exclude"
|
existing.upgrade_mode = "exclude"
|
||||||
existing.exclude_plugins = ["p-existing"]
|
existing.exclude_plugins = ["p-existing"]
|
||||||
session.scalar.return_value = existing
|
session.scalar.return_value = existing
|
||||||
|
|
||||||
with p1, p2, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
with p1, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
||||||
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
||||||
strat_cls.UpgradeMode.PARTIAL = "partial"
|
strat_cls.UpgradeMode.PARTIAL = "partial"
|
||||||
strat_cls.UpgradeMode.ALL = "all"
|
strat_cls.UpgradeMode.ALL = "all"
|
||||||
@ -128,13 +127,13 @@ class TestExcludePlugin:
|
|||||||
assert existing.exclude_plugins == ["p-existing", "p-new"]
|
assert existing.exclude_plugins == ["p-existing", "p-new"]
|
||||||
|
|
||||||
def test_removes_from_include_list_in_partial_mode(self):
|
def test_removes_from_include_list_in_partial_mode(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
existing = MagicMock()
|
existing = MagicMock()
|
||||||
existing.upgrade_mode = "partial"
|
existing.upgrade_mode = "partial"
|
||||||
existing.include_plugins = ["p1", "p2"]
|
existing.include_plugins = ["p1", "p2"]
|
||||||
session.scalar.return_value = existing
|
session.scalar.return_value = existing
|
||||||
|
|
||||||
with p1, p2, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
with p1, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
||||||
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
||||||
strat_cls.UpgradeMode.PARTIAL = "partial"
|
strat_cls.UpgradeMode.PARTIAL = "partial"
|
||||||
strat_cls.UpgradeMode.ALL = "all"
|
strat_cls.UpgradeMode.ALL = "all"
|
||||||
@ -146,12 +145,12 @@ class TestExcludePlugin:
|
|||||||
assert existing.include_plugins == ["p2"]
|
assert existing.include_plugins == ["p2"]
|
||||||
|
|
||||||
def test_switches_to_exclude_mode_from_all(self):
|
def test_switches_to_exclude_mode_from_all(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
existing = MagicMock()
|
existing = MagicMock()
|
||||||
existing.upgrade_mode = "all"
|
existing.upgrade_mode = "all"
|
||||||
session.scalar.return_value = existing
|
session.scalar.return_value = existing
|
||||||
|
|
||||||
with p1, p2, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
with p1, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
||||||
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
||||||
strat_cls.UpgradeMode.PARTIAL = "partial"
|
strat_cls.UpgradeMode.PARTIAL = "partial"
|
||||||
strat_cls.UpgradeMode.ALL = "all"
|
strat_cls.UpgradeMode.ALL = "all"
|
||||||
@ -164,13 +163,13 @@ class TestExcludePlugin:
|
|||||||
assert existing.exclude_plugins == ["p1"]
|
assert existing.exclude_plugins == ["p1"]
|
||||||
|
|
||||||
def test_no_duplicate_in_exclude_list(self):
|
def test_no_duplicate_in_exclude_list(self):
|
||||||
p1, p2, session = _patched_session()
|
p1, session = _patched_session()
|
||||||
existing = MagicMock()
|
existing = MagicMock()
|
||||||
existing.upgrade_mode = "exclude"
|
existing.upgrade_mode = "exclude"
|
||||||
existing.exclude_plugins = ["p1"]
|
existing.exclude_plugins = ["p1"]
|
||||||
session.scalar.return_value = existing
|
session.scalar.return_value = existing
|
||||||
|
|
||||||
with p1, p2, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
with p1, patch(f"{MODULE}.select"), patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls:
|
||||||
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
strat_cls.UpgradeMode.EXCLUDE = "exclude"
|
||||||
strat_cls.UpgradeMode.PARTIAL = "partial"
|
strat_cls.UpgradeMode.PARTIAL = "partial"
|
||||||
strat_cls.UpgradeMode.ALL = "all"
|
strat_cls.UpgradeMode.ALL = "all"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user