Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract public 'dispatch' method from task_sent #427

Merged
merged 3 commits into from
Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
16 changes: 7 additions & 9 deletions docs/source/guide/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,13 @@ Now we define a dedicated future class ``FizzBuzzFuture`` for this background
task type. The most convenient way to do this is to inherit from the
|BaseFuture| class, which is a |HasStrictTraits| subclass that provides the
|IFuture| interface. Messages coming into the |BaseFuture| instance from the
background task are processed by the |task_sent| method. The default
implementation of this method expects incoming messages to have the
form ``(message_type, message_arg)``, and does a couple of things:
background task are processed by the |dispatch| method. The default
implementation of this method expects incoming messages to have the form
``(message_type, message_arg)``, and it converts each such message to a call to
a method named ``_process_<message_type>``, passing ``message_arg`` as an
argument.

- it dispatches the argument of each message to a method named
``_process_<message_type>``.
- it suppresses any messages that arrive after cancellation has been requested

The |task_sent| method can be safely overridden by subclasses if messages
The |dispatch| method can be safely overridden by subclasses if messages
do not have the form ``(message_type, message_arg)``, or if some
other dispatch mechanism is wanted. For this example, we use the default
dispatch mechanism, so all we need to do is to define methods
Expand Down Expand Up @@ -182,6 +180,7 @@ of the new background task type:

.. |BaseFuture| replace:: :class:`~.BaseFuture`
.. |BaseTask| replace:: :class:`~.BaseTask`
.. |dispatch| replace:: :meth:`~.BaseFuture.dispatch`
.. |exception| replace:: :attr:`~traits_futures.i_future.IFuture.exception`
.. |HasStrictTraits| replace:: :class:`~traits.has_traits.HasStrictTraits`
.. |IFuture| replace:: :class:`~.IFuture`
Expand All @@ -191,5 +190,4 @@ of the new background task type:
.. |submit_call| replace:: :func:`~.submit_call`
.. |submit_iteration| replace:: :func:`~.submit_iteration`
.. |submit_progress| replace:: :func:`~.submit_progress`
.. |task_sent| replace:: :meth:`~.BaseFuture._task_sent`
.. |TraitsExecutor| replace:: :class:`~.TraitsExecutor`
48 changes: 29 additions & 19 deletions traits_futures/base_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ class BaseFuture(HasRequiredTraits):
Convenience base class for the various flavours of Future.
"""

# IFuture interface #######################################################

#: The state of the background task, to the best of the knowledge of
#: this future. One of the six constants ``WAITING``, ``EXECUTING``,
#: ``COMPLETED``, ``FAILED``, ``CANCELLING`` or ``CANCELLED``.
Expand Down Expand Up @@ -257,16 +259,11 @@ def receive(self, message):
getattr(self, method_name)(message_arg)
return message_type in FINAL_MESSAGES

# Semi-private methods ####################################################

# These methods represent the state transitions in response to external
# events. They're used by the FutureWrapper, and are potentially useful for
# unit testing, but are not intended for use by the users of Traits
# Futures.
# BaseFuture interface ####################################################

def _task_sent(self, message):
def dispatch(self, message):
"""
Automate dispatch of different types of message.
Dispatch a message arriving from the associated BaseTask.

This is a convenience function, and may be safely overridden by
subclasses that want to use a different dispatch mechanism. For
Expand All @@ -275,27 +272,40 @@ def _task_sent(self, message):
that method. Subclasses then only need to provide the appropriate
``_process_<msgtype>`` methods.

If the future is already in ``CANCELLING`` state, no message is
dispatched.
Parameters
----------
message : object
Message sent by the background task. The default implementation of
this method expects the message to be in the form ``(message_type,
message_args)`` with ``message_type`` a string.
"""
message_type, message_arg = message
method_name = "_process_{}".format(message_type)
getattr(self, method_name)(message_arg)

# State transitions #######################################################

Internal state:
* _CANCELLING_AFTER_STARTED -> _CANCELLING_AFTER_STARTED
* EXECUTING -> EXECUTING
# These methods represent state transitions in response to external events.

def _task_sent(self, message):
"""
Automate dispatch of different types of message.

Delegates the actual work to the :meth:`dispatch` method,
which can be overridden by subclasses. Messages received after
cancellation are ignored.

Parameters
----------
message : tuple
Message from the background task, in the form (message_type,
message_args).
message : object
Message from the background task.
"""

if self._internal_state == _CANCELLING_AFTER_STARTED:
# Ignore messages that arrive after a cancellation request.
return
elif self._internal_state == EXECUTING:
message_type, message_arg = message
method_name = "_process_{}".format(message_type)
getattr(self, method_name)(message_arg)
self.dispatch(message)
else:
raise _StateTransitionError(
"Unexpected custom message in internal state {!r}".format(
Expand Down
2 changes: 1 addition & 1 deletion traits_futures/i_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class IFuture(Interface):
#: The state of the background task, to the best of the knowledge of
#: this future. One of the six constants ``WAITING``, ``EXECUTING``,
#: ``COMPLETED``, ``FAILED``, ``CANCELLING`` or ``CANCELLED``.
state = FutureState
Copy link
Member Author

Choose a reason for hiding this comment

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

Sigh. Sorry, this was an unrelated fix; let me pull it into a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

state = Property(FutureState)

#: True if cancellation of the background task can be requested,
#: else False. Cancellation of the background task can be requested
Expand Down