Split util.py and start documentation
authorBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 17 Mar 2021 14:39:15 +0000 (15:39 +0100)
committerBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 17 Mar 2021 14:39:15 +0000 (15:39 +0100)
controlpi-plugins/state.py [new file with mode: 0644]
controlpi-plugins/util.py
controlpi-plugins/wait.py [new file with mode: 0644]

diff --git a/controlpi-plugins/state.py b/controlpi-plugins/state.py
new file mode 100644 (file)
index 0000000..b6c762f
--- /dev/null
@@ -0,0 +1,42 @@
+"""Provide state plugins for all kinds of systems.
+
+TODO: documentation, doctests
+TODO: AndState, OrState
+"""
+from controlpi import BasePlugin, Message
+
+
+class State(BasePlugin):
+    CONF_SCHEMA = True
+
+    async def receive(self, message: Message) -> None:
+        if message['command'] == 'get state':
+            answer = {'sender': self.name, 'state': self.state}
+            await self.bus.send(answer)
+        elif message['command'] == 'set state':
+            if self.state != message['new state']:
+                self.state: bool = message['new state']
+                event = {'sender': self.name, 'event': 'changed',
+                         'state': self.state}
+                await self.bus.send(event)
+            else:
+                answer = {'sender': self.name, 'state': self.state}
+                await self.bus.send(answer)
+
+    def process_conf(self) -> None:
+        self.state = False
+        sends = [{'event': {'const': 'changed'},
+                  'state': {'type': 'boolean'}},
+                 {'state': {'type': 'boolean'}}]
+        receives = [{'target': {'const': self.name},
+                     'command': {'const': 'get state'}},
+                    {'target': {'const': self.name},
+                     'command': {'const': 'set state'},
+                     'new state': {'type': 'boolean'}}]
+        self.bus.register(self.name, 'State',
+                           sends,
+                           receives,
+                           self.receive)
+
+    async def run(self) -> None:
+        pass
index 29d892ed96cc48baf0095bb59bc6a04360db08be..2200c554dcbcb9d54ef627e41961085efe73bdd6 100644 (file)
 """Provide utility plugins for all kinds of systems.
 
-TODO: distribute over several modules
+- Log logs messages on stdout.
+- Init sends list of messages on startup and on demand.
+- Alias translates messages to an alias.
+
+>>> import controlpi
+>>> import asyncio
+>>> async def test():
+...     run_task = asyncio.create_task(controlpi.run(
+...         {"Debug Log": {"plugin": "Log",
+...                        "filter": [{}]},
+...          "Test Init": {"plugin": "Init",
+...                        "messages": [{"id": 42,
+...                                      "content": "Test Message"}]},
+...          "Test Alias": {"plugin": "Alias",
+...                         "from": {"sender": {"const": "Test Init"},
+...                                  "id": {"const": 42}},
+...                         "to": {"id": "translated"}}}
+...     ))
+...     for i in range(7):
+...         await asyncio.sleep(0)
+...     run_task.cancel()
+...     await run_task
+>>> asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
+Debug Log: {'sender': '', 'event': 'registered',
+            'client': 'Debug Log', 'plugin': 'Log',
+            'sends': [], 'receives': [{}]}
+Debug Log: {'sender': '', 'event': 'registered',
+            'client': 'Test Init', 'plugin': 'Init',
+            'sends': [{'id': {'const': 42},
+                       'content': {'const': 'Test Message'}},
+                      {'target': {'const': 'Test Init'},
+                       'command': {'const': 'execute'}}],
+            'receives': [{'target': {'const': 'Test Init'},
+                          'command': {'const': 'execute'}}]}
+Debug Log: {'sender': '', 'event': 'registered',
+            'client': 'Test Alias', 'plugin': 'Alias',
+            'sends': [{'id': {'const': 'translated'}}],
+            'receives': [{'sender': {'const': 'Test Init'},
+                          'id': {'const': 42}}]}
+Debug Log: {'sender': 'Test Init',
+            'target': 'Test Init', 'command': 'execute'}
+Debug Log: {'sender': 'Test Init',
+            'id': 42, 'content': 'Test Message'}
+Debug Log: {'sender': 'Test Alias',
+            'id': 'translated', 'content': 'Test Message'}
+
 TODO: documentation, doctests
-TODO: AndState, OrState?
 """
