Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/dev_guide/atom_enaml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ Enaml
.. todo::

Need to describe the syntax for overriding declarative functions.

See the package documentation at http://enaml.readthedocs.io
26 changes: 15 additions & 11 deletions docs/source/dev_guide/measurement.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ pre-hook can have two purposes :

Adding a pre-hook requires to :

- implement the logic by subclassing |BasePreExecutionHook|. The methods that can be
overridden are :
- implement the logic by subclassing |BasePreExecutionHook|. The methods that
can be overridden are :

- check: make sure that the measurement is in a proper state to be executed.
- run: execute any custom logic. If any task is to be executed it should be
executed by passing to the active engine.
- pause/resume/stop: to implement if the run method execution can take a
long time (typically if tasks are involved).
- list_runtimes: let the measurement know the runtime dependencies (such as
instrument drivers) if any.
instrument drivers) if any. They are then collected by the measurement.

Additionally if any entry is contributed to the task hierarchy they should
be added when the tool is linked (or later during edition of the tool).
Expand All @@ -68,14 +68,16 @@ Adding a pre-hook requires to :

- If a make_view method has been declared then one needs to create the
associated widget which should inherit of |Container|.
The syntax of the make_view is defined in the |BaseToolDeclaration| class.


Monitors
^^^^^^^^

Monitors are used to follow the progress of a measurement. They specify a number of
database entries they are interested in and will receive notifications when
the concerned entry is updated during the execution of the task hierarchy.
Monitors are used to follow the progress of a measurement. They specify a
number of database entries they are interested in and will receive
notifications whenthe concerned entry is updated during the execution of the
task hierarchy.

Adding a monitor requires to :

Expand Down Expand Up @@ -119,8 +121,8 @@ asked not to run them). They are hence perfectly fitted to run clean up.

Adding a post-hook requires to :

- implement the logic by subclassing |BasePostExecutionHook|. The methods that can be
overridden are :
- implement the logic by subclassing |BasePostExecutionHook|. The methods that
can be overridden are :

- check: make sure that the measurement is in a proper state to be executed.
- run: execute any custom logic. If any task is to be executed it should be
Expand All @@ -130,9 +132,10 @@ Adding a post-hook requires to :
- pause/resume/stop: to implement if the run method execution can take a
long time (typically if tasks are involved).
- list_runtimes: let the measurement know the runtime dependencies (such as
instrument drivers) if any. To access those dependencies inside the
`run` method one can use the |Measurement.get_runtime_dependencies| method
called with the id of the hook.
instrument drivers) if any. They are then collected by the measurement.
To access those dependencies inside the `run` method one can use
the |Measurement.get_runtime_dependencies| method called with the
id of the hook.

Additionally if any entry is contributed to the task hierarchy they should
be added when the tool is linked (or later during edition of the tool).
Expand All @@ -147,6 +150,7 @@ Adding a post-hook requires to :

- If a make_view method has been declared then one needs to create the
associated widget which should inherit of |Container|.
The syntax of the make_view is defined in the |BaseToolDeclaration| class.

.. note ::

Expand Down
2 changes: 1 addition & 1 deletion exopy/app/dependencies/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def validate_dependencies(self, kind, dependencies):
return not container.errors, container.errors

def collect_dependencies(self, kind, dependencies, owner=None):
"""Collect that a set of dependencies.
"""Collect a set of dependencies.

For runtime dependencies if permissions are necessary to use a
dependence they are requested and should released when they are no
Expand Down
132 changes: 132 additions & 0 deletions exopy/measurement/hooks/addtask_hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2015-2018 by Exopy Authors, see AUTHORS for more details.
#
# Distributed under the terms of the BSD license.
#
# The full license is in the file LICENCE, distributed with this software.
# -----------------------------------------------------------------------------
"""Implementaion of the AddTaskHook hook.

"""
from enaml.workbench.api import Workbench
from atom.api import Typed, Unicode, Tuple
from .base_hooks import BasePostExecutionHook
from ...tasks.api import RootTask
from ..engines.base_engine import ExecutionInfos, BaseEngine


class AddTasksHook(BasePostExecutionHook):
"""Post-execusion hook to add a hierarchy of tasks.

"""
#: Reference to the root task at the base of the hierarchy
root_task = Typed(RootTask)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those attributes should be documented using #: comments.


