From 363094170e218e935f7343b43b54878905a412dc Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Thu, 24 Jan 2019 14:05:57 +0000 Subject: [PATCH] Added/updated docs --- openflexure_microscope/camera/base.py | 2 +- openflexure_microscope/stage/openflexure.py | 8 +++- openflexure_microscope/task.py | 50 ++++++++++++++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index 07e5ee5e..98e738a8 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -87,7 +87,7 @@ class BaseCamera(object): self.thread = None #: Background thread reading frames from camera self.camera = None #: Camera object - self.lock = StrictLock(timeout=1) #: Strict lock controlling thread access to camera hardware + self.lock = StrictLock(timeout=1) #: :py:class:`openflexure_microscope.lock.StrictLock`: Strict lock controlling thread access to camera hardware self.frame = None #: bytes: Current frame is stored here by background thread self.last_access = 0 #: time: Time of last client access to the camera diff --git a/openflexure_microscope/stage/openflexure.py b/openflexure_microscope/stage/openflexure.py index 5d6e745b..56d4a483 100644 --- a/openflexure_microscope/stage/openflexure.py +++ b/openflexure_microscope/stage/openflexure.py @@ -5,13 +5,17 @@ from openflexure_microscope.lock import StrictLock # TODO: Implement lock on movement class Stage(OpenFlexureStage): def __init__(self, *args, **kwargs): - self.lock = StrictLock(timeout=2) #: Strict lock controlling thread access to camera hardware + """ + Subclass of :py:class:`openflexure_stage.stage.OpenFlexureStage`, + adding an instance of :py:class:`openflexure_microscope.lock.StrictLock` to regulate access. + """ + self.lock = StrictLock(timeout=2) #: :py:class:`openflexure_microscope.lock.StrictLock`: Strict lock controlling thread access to camera hardware OpenFlexureStage.__init__(self, *args, **kwargs) def _move_rel_nobacklash(self, *args, **kwargs): """ - Overrides `OpenFlexureStage._move_rel_nobacklash` to acquire lock first. + Overrides :py:function:`openflexure_stage.stage.OpenFlexureStage._move_rel_nobacklash` to acquire lock first. """ with self.lock: OpenFlexureStage._move_rel_nobacklash(self, *args, **kwargs) \ No newline at end of file diff --git a/openflexure_microscope/task.py b/openflexure_microscope/task.py index 7684936c..d35937a9 100644 --- a/openflexure_microscope/task.py +++ b/openflexure_microscope/task.py @@ -9,19 +9,34 @@ from openflexure_microscope.utilities import entry_by_id class TaskOrchestrator: def __init__(self): - # List of tasks in the orchestrator - self.tasks = [] + """ + Class responsible for spawning threaded tasks, and storing their returns. + A microscope should contain exactly one instance of `TaskOrchestrator`. + """ + self.tasks = [] #: list: List of `Task` objects @property def state(self): + """ + Returns a list of dictionary representations of all tasks in the session. + """ return [task.state for task in self.tasks] - def task_from_id(self, task_id): + def task_from_id(self, task_id: str): + """ + Returns a particular task object with the specified `task_id`. + """ return entry_by_id(task_id, self.tasks) - def start(self, function, *args, **kwargs): + def start(self, function: function, *args, **kwargs): """ Attach and start a new long-running task, if allowed by `start_condition()`. + Returns an instance of :py:class:`openflexure_microscope.task.Task`, which can be used to check the state + or eventual return of the task. + + Args: + function (function): The target function to run in the background + *args, **kwargs: Arguments that will be passed to `function` at runtime. """ # Create a task object task = Task(function, *args, **kwargs) @@ -65,16 +80,18 @@ class TaskOrchestrator: class Task: def __init__(self, task, *args, **kwargs): - + """ + Class responsible for running a task function in a thread, and handling return or errors. + Tasks should be created by an instance of :py:class:`openflexure_microscope.task.TaskOrchestrator`. + """ # The task long-running method - self.task = task - self.args = args - self.kwargs = kwargs + self.task = task #: function: Function to be called in the task thread. + self.args = args #: Positional arguments to be passed to the task function. + self.kwargs = kwargs #: Keyword arguments to be passed to the task function. - # If task is currently running - self._running = False + self._running = False #: bool: If task is currently running - self.id = uuid.uuid4().hex + self.id = uuid.uuid4().hex #: str: Unique ID for the task self.state = { 'id': self.id, @@ -82,9 +99,12 @@ class Task: 'return': None, 'start_time': None, 'end_time': None, - } + } #: dict: Dictionary describing the full state of the task. `status` will be one of 'idle'', 'running', 'error', or 'success'. `return` eventually holds the return value of the task function. def process(self, f): + """ + Wraps the target function to handle recording `status` and `return` to `state`. + """ def wrapped(*args, **kwargs): self.state['status'] = 'running' try: @@ -98,12 +118,18 @@ class Task: return wrapped def run(self): + """ + Records the task start and end times to `state`, and runs the task wrapped in `process`. + """ self.state['start_time'] = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S") self.process(self.task)(*self.args, **self.kwargs) self._running = False self.state['end_time'] = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S") def start(self): # Start and draw + """ + Spawns a thread, and starts `run()` in that thread. + """ # If not already running if not self._running: self._running = True # Set start command