-import asyncio
-
 from controlpi import BasePlugin, Message, MessageTemplate
 
 
 class Log(BasePlugin):
+    """Log messages on stdout.
+
+    """
+
     CONF_SCHEMA = {'properties': {'filter': {'type': 'array'}},
                    'required': ['filter']}
+    """Schema for Log plugin configuration.
+
+    Required configuration key:
+
+    - 'filter' with list of message templates to be logged.
+    """
 
     async def log(self, message: Message) -> None:
+        """Log received message on stdout using own name as prefix."""
         print(f"{self.name}: {message}")
 
     def process_conf(self) -> None:
+        """Register plugin as bus client."""
         self.bus.register(self.name, 'Log', [], self.conf['filter'], self.log)
 
     async def run(self) -> None:
+        """Run no code proactively."""
         pass
 
 
 class Init(BasePlugin):
+    """Send list of messages on startup and on demand.
+
+    """
+
     CONF_SCHEMA = {'properties': {'messages': {'type': 'array'}},
                    'required': ['messages']}
+    """Schema for Init plugin configuration.
+
+    Required configuration key:
+
+    - 'messages' with list of messages to be sent.
+    """
 
     async def execute(self, message: Message) -> None:
+        """Send configured messages."""
         for message in self.conf['messages']:
             await self.bus.send(Message(self.name, message))
 
     def process_conf(self) -> None:
-        receives = [{'target': {'const': self.name},
-                     'command': {'const': 'execute'}}]
+        """Register plugin as bus client."""
+        receives = [MessageTemplate({'target': {'const': self.name},
+                                     'command': {'const': 'execute'}})]
         sends = [MessageTemplate.from_message(message)
                  for message in self.conf['messages']]
         sends.extend(receives)
         self.bus.register(self.name, 'Init', sends, receives, self.execute)
 
     async def run(self) -> None:
-        await self.bus.send({'sender': self.name,
-                             'target': self.name,
-                             'command': 'execute'})
-
-
-class Wait(BasePlugin):
-    CONF_SCHEMA = {'properties': {'seconds': {'type': 'number'}},
-                   'required': ['seconds']}
-
-    async def wait(self, message: Message) -> None:
-        await asyncio.sleep(self.conf['seconds'])
-        await self.bus.send({'sender': self.name, 'event': 'finished'})
-
-    def process_conf(self) -> None:
-        receives = [{'target': {'const': self.name},
-                     'command': {'const': 'wait'}}]
-        sends = [{'event': {'const': 'finished'}}]
-        self.bus.register(self.name, 'Wait', sends, receives, self.wait)
-
-    async def run(self) -> None:
-        pass
+        """Send execution command on startup."""
+        await self.bus.send(Message(self.name, {'target': self.name,
+                                                'command': 'execute'}))
 
 
-class GenericWait(BasePlugin):
-    CONF_SCHEMA = True
-
-    async def wait(self, message: Message) -> None:
-        await asyncio.sleep(message['seconds'])
-        await self.bus.send(Message(self.name, {'id': message['id']}))
-
-    def process_conf(self) -> None:
-        receives = [{'target': {'const': self.name},
-                     'command': {'const': 'wait'},
-                     'seconds': {'type': 'number'},
-                     'id': {'type': 'string'}}]
-        sends = [{'id': {'type': 'string'}}]
-        self.bus.register(self.name, 'GenericWait', sends, receives, self.wait)
-
-    async def run(self) -> None:
-        pass
+class Alias(BasePlugin):
+    """Translate messages to an alias.
 
+    """
 
