From f52b55621915e15f80d4f9e4ba054fb17a047e69 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Fri, 8 Apr 2022 16:49:47 +0200 Subject: [PATCH] - icon_class should not be part of the backend model - Interaction with entities should occur through the `entities.action` method, not by implementing native methods on each of the model objects --- platypush/entities/_base.py | 20 ++++++---------- platypush/entities/devices.py | 7 ------ platypush/entities/lights.py | 7 ------ platypush/entities/switches.py | 16 ------------- platypush/plugins/entities/__init__.py | 33 ++++++++++++++++++++++---- 5 files changed, 35 insertions(+), 48 deletions(-) diff --git a/platypush/entities/_base.py b/platypush/entities/_base.py index aa589261..fe4ec2c6 100644 --- a/platypush/entities/_base.py +++ b/platypush/entities/_base.py @@ -52,12 +52,6 @@ class Entity(Base): 'polymorphic_on': type, } - @property - def _meta(self) -> dict: - return { - 'icon_class': 'fa-solid fa-circle-question', - } - @classmethod @property def columns(cls) -> Tuple[ColumnProperty]: @@ -73,13 +67,7 @@ class Entity(Base): return val def to_json(self) -> dict: - return { - **{col.key: self._serialize_value(col) for col in self.columns}, - 'meta': { - **self._meta, - **(self.meta or {}), - }, - } + return {col.key: self._serialize_value(col) for col in self.columns} def get_plugin(self): from platypush.context import get_plugin @@ -88,6 +76,12 @@ class Entity(Base): assert plugin, f'No such plugin: {plugin}' return plugin + def run(self, action: str, *args, **kwargs): + plugin = self.get_plugin() + method = getattr(plugin, action, None) + assert method, f'No such action: {self.plugin}.{action}' + return method(self.external_id or self.name, *args, **kwargs) + # Inject the JSONAble mixin (Python goes nuts if done through # standard multiple inheritance with an SQLAlchemy ORM class) diff --git a/platypush/entities/devices.py b/platypush/entities/devices.py index bf26c2ac..24820eef 100644 --- a/platypush/entities/devices.py +++ b/platypush/entities/devices.py @@ -11,10 +11,3 @@ class Device(Entity): __mapper_args__ = { 'polymorphic_identity': __tablename__, } - - @property - def _meta(self): - return { - **super()._meta, - 'icon_class': 'fa-solid fa-gear', - } diff --git a/platypush/entities/lights.py b/platypush/entities/lights.py index 4df4c51c..44392aec 100644 --- a/platypush/entities/lights.py +++ b/platypush/entities/lights.py @@ -11,10 +11,3 @@ class Light(Device): __mapper_args__ = { 'polymorphic_identity': __tablename__, } - - @property - def _meta(self): - return { - **super()._meta, - 'icon_class': 'fa-solid fa-lightbulb', - } diff --git a/platypush/entities/switches.py b/platypush/entities/switches.py index f26ca6ef..e7dcfbde 100644 --- a/platypush/entities/switches.py +++ b/platypush/entities/switches.py @@ -12,19 +12,3 @@ class Switch(Device): __mapper_args__ = { 'polymorphic_identity': __tablename__, } - - @property - def _meta(self): - return { - **super()._meta, - 'icon_class': 'fa-solid fa-light-switch', - } - - def on(self): - return self.get_plugin().on(self) - - def off(self): - return self.get_plugin().off(self) - - def toggle(self): - return self.get_plugin().toggle(self) diff --git a/platypush/plugins/entities/__init__.py b/platypush/plugins/entities/__init__.py index dc65a661..40918d9b 100644 --- a/platypush/plugins/entities/__init__.py +++ b/platypush/plugins/entities/__init__.py @@ -1,10 +1,10 @@ from queue import Queue, Empty from threading import Thread from time import time -from typing import Optional +from typing import Optional, Any from platypush.context import get_plugin -from platypush.entities import get_plugin_entity_registry, get_entities_registry +from platypush.entities import Entity, get_plugin_entity_registry, get_entities_registry from platypush.plugins import Plugin, action @@ -17,6 +17,11 @@ class EntitiesPlugin(Plugin): def __init__(self, **kwargs): super().__init__(**kwargs) + def _get_db(self): + db = get_plugin('db') + assert db + return db + @action def get(self, type: str = 'entity', **filter): """ @@ -35,9 +40,7 @@ class EntitiesPlugin(Plugin): entity_type ), f'No such entity type: {type}. Supported types: {list(all_types.keys())}' - db = get_plugin('db') - assert db - + db = self._get_db() with db.get_session() as session: query = session.query(entity_type) if filter: @@ -127,5 +130,25 @@ class EntitiesPlugin(Plugin): return self.get(**filter) + @action + def execute(self, id: Any, action: str, *args, **kwargs): + """ + Execute an action on an entity (for example `on`/`off` on a switch, or `get` + on a sensor). + + :param id: Entity ID (i.e. the entity's db primary key, not the plugin's external + or "logical" key) + :param action: Action that should be run. It should be a method implemented + by the entity's class. + :param args: Action's extra positional arguments. + :param kwargs: Action's extra named arguments. + """ + db = self._get_db() + with db.get_session() as session: + entity = session.query(Entity).filter_by(id=id).one_or_none() + + assert entity, f'No such entity ID: {id}' + return entity.run(action, *args, **kwargs) + # vim:sw=4:ts=4:et: