modified: controls/device.py

modified:   equipment/turtle_device.py
	modified:   noblocking_turtle_shell.py
	modified:   turtle_shell.py
This commit is contained in:
vviora 2023-12-20 19:17:55 +03:00
parent 8a621ebbe3
commit 718e9700ca
4 changed files with 102 additions and 101 deletions

View File

@ -1,15 +1,16 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional, Collection, Any from typing import Optional, Collection, Any
from abc import ABC, abstractmethod from abc import ABC, abstractmethod, abstractproperty
from enum import Enum, auto from enum import Enum
class DeviceLifecycleState(Enum): class DeviceLifecycleState(Enum):
INIT = "init" INIT = 0
OPEN = "open" OPEN = 1
CLOSE = "close" CLOSE = 2
class DevaceError(Exception): class DeviceError(Exception):
pass pass
@ -37,7 +38,6 @@ class ActionDescriptor:
class Device(ABC): class Device(ABC):
# TODO(Homework #3)
_state = DeviceLifecycleState.INIT _state = DeviceLifecycleState.INIT
@property @property
@ -47,13 +47,11 @@ class Device(ABC):
def close(self): def close(self):
self._state = DeviceLifecycleState.CLOSE self._state = DeviceLifecycleState.CLOSE
@property @abstractproperty
@abstractmethod
def trait_descriptors(self) -> Collection[TraitDescriptor]: def trait_descriptors(self) -> Collection[TraitDescriptor]:
pass pass
@property @abstractproperty
@abstractmethod
def action_descriptors(self) -> Collection[ActionDescriptor]: def action_descriptors(self) -> Collection[ActionDescriptor]:
pass pass
@ -71,7 +69,7 @@ class SynchronyDevice(Device):
@abstractmethod @abstractmethod
def execute(self, action_name: str, *args, **kwargs): def execute(self, action_name: str, *args, **kwargs):
"""Execute action `action_name`, using `args` and `kwargs` as action argument.""" """Execute action `action_name`, using `args` and `kwargs` as action argument."""
pass raise DeviceError
@abstractmethod @abstractmethod
def read(self, trait_name: str) -> Any: def read(self, trait_name: str) -> Any:
@ -87,6 +85,3 @@ class SynchronyDevice(Device):
def invalidate(self, trait_name: str): def invalidate(self, trait_name: str):
"""Invalidate logical state of trait `trait_name`""" """Invalidate logical state of trait `trait_name`"""
pass pass
def close(self):
return super().close()

View File

@ -1,73 +1,80 @@
import time
from turtle import Turtle from turtle import Turtle
from equipment.device import SynchronyDevice
from equipment.device import Device
import inspect
from typing import Optional, Collection, Any from typing import Optional, Collection, Any
from controls.device import *
import inspect
class TurtleDevice(SynchronyDevice): class TurtleDevice(SynchronyDevice):
def open(self): def open(self):
super().open()
self.turtle = Turtle() self.turtle = Turtle()
self.descriptors = dict(traits=dict(), actions=dict())
super().open()
def close (self): def close(self):
self.turtle.reset()
super().close() super().close()
del self.turtle
@property
def trait_descriptors(self):
l = list()
for i in inspect.getmembers(TurtleDevice):
if not (i[0].startswith("__") or i[0].startswith("_")) and not inspect.isfunction(i[1]):
l.append(i[0])
return l
@property def trait_descriptors(self) -> Collection[TraitDescriptor]:
def action_descriptors(self): return self.get_descriptors()["traits"]
l = list()
#print(inspect.getmembers(TurtleDevice))
#for i in dir(TurtleDevice):
# # print(type(getattr(TurtleDevice(), i))=='method')
# # if not i.startswith("__") and type(getattr(TurtleDevice(), i)) == types.MethodType:
# if not i.startswith("__") and inspect.isroutine(inspect.getattr_static(TurtleDevice, i)):
# sig = inspect.signature(getattr(TurtleDevice, i))
# l.append(i + " " + str(sig))
#return l
for i in inspect.getmembers(TurtleDevice):
# print(type(getattr(TurtleDevice, i)))
# print(type(getattr(TurtleDevice(), i))=='method')
if not (i[0].startswith("__") or i[0].startswith("_")) and inspect.isfunction(i[1]):
sig = inspect.signature(getattr(TurtleDevice, i[0]))
l.append(i[0]+str(sig))
return l
def execute(self, action_name: str, *args, **kwargs): def action_descriptors(self) -> Collection[ActionDescriptor]:
"""Execute action `action_name`, using `args` and `kwargs` as action argument.""" return self.get_descriptors()["actions"]
if self.state == 1:
f = getattr(self.turtle, action_name)
f(int(*args), **kwargs)
else:
print("It's not opened")
self.open()
#time.sleep(30)
f = getattr(self.turtle, action_name)
f(int(*args), **kwargs)
def read(self, trait_name: str):
"""Read physical state of trait `trait_name` from device."""
return getattr(self.turtle, trait_name)
def write(self, trait_name: str, value: Any) -> bool:
"""Pass `value` to trait `trait_name` of device."""
setattr(self.turtle, trait_name, value)
def invalidate(self, trait_name: str):
"""Invalidate logical state of trait `trait_name`"""
if self.read(trait_name) == self.__getitem__(trait_name):
print("Everything's okey")
else:
print(f"Something went wrong with {trait_name}.")
def __getitem__(self, trait_name: str) -> Optional[Any]: def __getitem__(self, trait_name: str) -> Optional[Any]:
"""Return logical state of trait `trait_name`.""" """Return logical state of trait `trait_name`."""
return getattr(self, trait_name) return self.descriptors[trait_name]
def read_descriptors(self, arg):
self.descriptors = self.get_descriptors()
return self.descriptors
def read(self, trait_name: str) -> Any:
"""Read physical state of trait `trait_name` from device."""
self.read_descriptors()
return self.descriptors[trait_name]
def write(self, trait_name: str, value: Any) -> bool:
"""Turtle traits are not writable"""
# trait_desc = self.trait_descriptors.get(trait_name)
# if trait_desc.writable:
# return getattr(self.turtle, trait_name)(value)
super().write()
def execute(self, action_name: str, *args, **kwargs):
"""Execute action `action_name`, using `args` and `kwargs` as action argument."""
action = self.get_descriptors()["actions"].get(action_name)
if action:
getattr(self.turtle, action_name)(*args, **kwargs)
return
else:
raise DeviceError("No such action: `{}`".format(action_name))
def invalidate(self, trait_name: str):
"""Invalidate logical state of trait `trait_name`"""
if self.trait_descriptors.get(trait_name):
self.trait_descriptors[trait_name] = None
raise DeviceError()
def get_descriptors(self):
descriptors = dict(actions=dict(), traits=dict())
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

