from turtle import Turtle from typing import Optional, Collection, Any from controls.device import SynchronyDevice from controls.device import TraitDescriptor from controls.device import ActionDescriptor import inspect class TurtleDevice(SynchronyDevice): def open(self): self.turtle = Turtle() super().open() def close(self): self.turtle.clear() super().close() def trait_descriptors(self) -> Collection[TraitDescriptor]: return self.get_descriptors()["traits"] def action_descriptors(self) -> Collection[ActionDescriptor]: return self.get_descriptors()["actions"] def __getitem__(self, trait_name: str) -> Optional[Any]: """Return logical state of trait `trait_name`.""" pass def read(self, trait_name: str) -> Any: pass def write(self, trait_name: str, value: Any) -> bool: self.turtle.write() def execute(self, action_name: str, *args, **kwargs): """Execute action `action_name`, using `args` and `kwargs` as action argument.""" pass def invalidate(self, trait_name: str): pass def get_descriptors(self): descriptors = dict(actions=dict(), traits=dict()) for k, v in self.turtle.__dict__.items(): if not k.startswith("_"): descriptors["traits"][k] = TraitDescriptor(k, inspect.getdoc(v), readable=True, writable=False) for m_name, member in inspect.getmembers(Turtle): if m_name.startswith("_"): continue if m_name.lower() != m_name: continue doc = inspect.getdoc(member) if doc is None: continue if not inspect.isfunction(member): descriptors["traits"][m_name] = TraitDescriptor(m_name, doc, readable=True, writable=False) else: sig = inspect.signature(member) params_dict = dict(sig.parameters) descriptors["actions"][m_name] = ActionDescriptor(m_name, arguments=params_dict, info=doc) return descriptors