forked from platypush/platypush
[#341] Backend implementation of the new procedure
entities architecture.
This commit is contained in:
parent
1ee8055597
commit
99909c73ab
8 changed files with 138 additions and 10 deletions
|
@ -272,6 +272,7 @@ class Config:
|
||||||
@property
|
@property
|
||||||
def _core_plugins(self) -> Dict[str, dict]:
|
def _core_plugins(self) -> Dict[str, dict]:
|
||||||
return {
|
return {
|
||||||
|
'procedures': {},
|
||||||
'variable': {},
|
'variable': {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
class ProceduresManager:
|
|
||||||
"""
|
|
||||||
This class is responsible for managing the procedures as native entities.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.procedures = {}
|
|
29
platypush/entities/managers/procedures.py
Normal file
29
platypush/entities/managers/procedures.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Callable, Dict, Union
|
||||||
|
|
||||||
|
from platypush.config import Config
|
||||||
|
from . import EntityManager
|
||||||
|
|
||||||
|
|
||||||
|
class ProcedureEntityManager(EntityManager, ABC):
|
||||||
|
"""
|
||||||
|
Base class for integrations that can run and manage procedures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def exec(self, procedure: str, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Run a procedure.
|
||||||
|
|
||||||
|
:param procedure: Procedure to run, by name.
|
||||||
|
:param args: Arguments to pass to the procedure.
|
||||||
|
:param kwargs: Keyword arguments to pass to the procedure.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _all_procedures(self) -> Dict[str, Union[dict, Callable]]:
|
||||||
|
"""
|
||||||
|
:return: All the procedures that can be run by this entity manager.
|
||||||
|
"""
|
||||||
|
return Config.get_procedures()
|
|
@ -28,9 +28,13 @@ if not is_defined('procedure'):
|
||||||
id = Column(
|
id = Column(
|
||||||
Integer, ForeignKey('entity.id', ondelete='CASCADE'), primary_key=True
|
Integer, ForeignKey('entity.id', ondelete='CASCADE'), primary_key=True
|
||||||
)
|
)
|
||||||
name = Column(String, unique=True, nullable=False)
|
|
||||||
args = Column(JSON, nullable=False, default=[])
|
args = Column(JSON, nullable=False, default=[])
|
||||||
type = Column(Enum('python', 'config', name='procedure_type'), nullable=False)
|
procedure_type = Column(
|
||||||
|
Enum('python', 'config', name='procedure_type'), nullable=False
|
||||||
|
)
|
||||||
|
module = Column(String)
|
||||||
|
source = Column(String)
|
||||||
|
line = Column(Integer)
|
||||||
|
|
||||||
__table_args__ = {'keep_existing': True}
|
__table_args__ = {'keep_existing': True}
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
|
|
|
@ -12,6 +12,7 @@ from platypush.common.db import override_definitions
|
||||||
from platypush.common.reflection import Integration, Message as MessageMetadata
|
from platypush.common.reflection import Integration, Message as MessageMetadata
|
||||||
from platypush.config import Config
|
from platypush.config import Config
|
||||||
from platypush.plugins import Plugin, action
|
from platypush.plugins import Plugin, action
|
||||||
|
from platypush.plugins.procedure import ProcedureEncoder
|
||||||
from platypush.message import Message
|
from platypush.message import Message
|
||||||
from platypush.message.event import Event
|
from platypush.message.event import Event
|
||||||
from platypush.message.response import Response
|
from platypush.message.response import Response
|
||||||
|
@ -20,7 +21,6 @@ from platypush.utils.mock import auto_mocks
|
||||||
from platypush.utils.manifest import Manifest, Manifests, PackageManagers
|
from platypush.utils.manifest import Manifest, Manifests, PackageManagers
|
||||||
|
|
||||||
from ._cache import Cache
|
from ._cache import Cache
|
||||||
from ._serialize import ProcedureEncoder
|
|
||||||
|
|
||||||
|
|
||||||
class InspectPlugin(Plugin):
|
class InspectPlugin(Plugin):
|
||||||
|
|
94
platypush/plugins/procedures/__init__.py
Normal file
94
platypush/plugins/procedures/__init__.py
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Callable, Collection, Optional, Union
|
||||||
|
|
||||||
|
from platypush.entities.managers.procedures import ProcedureEntityManager
|
||||||
|
from platypush.entities.procedures import Procedure
|
||||||
|
from platypush.plugins import RunnablePlugin, action
|
||||||
|
from platypush.utils import run
|
||||||
|
|
||||||
|
from ._serialize import ProcedureEncoder
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class _ProcedureWrapper:
|
||||||
|
name: str
|
||||||
|
obj: Union[dict, Callable]
|
||||||
|
|
||||||
|
|
||||||
|
class ProceduresPlugin(RunnablePlugin, ProcedureEntityManager):
|
||||||
|
"""
|
||||||
|
Utility plugin to run and store procedures as native entities.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@action
|
||||||
|
def exec(self, procedure: str, *args, **kwargs):
|
||||||
|
return run(f'procedure.{procedure}', *args, **kwargs)
|
||||||
|
|
||||||
|
def _convert_procedure(self, name: str, proc: Union[dict, Callable]) -> Procedure:
|
||||||
|
metadata = self._serialize_procedure(proc, name=name)
|
||||||
|
return Procedure(
|
||||||
|
id=name,
|
||||||
|
name=name,
|
||||||
|
plugin=self,
|
||||||
|
procedure_type=metadata['type'],
|
||||||
|
module=metadata.get('module'),
|
||||||
|
source=metadata.get('source'),
|
||||||
|
line=metadata.get('line'),
|
||||||
|
args=metadata.get('args', []),
|
||||||
|
)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def status(self, *_, **__):
|
||||||
|
"""
|
||||||
|
:return: The serialized configured procedures. Format:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"procedure_name": {
|
||||||
|
"type": "python",
|
||||||
|
"module": "module_name",
|
||||||
|
"source": "/path/to/source.py",
|
||||||
|
"line": 42,
|
||||||
|
"args": ["arg1", "arg2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.publish_entities(self._get_wrapped_procedures())
|
||||||
|
return self._get_serialized_procedures()
|
||||||
|
|
||||||
|
def transform_entities(
|
||||||
|
self, entities: Collection[_ProcedureWrapper], **_
|
||||||
|
) -> Collection[Procedure]:
|
||||||
|
return [
|
||||||
|
self._convert_procedure(name=proc.name, proc=proc.obj) for proc in entities
|
||||||
|
]
|
||||||
|
|
||||||
|
def _get_wrapped_procedures(self) -> Collection[_ProcedureWrapper]:
|
||||||
|
return [
|
||||||
|
_ProcedureWrapper(name=name, obj=proc)
|
||||||
|
for name, proc in self._all_procedures.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _serialize_procedure(
|
||||||
|
proc: Union[dict, Callable], name: Optional[str] = None
|
||||||
|
) -> dict:
|
||||||
|
ret = json.loads(json.dumps(proc, cls=ProcedureEncoder))
|
||||||
|
if name:
|
||||||
|
ret['name'] = name
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _get_serialized_procedures(self) -> dict:
|
||||||
|
return {
|
||||||
|
name: self._serialize_procedure(proc, name=name)
|
||||||
|
for name, proc in self._all_procedures.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
def main(self, *_, **__):
|
||||||
|
while not self.should_stop():
|
||||||
|
self.publish_entities(self._get_wrapped_procedures())
|
||||||
|
self.wait_stop()
|
7
platypush/plugins/procedures/manifest.json
Normal file
7
platypush/plugins/procedures/manifest.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"manifest": {
|
||||||
|
"package": "platypush.plugins.procedure",
|
||||||
|
"type": "plugin",
|
||||||
|
"events": []
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue