Make assignments on BaseAddon class objects work as expected
The descriptors were being silently clobbered for a while now, and I never noticed. Oops!
This commit is contained in:
@@ -143,7 +143,34 @@ def ais_folder_to_inventory_data(ais_folder: dict):
|
||||
)
|
||||
|
||||
|
||||
class BaseAddon(abc.ABC):
|
||||
class MetaBaseAddon(abc.ABCMeta):
|
||||
"""
|
||||
Metaclass for BaseAddon that prevents class member assignments from clobbering descriptors
|
||||
|
||||
Without this things like:
|
||||
|
||||
class Foo(BaseAddon):
|
||||
bar: int = GlobalProperty(0)
|
||||
|
||||
Foo.bar = 2
|
||||
|
||||
Won't work as you expect!
|
||||
"""
|
||||
def __setattr__(self, key: str, value):
|
||||
# TODO: Keep track of AddonProperties in __new__ or something?
|
||||
try:
|
||||
existing = object.__getattribute__(self, key)
|
||||
except AttributeError:
|
||||
# If the attribute doesn't exist then it's fine to use the base setattr.
|
||||
super().__setattr__(key, value)
|
||||
return
|
||||
if existing and isinstance(existing, BaseAddonProperty):
|
||||
existing.__set__(self, value)
|
||||
return
|
||||
super().__setattr__(key, value)
|
||||
|
||||
|
||||
class BaseAddon(metaclass=MetaBaseAddon):
|
||||
def _schedule_task(self, coro: Coroutine, session=None,
|
||||
region_scoped=False, session_scoped=True, addon_scoped=True):
|
||||
session = session or addon_ctx.session.get(None) or None
|
||||
|
||||
@@ -33,10 +33,11 @@ class MockAddon(BaseAddon):
|
||||
|
||||
|
||||
PARENT_ADDON_SOURCE = """
|
||||
from hippolyzer.lib.proxy.addon_utils import BaseAddon
|
||||
from hippolyzer.lib.proxy.addon_utils import BaseAddon, GlobalProperty
|
||||
|
||||
class ParentAddon(BaseAddon):
|
||||
baz = None
|
||||
quux: int = GlobalProperty(0)
|
||||
|
||||
@classmethod
|
||||
def foo(cls):
|
||||
@@ -136,3 +137,16 @@ class AddonIntegrationTests(BaseProxyTest):
|
||||
AddonManager.unload_addon_from_path(str(self.parent_path), reload=True)
|
||||
await asyncio.sleep(0.001)
|
||||
self.assertNotIn('hippolyzer.user_addon_parent_addon', sys.modules)
|
||||
|
||||
async def test_global_property_access_and_set(self):
|
||||
with open(self.parent_path, "w") as f:
|
||||
f.write(PARENT_ADDON_SOURCE)
|
||||
AddonManager.load_addon_from_path(str(self.parent_path), reload=True)
|
||||
# Wait for the init hooks to run
|
||||
await asyncio.sleep(0.001)
|
||||
self.assertFalse("quux" in self.session_manager.addon_ctx)
|
||||
parent_addon_mod = AddonManager.FRESH_ADDON_MODULES['hippolyzer.user_addon_parent_addon']
|
||||
self.assertEqual(0, parent_addon_mod.ParentAddon.quux)
|
||||
self.assertEqual(0, self.session_manager.addon_ctx["quux"])
|
||||
parent_addon_mod.ParentAddon.quux = 1
|
||||
self.assertEqual(1, self.session_manager.addon_ctx["quux"])
|
||||
|
||||
Reference in New Issue
Block a user