View File

@ -1,19 +1,17 @@
import cmd import cmd
import threading from threading import Thread, Event
from queue import Empty, Queue from turtle import bye
from queue import Queue, Empty
from equipment.turtle_device import TurtleDevice from equipment.turtle_device import TurtleDevice
import argparse
import time
class TurtleDeviceThread(threading.Thread): class TurtleDeviceThread(Thread):
# TODO(Homework 4)
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.device = TurtleDevice() self.device = TurtleDevice()
self.queue = Queue() self.queue = Queue()
self.event = Event()
def run(self): def run(self):
while True: while True:
try: try:
@ -23,22 +21,9 @@ class TurtleDeviceThread(threading.Thread):
else: else:
if (item == 'exit'): if (item == 'exit'):
break break
self.device.execute(item[0], item[1:]) self.device.execute(*item)
self.queue.task_done() self.queue.task_done()
def __message_processing__(self):
while True:
new_message = self.queue.get()
#print(type(new_message))
#print(new_message)
#print("Name and args of action are {}".format(new_message))
self.device.execute(*new_message)
#time.sleep(30)
self.queue.task_done()
if self.event.is_set():
break
def __message_thread__(self):
thread = Thread(target = self.__message_processing__, daemon=True)
thread.start()
class NoBlockingTurtleShell(cmd.Cmd): class NoBlockingTurtleShell(cmd.Cmd):
intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n' intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n'
@ -47,14 +32,27 @@ class NoBlockingTurtleShell(cmd.Cmd):
def __init__(self, turtle_thread: TurtleDeviceThread): def __init__(self, turtle_thread: TurtleDeviceThread):
super(NoBlockingTurtleShell, self).__init__() super(NoBlockingTurtleShell, self).__init__()
turtle_thread.__message_thread__() self.turtle_thread = turtle_thread
def do_execute(self, arg): def do_execute(self, arg):
turtle_thread.queue.put(parse(arg)) self.turtle_thread.queue.put(parse(arg))
def do_exit(self, arg): def do_exit(self, arg):
turtle_thread.event.set() self.close()
self.turtle_thread.queue.put("exit")
print('Thank you for using Turtle')
return True
def close(self):
if self.file:
self.file.close()
self.file = None
def parse(arg):
'Convert a series of zero or more numbers to an argument tuple'
return tuple(arg.split())
if __name__ == '__main__': if __name__ == '__main__':
turtle_thread = TurtleDeviceThread() turtle_thread = TurtleDeviceThread()

View File

@ -10,6 +10,7 @@ class TurtleShell(cmd.Cmd):
# ----- basic turtle commands ----- # ----- basic turtle commands -----
def do_forward(self, arg): def do_forward(self, arg):
'Move the turtle forward by the specified distance: FORWARD 10' 'Move the turtle forward by the specified distance: FORWARD 10'
forward(*parse(arg)) forward(*parse(arg))
def do_right(self, arg): def do_right(self, arg):
'Turn turtle right by given number of degrees: RIGHT 20' 'Turn turtle right by given number of degrees: RIGHT 20'