#: Reference to the measurement workbench
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

application workbench

The workbench is shared by the whole application and is not specific to the measurement plugin.

workbench = Typed(Workbench)

#: Reference to the measurement engine
engine = Typed(BaseEngine)

#: Reference to the hook root task path;
#: it is the same as the one of the measurement and will not be displayed
default_path = Unicode()

#: Reference to the build and runtime dependencies of the hook tasks
dependencies = Tuple()

def __init__(self, declaration, workbench):
self.root_task = RootTask()
self.workbench = workbench
super().__init__(declaration=declaration)

def check(self, workbench, **kwargs):
""" Check that the post-hook task can be executed

"""
# set the root_task default path to the one of the measure
self.root_task.default_path = self.measurement.root_task.default_path
res, traceback = self.root_task.check()
return res, traceback

def run(self, workbench, engine):
""" Execute the post-hook task

"""
# measure has collected the runtime dependencies given by list_runtimes
meas_deps = self.measurement.dependencies
runtime_deps = meas_deps.get_runtime_dependencies(self.declaration.id)
# on the other hand, we need to collect the build dependencies
build_deps = self.dependencies[0].dependencies
cmd = 'exopy.app.dependencies.collect'
core = workbench.get_plugin('enaml.workbench.core')
deps = core.invoke_command(cmd, dict(dependencies=build_deps,
kind='build'))
if deps.errors:
raise RuntimeError('Error when collecting the build dependencies')

infos = ExecutionInfos(id=self.measurement.id+'.posttask',
task=self.root_task,
build_deps=deps.dependencies,
runtime_deps=runtime_deps,
observed_entries=[], # no monitor for the hooks
checks=not self.measurement.forced_enqueued,
)
execution_result = engine.perform(infos)
self.engine = engine
return execution_result

def pause(self):
""" Pause the task

"""
self.engine.pause()

def resume(self):
""" Resume the task

"""
self.engine.resume()

def stop(self, force=False):
""" Stop the task

"""
self.engine.stop(force)

def list_runtimes(self, workbench):
""" Returns the run_time dependencies

"""
cmd = 'exopy.app.dependencies.analyse'
core = workbench.get_plugin('enaml.workbench.core')
deps = core.invoke_command(cmd,
{'obj': self.root_task,
'dependencies': ['build', 'runtime']})
self.dependencies = deps
return deps[1]

def get_state(self):
""" Return the informations to save the post hook

"""
core = self.workbench.get_plugin('enaml.workbench.core')
cmd = 'exopy.tasks.save'
task_prefs = core.invoke_command(cmd, {'task': self.root_task}, self)
return task_prefs

def set_state(self, state):
""" Load the post hook

"""
cmd = 'exopy.tasks.build_root'
kwarg = {'mode': 'from config', 'config': state,
'build_dep': self.workbench}
try:
core = self.workbench.get_plugin('enaml.workbench.core')
self.root_task = core.invoke_command(cmd, kwarg)
except Exception:
msg = 'Building %s, failed to restore post hook task : %s'
errors['post hook'] = msg % (state.get('name'), format_exc())
return None, errors
35 changes: 35 additions & 0 deletions exopy/measurement/hooks/addtask_view.enaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2015-2018 by Exopy Authors, see AUTHORS for more details.
#
# Distributed under the terms of the BSD license.
#
# The full license is in the file LICENCE, distributed with this software.
# -----------------------------------------------------------------------------
"""Widget associated with the AddTaskHook.

"""
from atom.api import Typed
from enaml.widgets.api import Container, PushButton, Label
from ...tasks.tasks.base_views import RootTaskView


enamldef AddTasksView(Container):
""" Widget used for the AddTaskHook

"""
#: Reference to the hook edited with this view
attr hook
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same those deserve a #: comment


#: Reference to the corresponding declaration
attr declaration

#: Reference to the corresponding measurement workbench
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

attr workbench

hug_width = 'ignore'
hug_height = 'ignore'
RootTaskView: view:
core = workbench.get_plugin('enaml.workbench.core')
task = hook.root_task
show_path = False
21 changes: 20 additions & 1 deletion exopy/measurement/manifest.enaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ from ..instruments.api import InstrUser