-class Alias(BasePlugin):
     CONF_SCHEMA = {'properties': {'from': {'type': 'object'},
                                   'to': {'type': 'object'}},
                    'required': ['from', 'to']}
+    """Schema for Alias plugin configuration.
+
+    Required configuration keys:
+
+    - 'from' with template of messages to be translated.
+    - 'to' with translated message to be sent.
+    """
 
     async def alias(self, message: Message) -> None:
+        """Translate and send message."""
         alias_message = Message(self.name)
         alias_message.update(self.conf['to'])
         for key in message:
@@ -96,46 +138,12 @@ class Alias(BasePlugin):
         await self.bus.send(alias_message)
 
     def process_conf(self) -> None:
+        """Register plugin as bus client."""
         self.bus.register(self.name, 'Alias',
-                           [MessageTemplate.from_message(self.conf['to'])],
-                           [self.conf['from']],
-                           self.alias)
-
-    async def run(self) -> None:
-        pass
-
-
-class State(BasePlugin):
-    CONF_SCHEMA = True
-
-    async def receive(self, message: Message) -> None:
-        if message['command'] == 'get state':
-            answer = {'sender': self.name, 'state': self.state}
-            await self.bus.send(answer)
-        elif message['command'] == 'set state':
-            if self.state != message['new state']:
-                self.state: bool = message['new state']
-                event = {'sender': self.name, 'event': 'changed',
-                         'state': self.state}
-                await self.bus.send(event)
-            else:
-                answer = {'sender': self.name, 'state': self.state}
-                await self.bus.send(answer)
-
-    def process_conf(self) -> None:
-        self.state = False
-        sends = [{'event': {'const': 'changed'},
-                  'state': {'type': 'boolean'}},
-                 {'state': {'type': 'boolean'}}]
-        receives = [{'target': {'const': self.name},
-                     'command': {'const': 'get state'}},
-                    {'target': {'const': self.name},
-                     'command': {'const': 'set state'},
-                     'new state': {'type': 'boolean'}}]
-        self.bus.register(self.name, 'State',
-                           sends,
-                           receives,
-                           self.receive)
+                          [MessageTemplate.from_message(self.conf['to'])],
+                          [self.conf['from']],
+                          self.alias)
 
     async def run(self) -> None:
+        """Run no code proactively."""
         pass
diff --git a/controlpi-plugins/wait.py b/controlpi-plugins/wait.py
new file mode 100644 (file)
index 0000000..afe5431
--- /dev/null
@@ -0,0 +1,44 @@
+"""Provide waiting/sleeping plugins for all kinds of systems.
+
+TODO: documentation, doctests
+"""
+import asyncio
+
+from controlpi import BasePlugin, Message
+
+
+class Wait(BasePlugin):
+    CONF_SCHEMA = {'properties': {'seconds': {'type': 'number'}},
+                   'required': ['seconds']}
+
+    async def wait(self, message: Message) -> None:
+        await asyncio.sleep(self.conf['seconds'])
+        await self.bus.send({'sender': self.name, 'event': 'finished'})
+
+    def process_conf(self) -> None:
+        receives = [{'target': {'const': self.name},
+                     'command': {'const': 'wait'}}]
+        sends = [{'event': {'const': 'finished'}}]
+        self.bus.register(self.name, 'Wait', sends, receives, self.wait)
+
+    async def run(self) -> None:
+        pass
+
+
+class GenericWait(BasePlugin):
+    CONF_SCHEMA = True
+
+    async def wait(self, message: Message) -> None:
+        await asyncio.sleep(message['seconds'])
+        await self.bus.send(Message(self.name, {'id': message['id']}))
+
+    def process_conf(self) -> None:
+        receives = [{'target': {'const': self.name},
+                     'command': {'const': 'wait'},
+                     'seconds': {'type': 'number'},
+                     'id': {'type': 'string'}}]
+        sends = [{'id': {'type': 'string'}}]
+        self.bus.register(self.name, 'GenericWait', sends, receives, self.wait)
+
+    async def run(self) -> None:
+        pass