Source code for masterpiece.core.composite
from typing import List, Optional
from .masterpiece import MasterPiece
[docs]
class Composite(MasterPiece):
"""Class implementing hierarchy. Objects of this class can consist of children.
This class can be used for grouping masterpieces into larger entities.
Example:
::
motion_sensors = Composite("motionsensors")
motion_sensors.add(ShellyMotionSensor("downstairs"))
motion_sensors.add(ShellyMotionSensor("upstairs"))
"""
def __init__(
self, name: str = "group", payload: Optional[MasterPiece] = None
) -> None:
super().__init__(name, payload)
self.children: List[MasterPiece] = []
self.role: str = "union"
[docs]
def add(self, h: MasterPiece) -> None:
"""Add new automation object as children. The object to be inserted
must be derived from MasterPiece base class.
Args:
h (T): object to be inserted.
"""
self.children.append(h)
def to_dict(self):
data = super().to_dict()
data["_group"] = {
"role": self.role,
"children": [child.to_dict() for child in self.children],
}
return data
[docs]
def from_dict(self, data):
"""Recursively deserialize the group from a dictionary, including its
children.
Args:
data (dict): data to deserialize from.
"""
super().from_dict(data)
for key, value in data.get("_group", {}).items():
if key == "children":
for child_dict in value:
child = MasterPiece.instantiate(child_dict["_class"])
self.add(child)
child.from_dict(child_dict)
else:
setattr(self, key, value)
[docs]
def print(self, prefix="", is_last=True):
"""Print the hierarchy of the node using ├─, └─, and │.
Example:
::
parent = Composite("parent")
child = MasterPiece("child")
parent.add(child)
parent.print()
# expected output:
# parent
# └─ child
Args:
prefix (str, optional): Defaults to "".
is_last (bool, optional): Defaults to True.
"""
super().print(prefix, is_last)
# Prepare the new prefix for the child nodes
if prefix:
prefix += " " if is_last else "│ "
else:
prefix = " " if is_last else "│ "
# Recursively print all the children
for i, child in enumerate(self.children):
is_last_child = i == len(self.children) - 1
child.print(prefix, is_last_child)
# @override
[docs]
def run_forever(self) -> None:
"""
Dispatches first the call to all children and then to the super class.
It is up to the sub classes to implement the actual functionality
for this method.
"""
self.start_children()
super().run_forever()
self.shutdown_children()
def start_children(self) -> None:
i: int = 0
for s in self.children:
self.info(f"Starting up thread {i} {s.name}")
s.run()
i = i + 1
self.info(f"All {i} threads succesfully started")
def shutdown_children(self) -> None:
i: int = 0
self.info("Shuttding down threads")
for s in self.children:
self.info(f"Shutting down thread {i} {s.name}")
s.shutdown()
i = i + 1
self.info(f"All {i} threads succesfully shut down")
# @override
[docs]
def shutdown(self) -> None:
"""
Dispatches first the call to all children and then to the super class.
It is up to the sub classes to implement the actual functionality
for this method.
"""
self.shutdown_children()
super().shutdown()