advanced-python-homework-2023/equipment/turtle_device.py
2023-11-12 18:13:02 +03:00

104 lines
3.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from turtle import Turtle
from controls.device import (
SynchronyDevice,
TraitDescriptor,
ActionDescriptor,
NoSuchTrait,
NoSuchAction,
)
from typing import Collection, Optional, Any
import inspect
class TurtleDevice(SynchronyDevice):
def __init__(self) -> None:
super().__init__()
self.open()
def open(self) -> None:
self.turtle = Turtle()
def close(self) -> None:
del self.turtle
self.close()
def execute(self, action_name: str, *args, **kwargs) -> None:
actions = self.action_descriptors
for action in actions:
if action.name == action_name:
# NOTE: судя по заданию, должен быть такой assert,
# но почему-то у меня inspect плохо спарсил типы именно для Turtle
# везде empty_time, хотя судя по доке в модуле typos проставлены
# при чем тестировал на pd.DataFrame, там все прекрасно парсит
# for argument in kwargs:
# action_tmp_argument_type = action.arguments[argument]
# given_method_tmp_argument = type(kwargs[argument])
# assert (
# action_tmp_argument_type == given_method_tmp_argument
# ), f"Переданный аргумент должен быть типа {action_tmp_argument_type}, вы передали {given_method_tmp_argument}"
getattr(self.turtle, action_name)(*args, **kwargs)
return
raise NoSuchAction
def read(self, trait_name: str) -> Any:
return Turtle().__getattribute__(trait_name)
def write(self, trait_name: str, value: Any) -> bool:
traits = self.trait_descriptors
for trait in traits:
if trait.name == trait_name:
attribute_type = type(self.turtle.__getattribute__(trait_name))
assert (
type(value) == attribute_type
), f"Wrong value type. Type should be {attribute_type}, but you pass {type(value)}"
self.turtle.__setattr__(trait_name, value)
return True
raise NoSuchTrait
def invalidate(self, trait_name: str) -> None:
self.write(trait_name=trait_name, value=Turtle().__getattribute__(trait_name))
return
def __getitem__(self, trait_name: str) -> Optional[Any]:
traits = self.trait_descriptors
for trait in traits:
if trait.name == trait_name:
return self.turtle.__getattribute__(trait_name)
raise NoSuchTrait
@property
def trait_descriptors(self) -> Collection[TraitDescriptor]:
return [
TraitDescriptor(name=attr, info=getattr(self.turtle, attr).__doc__)
for attr in dir(self.turtle)
if attr[0] != "_"
and attr[-1] != "_"
and not callable(getattr(self.turtle, attr))
]
@property
def action_descriptors(self) -> Collection[ActionDescriptor]:
methods = [
attr
for attr in dir(self.turtle)
if attr[0] != "_"
and attr[-1] != "_"
and callable(getattr(self.turtle, attr))
]
result = []
for method_name in methods:
method = getattr(self.turtle, method_name)
parameters = inspect.signature(method).parameters
arg_types = {}
for arg_name, arg in parameters.items():
arg_types[arg_name] = parameters[arg_name].annotation
result.append(
ActionDescriptor(
name=method_name, info=method.__doc__, arguments=arg_types
)
)
return result