from .engines.process_engine import ProcessEngine
from .editors.api import Editor
from .hooks.api import PreExecutionHook
from .hooks.api import PreExecutionHook, PostExecutionHook

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -216,6 +216,25 @@ enamldef MeasureManifest(PluginManifest): manifest:
from .hooks.internal_checks import InternalChecksHook
return InternalChecksHook(declaration=self)

Extension:
id = 'post-execution'
point = manifest.id + '.post-execution'
PostExecutionHook:
id = 'exopy.addtask_hook'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say I am not a big fan fan of this name... RunTaskHook perhaps ?

description = ('Run an additional task at the end of a measure,'
'even if it is stopped.')

new => (workbench, default=False):
from .hooks.addtask_hook import AddTasksHook
return AddTasksHook(declaration=self,
workbench=workbench)

make_view => (workbench, hook):
with enaml.imports():
from .hooks.addtask_view import AddTasksView
return AddTasksView(declaration=self, hook=hook,
workbench=workbench)

Extension:
id = 'preferences'
point = 'exopy.app.preferences.plugin'
Expand Down
4 changes: 2 additions & 2 deletions exopy/measurement/measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ def save(self, path):
config.update(self.preferences_from_members())

# First save the task.
core = self.plugin.workbench.get_plugin(u'enaml.workbench.core')
cmd = u'exopy.tasks.save'
core = self.plugin.workbench.get_plugin('enaml.workbench.core')
cmd = 'exopy.tasks.save'
task_prefs = core.invoke_command(cmd, {'task': self.root_task,
'mode': 'config'}, self)
config['root_task'] = {}
Expand Down
38 changes: 18 additions & 20 deletions exopy/measurement/workspace/tools_edition.enaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ enamldef ToolsEditor(DestroyableContainer): main:
attr _names = ids_to_unique_names(getattr(measurement, _kind), reverse=True)

constraints << [hbox(tools, *(list(inc.objects) +
[vbox(add, remove, up, down, spacer)]))
]
[vbox(add, remove, up, down, spacer)])),
add.right == contents_right,
tools.bottom == contents_bottom,
tools.top == contents_top]

func update_items():
"""Update the list of tools.
Expand All @@ -132,6 +134,7 @@ enamldef ToolsEditor(DestroyableContainer): main:
self._names = ids_to_unique_names(getattr(measurement, _kind),
reverse=True)
tools.items = list(_names)

if not _names:
tools.selected_item = None

Expand Down Expand Up @@ -181,13 +184,13 @@ enamldef ToolsEditor(DestroyableContainer): main:

Include: inc:
objects << (make_view(tools.selected_item) if tools.selected_item
else [])
else [Container()])
destroy_old = False

PushButton: add:
text = 'Add'
enabled << not all([id in tools.items
for id in getattr(measurement.plugin, _kind)])
for id in getattr(measurement.plugin, _kind)])
clicked ::
selector = ToolSelector(measurement=measurement, kind=kind)
res = selector.exec_()
Expand Down Expand Up @@ -263,27 +266,22 @@ enamldef ToolsEditorDockItem(DockItem): main:
Page:
title = 'Pre-execution'
name = 'exopy.measurement.workspace.tools.pre_hooks'
Container:
constraints << [hbox(pre_ed, spacer)]
ToolsEditor: pre_ed:
kind = 'pre-hook'
measurement << main.measurement
mandatory_tools = ['exopy.internal_checks']
ToolsEditor: pre_ed:
kind = 'pre-hook'
measurement << main.measurement
mandatory_tools = ['exopy.internal_checks']

Page:
title = 'Monitors'
name = 'exopy.measurement.workspace.tools.monitors'
Container:
constraints << [hbox(mon_ed, spacer)]
ToolsEditor: mon_ed:
kind = 'monitor'
measurement << main.measurement
ToolsEditor: mon_ed:
kind = 'monitor'
measurement << main.measurement

Page:
title = 'Post-execution'
name = 'exopy.measurement.workspace.tools.post_hooks'
Container:
constraints << [hbox(post_ed, spacer)]
ToolsEditor: post_ed:
kind = 'post-hook'
measurement << main.measurement
ToolsEditor: post_ed:
kind = 'post-hook'
measurement << main.measurement

Loading