Skip to content

Commit

Permalink
Rename gui_context to event_loop (#365)
Browse files Browse the repository at this point in the history
* Rename IGuiContext to IEventLoop

* Rename setuptools entry point: traits_futures.gui_contexts -> traits_futures.event_loops

* Rename _gui_context attribute to _event_loop

* Rename IEventLoop implementations

* Rename gui_context attributes and local variables

* Rename gui_context_factory to event_loop_factory

* Rename a test method

* Rename module i_gui_context -> i_event_loop

* Rename i_gui_context_tests to i_event_loop_tests

* Rename a test method

* Rename toolkit-specific 'context' modules to 'event_loop'

* Rename ets_context module to ets_event_loop

* Rename test modules

* Manual updates of comments, docstrings, and documentation

* Revert some unrelated black-introduced changes

* Rename toolkit_context to toolkit_event_loop in ETSEventLoop

* Rename IEventLoop's event_loop_helper method to 'helper'

* Rename event_loop_helper -> helper and context_factory -> event_loop_factory

* Fix one more stray use of context in a docstring

* Update traits_futures/tests/i_event_loop_tests.py

Co-authored-by: Poruri Sai Rahul <rporuri@enthought.com>

Co-authored-by: Poruri Sai Rahul <rporuri@enthought.com>
  • Loading branch information
mdickinson and Poruri Sai Rahul committed Jul 5, 2021
1 parent a407055 commit 8331a1b
Show file tree
Hide file tree
Showing 39 changed files with 253 additions and 254 deletions.
8 changes: 6 additions & 2 deletions docs/source/guide/examples/headless.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
import asyncio
import random

from traits_futures.api import AsyncioContext, submit_iteration, TraitsExecutor
from traits_futures.api import (
AsyncioEventLoop,
submit_iteration,
TraitsExecutor,
)


def approximate_pi(sample_count=10**8, report_interval=10 ** 6):
Expand Down Expand Up @@ -59,7 +63,7 @@ def print_progress(event):


if __name__ == "__main__":
traits_executor = TraitsExecutor(gui_context=AsyncioContext())
traits_executor = TraitsExecutor(event_loop=AsyncioEventLoop())
traits_future = submit_iteration(traits_executor, approximate_pi)
traits_future.observe(print_progress, "result_event")

Expand Down
25 changes: 12 additions & 13 deletions docs/source/guide/toolkits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ Specifying a toolkit
--------------------

To explicitly specify which toolkit to use, you need to provide the
``gui_context`` parameter when instantiating the |TraitsExecutor|. The library
currently provides four different GUI contexts: |AsyncioContext|, |QtContext|,
|WxContext| and |ETSContext|. The first three correspond to the |asyncio|
event loop, the Qt event loop and the Wx event loop respectively.
``event_loop`` parameter when instantiating the |TraitsExecutor|. The library
currently provides four different event loops: |AsyncioEventLoop|,
|QtEventLoop|, |WxEventLoop| and |ETSEventLoop|.

By default, if no gui context is explicitly specified, an instance of
|ETSContext| is used. This follows the usual ETS rules to determine which
By default, if no event loop is explicitly specified, an instance of
|ETSEventLoop| is used. This follows the usual ETS rules to determine which
toolkit to use based on the value of the ``ETS_TOOLKIT`` environment variable,
on whether any other part of the ETS machinery has already "fixed" the toolkit,
and on which toolkits are available in the current Python environment.
Expand All @@ -50,13 +49,13 @@ directly.
However, you may find yourself in a situation where you already have Traits
Futures-based code that was written for a GUI setting, but that you want to be
able to execute in a environment that doesn't have the Qt or Wx toolkits
available. In that case, Traits Futures can use the |AsyncioContext| to
available. In that case, Traits Futures can use the |AsyncioEventLoop| to
deliver results to the main thread's |asyncio| event loop instead of to
a GUI framework's event loop.

Here's an :download:`example script <examples/headless.py>` that uses the
|AsyncioContext| in order to execute Traits Futures tasks within the context of
an asyncio event loop.
|AsyncioEventLoop| in order to execute Traits Futures tasks within the context
of an asyncio event loop.

.. literalinclude:: examples/headless.py

Expand All @@ -66,8 +65,8 @@ an asyncio event loop.

.. |asyncio| replace:: :mod:`asyncio`
.. |concurrent.futures| replace:: :mod:`concurrent.futures`
.. |AsyncioContext| replace:: :class:`~.AsyncioContext`
.. |ETSContext| replace:: :class:`~.ETSContext`
.. |QtContext| replace:: :class:`~.QtContext`
.. |WxContext| replace:: :class:`~.WxContext`
.. |AsyncioEventLoop| replace:: :class:`~.AsyncioEventLoop`
.. |ETSEventLoop| replace:: :class:`~.ETSEventLoop`
.. |QtEventLoop| replace:: :class:`~.QtEventLoop`
.. |WxEventLoop| replace:: :class:`~.WxEventLoop`
.. |TraitsExecutor| replace:: :class:`~.TraitsExecutor`
12 changes: 6 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ def get_long_description():
"Programming Language :: Python :: 3.9",
],
entry_points={
"traits_futures.gui_contexts": [
"asyncio = traits_futures.asyncio.context:AsyncioContext",
"null = traits_futures.asyncio.context:AsyncioContext",
"qt = traits_futures.qt.context:QtContext",
"qt4 = traits_futures.qt.context:QtContext",
"wx = traits_futures.wx.context:WxContext",
"traits_futures.event_loops": [
"asyncio = traits_futures.asyncio.event_loop:AsyncioEventLoop",
"null = traits_futures.asyncio.event_loop:AsyncioEventLoop",
"qt = traits_futures.qt.event_loop:QtEventLoop",
"qt4 = traits_futures.qt.event_loop:QtEventLoop",
"wx = traits_futures.wx.event_loop:WxEventLoop",
],
},
python_requires=">=3.6",
Expand Down
24 changes: 12 additions & 12 deletions traits_futures/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@
- :class:`~.MultiprocessingContext`
- :class:`~.MultithreadingContext`
GUI contexts
------------
Event loops
-----------
- :class:`~.IGuiContext`
- :class:`~.AsyncioContext`
- :class:`~.ETSContext`
- :class:`~.IEventLoop`
- :class:`~.AsyncioEventLoop`
- :class:`~.ETSEventLoop`
"""
from traits_futures.asyncio.context import AsyncioContext
from traits_futures.asyncio.event_loop import AsyncioEventLoop
from traits_futures.background_call import CallFuture, submit_call
from traits_futures.background_iteration import (
IterationFuture,
Expand All @@ -90,7 +90,7 @@
submit_progress,
)
from traits_futures.base_future import BaseFuture
from traits_futures.ets_context import ETSContext
from traits_futures.ets_event_loop import ETSEventLoop
from traits_futures.executor_states import (
ExecutorState,
RUNNING,
Expand All @@ -106,8 +106,8 @@
FutureState,
WAITING,
)
from traits_futures.i_event_loop import IEventLoop
from traits_futures.i_future import IFuture
from traits_futures.i_gui_context import IGuiContext
from traits_futures.i_parallel_context import IParallelContext
from traits_futures.i_task_specification import ITaskSpecification
from traits_futures.multiprocessing_context import MultiprocessingContext
Expand Down Expand Up @@ -147,8 +147,8 @@
"IParallelContext",
"MultiprocessingContext",
"MultithreadingContext",
# GUI contexts
"IGuiContext",
"AsyncioContext",
"ETSContext",
# Event loops
"IEventLoop",
"AsyncioEventLoop",
"ETSEventLoop",
]
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
# Thanks for using Enthought open source!

"""
IGuiContext implementation for the main-thread asyncio event loop.
IEventLoop implementation for the main-thread asyncio event loop.
"""
import asyncio

from traits_futures.asyncio.event_loop_helper import EventLoopHelper
from traits_futures.asyncio.pingee import Pingee
from traits_futures.i_gui_context import IGuiContext
from traits_futures.i_event_loop import IEventLoop


@IGuiContext.register
class AsyncioContext:
@IEventLoop.register
class AsyncioEventLoop:
"""
IGuiContext implementation for the main-thread asyncio event loop.
IEventLoop implementation for the main-thread asyncio event loop.
"""

def __init__(self):
Expand All @@ -44,7 +44,7 @@ def pingee(self, on_ping):
"""
return Pingee(on_ping=on_ping, event_loop=self._event_loop)

def event_loop_helper(self):
def helper(self):
"""
Return a new event loop helper.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
# Thanks for using Enthought open source!

"""
Tests for the asyncio GUI context.
Tests for the asyncio event loop.
"""


import unittest

from traits_futures.asyncio.context import AsyncioContext
from traits_futures.tests.i_gui_context_tests import IGuiContextTests
from traits_futures.asyncio.event_loop import AsyncioEventLoop
from traits_futures.tests.i_event_loop_tests import IEventLoopTests


class TestAsyncioContext(IGuiContextTests, unittest.TestCase):
class TestAsyncioEventLoop(IEventLoopTests, unittest.TestCase):

#: Factory for instances of the context.
context_factory = AsyncioContext
#: Factory for instances of the event loop.
event_loop_factory = AsyncioEventLoop
6 changes: 3 additions & 3 deletions traits_futures/asyncio/tests/test_event_loop_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

import unittest

from traits_futures.asyncio.context import AsyncioContext
from traits_futures.asyncio.event_loop import AsyncioEventLoop
from traits_futures.tests.i_event_loop_helper_tests import (
IEventLoopHelperTests,
)


class TestEventLoopHelper(IEventLoopHelperTests, unittest.TestCase):

#: Zero-parameter callable that creates a suitable IGuiContext instance.
gui_context_factory = AsyncioContext
#: Zero-parameter callable that creates a suitable IEventLoop instance.
event_loop_factory = AsyncioEventLoop
4 changes: 2 additions & 2 deletions traits_futures/asyncio/tests/test_pingee.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@

import unittest

from traits_futures.asyncio.context import AsyncioContext
from traits_futures.asyncio.event_loop import AsyncioEventLoop
from traits_futures.testing.gui_test_assistant import GuiTestAssistant
from traits_futures.tests.i_pingee_tests import IPingeeTests


class TestPingee(GuiTestAssistant, IPingeeTests, unittest.TestCase):

gui_context_factory = AsyncioContext
event_loop_factory = AsyncioEventLoop
40 changes: 21 additions & 19 deletions traits_futures/ets_context.py → traits_futures/ets_event_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,34 @@
# Thanks for using Enthought open source!

"""
Context with toolkit selection matching that of ETS.
Event loop with toolkit selection matching that of ETS.
This module provides an IGuiContext implementation that's determined in the
This module provides an IEventLoop implementation that's determined in the
same way that the toolkit is determined for TraitsUI and Pyface, using the
ETS_TOOLKIT environment variable if set, and examining the available toolkits
if not.
"""

from traits_futures.i_gui_context import IGuiContext
from traits_futures.i_event_loop import IEventLoop


@IGuiContext.register
class ETSContext:
@IEventLoop.register
class ETSEventLoop:
"""
IGuiContext implementation with lazily-determined toolkit.
IEventLoop implementation with lazily-determined toolkit.
The first time this context is used, an appropriate toolkit will
The first time this event loop is used, an appropriate toolkit will
be selected.
The toolkit selection mechanism used matches that used by Pyface, and
is based on the value of the ETS_TOOLKIT environment variable, followed
an examination of the available setuptools entry points under the
entry point group "traits_futures.gui_contexts".
entry point group "traits_futures.event_loops".
"""

def __init__(self):
self._toolkit_context = None
self._toolkit_event_loop = None

def pingee(self, on_ping):
"""
Expand All @@ -53,28 +53,30 @@ def pingee(self, on_ping):
-------
pingee : IPingee
"""
return self.toolkit_context.pingee(on_ping)
return self.toolkit_event_loop.pingee(on_ping)

def event_loop_helper(self):
def helper(self):
"""
Return a new event loop helper.
Returns
-------
event_loop_helper : IEventLoopHelper
"""
return self.toolkit_context.event_loop_helper()
return self.toolkit_event_loop.helper()

@property
def toolkit_context(self):
def toolkit_event_loop(self):
"""
Fix the toolkit for this context, using the same mechanism as Pyface
uses to find its toolkits.
Find and fix the toolkit, using the same mechanism that Pyface uses to
find its toolkits.
"""
from pyface.base_toolkit import find_toolkit

if self._toolkit_context is None:
toolkit_context_class = find_toolkit("traits_futures.gui_contexts")
self._toolkit_context = toolkit_context_class()
if self._toolkit_event_loop is None:
toolkit_event_loop_class = find_toolkit(
"traits_futures.event_loops"
)
self._toolkit_event_loop = toolkit_event_loop_class()

return self._toolkit_context
return self._toolkit_event_loop
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
# Thanks for using Enthought open source!

"""
Interface for GUI toolkit context objects.
Interface for toolkit-specific event-loop details.
"""

import abc


class IGuiContext(abc.ABC):
class IEventLoop(abc.ABC):
"""
Interface for objects usable in a GUI context.
Interface for toolkit-specific event-loop details.
An instance of this class provides consistent mechanisms to get
objects related to the event loop for a particular choice of GUI
toolkit or event loop.
objects related to a particular event loop (for example, that provided
by a GUI toolkit).
"""

@abc.abstractmethod
Expand All @@ -42,7 +42,7 @@ def pingee(self, on_ping):
"""

@abc.abstractmethod
def event_loop_helper(self):
def helper(self):
"""
Return a new event loop helper.
Expand Down
10 changes: 5 additions & 5 deletions traits_futures/i_event_loop_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def init(self):
Prepare the event loop for use.
This method is not thread-safe. It should always be called on the
main GUI thread.
event loop's thread.
"""

@abc.abstractmethod
Expand All @@ -39,7 +39,7 @@ def dispose(self):
Dispose of any resources used by this object.
This method is not thread-safe. It should always be called on the
main GUI thread.
event loop's thread.
"""

@abc.abstractmethod
Expand All @@ -50,8 +50,8 @@ def setattr_soon(self, obj, name, value):
In typical usage, *obj* will be a ``HasTraits`` instance and
*name* will be the name of a trait on *obj*.
This method is not thread-safe. It's designed to be called
from the main thread.
This method is not thread-safe. It should always be called on the
event loop's thread.
Parameters
----------
Expand All @@ -73,7 +73,7 @@ def run_until(self, object, trait, condition, timeout):
the trait changes.
This method is not thread-safe. It should always be called on the
main GUI thread.
event loop's thread.
Parameters
----------
Expand Down
2 changes: 1 addition & 1 deletion traits_futures/i_message_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- Creating "pipes". A pipe is a pair of linked :class:`IMessageSender` and
:class:`IMessageReceiver` objects that provide communications between a
background task and a foreground receiver.
- Ensuring that messages are routed appropriately via a running GUI event loop.
- Ensuring that messages are routed appropriately via a running event loop.
- Disposing of pipes on request.
The message routing layer of Traits Futures provides no meaning or structure to
Expand Down

0 comments on commit 8331a1b

Please sign in to comment.