- 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
This commit is contained in:
Fabio Manganiello 2022-04-08 16:49:47 +02:00
parent 947b50b937
commit f52b556219
Signed by: blacklight
GPG key ID: D90FBA7F76362774
5 changed files with 35 additions and 48 deletions

View file

@ -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)

View file

@ -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',
}

View file

@ -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',
}

View file

@ -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)

View file

@ -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: