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 execute(self, action_name: str, *args, **kwargs): getattr(self.turtle, action_name)(*args, **kwargs) def read(self, trait_name: str): """Read physical state of trait `trait_name` from device.""" trait = self.trait_descriptors()[trait_name] if not trait.readable : super().read(trait_name) return trait.info def write(self, trait_name: str, value: Any) -> bool: """Pass `value` to trait `trait_name` of device.""" if not self.trait_descriptors()[trait_name] : super().write(trait_name, value) setattr(self.turtle, trait_name, value) def invalidate(self, trait_name: str): """Invalidate logical state of trait `trait_name`""" pass def trait_descriptors(self): traits = dict() for name, value in inspect.getmembers(self.turtle): if not callable(value) and not name.startswith('_'): info = f"{value}" traits[name] = TraitDescriptor(name, info) return traits def action_descriptors(self): actions = dict() for name, func in inspect.getmembers(self.turtle): if callable(func) and not name.startswith('_'): args = dict(inspect.signature(func).parameters) info = inspect.getdoc(func) actions[name] = ActionDescriptor(name, args, info) return actions def __getitem__(self, trait_name: str): """Return logical state of trait `trait_name`.""" pass