GithubHelp home page GithubHelp logo

enthought / envisage Goto Github PK

View Code? Open in Web Editor NEW
80.0 55.0 26.0 8.29 MB

Envisage is a Python-based framework for building applications whose functionalities can be extended by adding "plug-ins".

Home Page: http://docs.enthought.com/envisage/

License: Other

Python 99.08% HTML 0.92%

envisage's Introduction

envisage: extensible application framework

Documentation: https://docs.enthought.com/envisage

Envisage is a Python-based framework for building extensible applications, that is, applications whose functionality can be extended by adding "plug-ins". Envisage provides a standard mechanism for features to be added to an application, whether by the original developer or by someone else. In fact, when you build an application using Envisage, the entire application consists primarily of plug-ins. In this respect, it is similar to the Eclipse and Netbeans frameworks for Java applications.

Each plug-in is able to:

  • Advertise where and how it can be extended (its "extension points").
  • Contribute extensions to the extension points offered by other plug-ins or its own.
  • Create and share the objects that perform the real work of the application ("services").

The Envisage project provides the basic machinery of the Envisage framework. You are free to use:

  • the envisage CorePlugin available through the envisage.api module
  • plug-ins from the envisage plugins module
  • plug-ins from other ETS projects that expose their functionality as plug-ins
  • plug-ins that you create yourself

Prerequisites

The supported versions of Python are Python >= 3.7. Envisage requires:

Envisage has the following optional dependencies:

To build the full documentation one needs:

envisage's People

Contributors

aaronayres35 avatar anshsrtv avatar brycehendrix avatar cfarrow avatar corranwebster avatar dpinte avatar epatters avatar homosapien-lcy avatar itziakos avatar jjenthought avatar jonathanrocher avatar kamalx avatar kitchoi avatar mchilvers avatar mdickinson avatar mgrady3 avatar pankajp avatar pib avatar prabhuramachandran avatar pradyunsg avatar punchagan avatar rahulporuri avatar rkern avatar robmcmullen avatar scopatz avatar sjagoe avatar skailasa avatar snegovikufa avatar swt2c avatar warrenweckesser avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

envisage's Issues

Use of `ExtensionPoint` in TasksApplication is confusing

[Arising from conversations with @stefanoborini]

There's a surprising and potentially confusing use of the ExtensionPoint trait type in the TasksApplication: the extension points in the application appear to duplicate those in the TasksPlugin. In the TasksApplication class definition, we have:

class TasksApplication(Application):

    ...

    # Extension point IDs.
    TASK_FACTORIES = 'envisage.ui.tasks.tasks'
    TASK_EXTENSIONS = 'envisage.ui.tasks.task_extensions'

    ...

    # Contributed task factories. This attribute is primarily for run-time
    # inspection; to instantiate a task, use the 'create_task' method.
    task_factories = ExtensionPoint(id=TASK_FACTORIES)

    # Contributed task extensions.
    task_extensions = ExtensionPoint(id=TASK_EXTENSIONS)

In the TasksPlugin definition, we have (where PKG evaluates to envisage.ui.tasks)

class TasksPlugin(Plugin):

    ...

    TASKS = PKG + '.tasks'
    TASK_EXTENSIONS = PKG + '.task_extensions'

    ...

    tasks = ExtensionPoint(
        List(Instance('envisage.ui.tasks.task_factory.TaskFactory')),
        id=TASKS,
        desc="""

        This extension point makes tasks avaiable to the application.

        Each contribution to the extension point must be an instance of
        'envisage.tasks.api.TaskFactory.
        """)

    task_extensions = ExtensionPoint(
        List(Instance('envisage.ui.tasks.task_extension.TaskExtension')),
        id=TASK_EXTENSIONS,
        desc="""

        This extension point permits the contribution of new actions and panes
        to existing tasks (without creating a new task).

        Each contribution to the extension point must be an instance of
        'envisage.tasks.api.TaskExtension'.
        """)

What seems to be happening here is that only the TasksPlugin definitions are relevant for the purposes of creating and registering the extension points: the ExtensionPoint.connect_extension_point_traits method only gets called for plugin objects, not for the application object. The TasksApplication redeclarations then provide a lazy way of accessing the list of current task factories / task extensions. In particular, this means that attempting to listen to task_factories_items (for example) on the application won't work, since the relevant trait connections haven't been hooked up.

At the least, I'd suggest documenting these uses in TasksApplication a little better to indicate what's going on. (There's a comment for the task_factories trait that's suggestive, but isn't explicit that this isn't really where the extension point is being defined.) But we may also be able to find a better way to do this.

setup.py test failure

ERROR: fbi_plugin_definition (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: fbi_plugin_definition
Traceback (most recent call last):
  File "/usr/lib64/python3.7/unittest/loader.py", line 154, in loadTestsFromName
    module = __import__(module_name)
  File "/builddir/build/BUILD/envisage-4.7.1/envisage/plugins/debug/fbi_plugin_definition.py", line 17, in <module>
    from envisage.core.core_plugin_definition \
ModuleNotFoundError: No module named 'envisage.core'

There seem to be a number of references to envisage.core that does not appear to exists:

envisage-4.7.1/envisage/developer/code_browser/module.py:        '/enthought/envisage/core/core_plugin_definition.py'
envisage-4.7.1/envisage/developer/code_browser/module.py:        'envisage.core.core_plugin_definition'
envisage-4.7.1/envisage/plugins/debug/fbi_plugin_definition.py:from envisage.core.core_plugin_definition \
envisage-4.7.1/examples/plugins/single_project/sample_project/data/plugin/plugin_definition.py:from envisage.core.core_plugin_definition import ApplicationObject

Envisage/ETS roadmap

I'm looking into porting an existing application to ETS/Envisage. In some Enthought repos, I currently see a lot of movement, while others look stale since years. It looks like Enthought is in a major overhaul process, and I'm a bit unsure how to proceed from here.

Is there a roadmap or any kind of plan for ETS and Envisage I can look into? I'm looking for feature development milestones and deprecation plans as well as a rough time estimate so I know what to embrace and what to avoid. I don't mind if the plan slips by months as I'll be working with the current (release) codebase – or should I start from master instead? Should I build a Pyface resp. TraitsUI app instead and later move it to envisage?

Can Envisage 4.5 be used together with v5 of Pyface and TraitsUI or should I use older versions of both?

`bind_extension_point` prevents object garbage collection

bind_extension_point stores a reference to the binding and prevents collection of the object, and it does not offer any way to unbind either.

ExtensionPointBinding objects are stored in a WeakKeyDictionary mapping object weakref to the ExtensionPointBinding instance, but the binding itself stores a strong reference to the object and hence prevents its garbage collection.

Python 3 issue with saving Tasks app state

Reported by Eric McDonald:

File "C:\Anaconda3\lib\site-packages\envisage\ui\tasks\tasks_application.py", line 315, in _load_state 
restored_state = pickle.load(f) 
TypeError: a bytes-like object is required, not 'str'

and similar errors. Reported fix is that files need to be opened in rb mode (which I think is bug in Python 2.7 as well - things probably aren't working as expected under Windows in some situations!)

Application.get_extensions gives infinite recursion against Traits master

The following script gives a RecursionError when run against Traits master. The change which triggered this looks very likely to be enthought/traits#382. The recursion seems to be a result of this change mixed with the inspect magic used by Envisage.

Here's the script

from envisage.api import Application, ExtensionPoint, Plugin
from traits.api import List

class PluginA(Plugin):
    id = 'A'
    x  = ExtensionPoint(List, id='bob')

application = Application(plugins=[PluginA()])
application.get_extensions('bob')

And here's the start and end of the recursion error:

(envisage-test-3.6-pyqt)bash-3.2$ python ~/Desktop/envisage_bug.py 
Traceback (most recent call last):
  File "/Users/mdickinson/Desktop/envisage_bug.py", line 9, in <module>
    application.get_extensions('bob')
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/application.py", line 205, in get_extensions
    return self.extension_registry.get_extensions(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/extension_registry.py", line 71, in get_extensions
    return self._get_extensions(extension_point_id)[:]
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/provider_extension_registry.py", line 94, in _get_extensions
    extensions = self._initialize_extensions(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/provider_extension_registry.py", line 280, in _initialize_extensions
    extensions.append(provider.get_extensions(extension_point_id)[:])
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/plugin.py", line 135, in get_extensions
    extensions = self._harvest_methods(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/plugin.py", line 368, in _harvest_methods
    for name, value in inspect.getmembers(self):
  File "/Users/mdickinson/.edm/envs/envisage-test-3.6-pyqt/lib/python3.6/inspect.py", line 315, in getmembers
    value = getattr(object, key)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/extension_point.py", line 154, in get
    extensions = extension_registry.get_extensions(self.id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/application.py", line 205, in get_extensions
    return self.extension_registry.get_extensions(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/extension_registry.py", line 71, in get_extensions

[ ... many repetitions ... ]

  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/provider_extension_registry.py", line 280, in _initialize_extensions
    extensions.append(provider.get_extensions(extension_point_id)[:])
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/plugin.py", line 135, in get_extensions
    extensions = self._harvest_methods(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/plugin.py", line 368, in _harvest_methods
    for name, value in inspect.getmembers(self):
  File "/Users/mdickinson/.edm/envs/envisage-test-3.6-pyqt/lib/python3.6/inspect.py", line 315, in getmembers
    value = getattr(object, key)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/extension_point.py", line 154, in get
    extensions = extension_registry.get_extensions(self.id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/application.py", line 205, in get_extensions
    return self.extension_registry.get_extensions(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/extension_registry.py", line 71, in get_extensions
    return self._get_extensions(extension_point_id)[:]
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/provider_extension_registry.py", line 94, in _get_extensions
    extensions = self._initialize_extensions(extension_point_id)
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/provider_extension_registry.py", line 280, in _initialize_extensions
    extensions.append(provider.get_extensions(extension_point_id)[:])
  File "/Users/mdickinson/Enthought/ETS/envisage/envisage/plugin.py", line 122, in get_extensions
    trait_names = self.trait_names(contributes_to=extension_point_id)
  File "/Users/mdickinson/.edm/envs/envisage-test-3.6-pyqt/lib/python3.6/site-packages/traits/has_traits.py", line 3104, in trait_names
    return list(self.traits( **metadata ).keys())
  File "/Users/mdickinson/.edm/envs/envisage-test-3.6-pyqt/lib/python3.6/site-packages/traits/has_traits.py", line 3003, in traits
    for name, trt in list(self._instance_traits().items()):
RecursionError: maximum recursion depth exceeded while calling a Python object
(envisage-test-3.6-pyqt)bash-3.2$ 

Include Jupyter packages in CI setup.

Since the CI rework in #111, 4 tests are being skipped on all platforms. Those tests are related to the Jupyter/IPython plugins. We should extend the CI setup so that those tests are executed.

Note that the tests fail with the most recent versions of Jupyter, so there's some investigation and bug fixing to be done here too.

Tests are unnecessarily noisy

The envisage test suite sends a lot of output to stdout. That output obscures warnings that might indicate an actual issue, and makes it hard to see the failures and errors. It would be good to clean this up where possible.

Warn on failed service lookups?

We discovered recently that two service lookups in our Envisage application had been failing (i.e., returning None) for a while, thanks to misspelled protocol strings, without us noticing.

Would it be worth issuing a logger.warn for failed service lookups?

Use `traits.util.import_symbol` instead of `ImportManager` in envisage

We have implementations of importing a symbol from a string scattered all over ETS. The current implementation in traits.util.import_symbol is recent, and handles both the new way of specifying symbols (tarfile:TarFile.open') and the old, frowned-upon way of doing it ('tarfile.TarFile.open').

python 3.5 test failure

Is python3 supported? I'm getting:

/usr/bin/python3 setup.py test
running test
running egg_info
writing entry points to envisage.egg-info/entry_points.txt
writing dependency_links to envisage.egg-info/dependency_links.txt
writing envisage.egg-info/PKG-INFO
writing requirements to envisage.egg-info/requires.txt
writing top-level names to envisage.egg-info/top_level.txt
reading manifest file 'envisage.egg-info/SOURCES.txt'
writing manifest file 'envisage.egg-info/SOURCES.txt'
running build_ext
Traceback (most recent call last):
  File "setup.py", line 158, in <module>
    zip_safe = False,
  File "/usr/lib64/python3.5/distutils/core.py", line 148, in setup
    dist.run_commands()
  File "/usr/lib64/python3.5/distutils/dist.py", line 955, in run_commands
    self.run_command(cmd)
  File "/usr/lib64/python3.5/distutils/dist.py", line 974, in run_command
    cmd_obj.run()
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 159, in run
    self.with_project_on_sys_path(self.run_tests)
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 140, in with_project_on_sys_path
    func()
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 180, in run_tests
    testRunner=self._resolve_as_ep(self.test_runner),
  File "/usr/lib64/python3.5/unittest/main.py", line 93, in __init__
    self.parseArgs(argv)
  File "/usr/lib64/python3.5/unittest/main.py", line 123, in parseArgs
    self._do_discovery([])
  File "/usr/lib64/python3.5/unittest/main.py", line 228, in _do_discovery
    self.test = loader.discover(self.start, self.pattern, self.top)
  File "/usr/lib64/python3.5/unittest/loader.py", line 341, in discover
    tests = list(self._find_tests(start_dir, pattern))
  File "/usr/lib64/python3.5/unittest/loader.py", line 398, in _find_tests
    full_path, pattern, namespace)
  File "/usr/lib64/python3.5/unittest/loader.py", line 475, in _find_test_path
    tests = self.loadTestsFromModule(package, pattern=pattern)
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 38, in loadTestsFromModule
    tests.append(self.loadTestsFromName(submodule))
  File "/usr/lib64/python3.5/unittest/loader.py", line 190, in loadTestsFromName
    return self.loadTestsFromModule(obj)
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 38, in loadTestsFromModule
    tests.append(self.loadTestsFromName(submodule))
  File "/usr/lib64/python3.5/unittest/loader.py", line 190, in loadTestsFromName
    return self.loadTestsFromModule(obj)
  File "/usr/lib/python3.5/site-packages/setuptools/command/test.py", line 38, in loadTestsFromModule
    tests.append(self.loadTestsFromName(submodule))
  File "/usr/lib64/python3.5/unittest/loader.py", line 153, in loadTestsFromName
    module = __import__(module_name)
  File "/builddir/build/BUILD/envisage-4.5.0/envisage/developer/ui/api.py", line 1, in <module>
    from .view.plugin_browser import browse_plugin
  File "/builddir/build/BUILD/envisage-4.5.0/envisage/developer/ui/view/plugin_browser.py", line 11, in <module>
    class ExtensionPointModel(Hastraits):
NameError: name 'Hastraits' is not defined

Drop support for Python 2.6, Python 3.3, Python 3.4

Dropping support for outdated versions of Python (2.6, 3.3, 3.4) is long overdue, and is already partially complete.

  • Remove support in Travis, Appveyor and etstool.py (already done)
  • Remove unnecessary eggs from envisage/tests/eggs and envisage/tests/bad_eggs
  • Document Python version requirements clearly somewhere (possibly in the README is good enough)
  • (Possibly) add explicit sys.version check in setup.py

See also #83, where CI support for Python 2.6 was removed.

ipython_kernel example broken with IPython4

When trying to open the ipython kernel view from the example app, while having ipython4 installed, I get an error while trying to read a security file:

---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)
/home/jrocher/Projects/ETS_source/pyface/pyface/ui/qt4/action/action_item.pyc in _qt4_on_triggered(self=<pyface.ui.qt4.action.action_item._MenuItem object>)
    161 
    162             else:
--> 163                 self.controller.perform(action, action_event)
        self.controller.perform = <bound method TaskActionController.perform of <pyface.tasks.action.task_action_controller.TaskActionController object at 0x7f97466604d0>>
        action = <envisage.plugins.ipython_kernel.actions.StartQtConsoleAction object at 0x7f9746660710>
        action_event = <pyface.action.action_event.ActionEvent object at 0x7f972ad7b0b0>
    164 
    165         else:

/home/jrocher/Projects/ETS_source/pyface/pyface/tasks/action/task_action_controller.pyc in perform(self=<pyface.tasks.action.task_action_controller.TaskActionController object>, action=<envisage.plugins.ipython_kernel.actions.StartQtConsoleAction object>, event=<pyface.action.action_event.ActionEvent object>)
     29         """
     30         event.task = self.task
---> 31         return action.perform(event)
        action.perform = <bound method StartQtConsoleAction.perform of <envisage.plugins.ipython_kernel.actions.StartQtConsoleAction object at 0x7f9746660710>>
        event = <pyface.action.action_event.ActionEvent object at 0x7f972ad7b0b0>
     32 
     33     def add_to_menu(self, item):

/home/jrocher/Projects/ETS_source/envisage/envisage/plugins/ipython_kernel/actions.pyc in perform(self=<envisage.plugins.ipython_kernel.actions.StartQtConsoleAction object>, event=<pyface.action.action_event.ActionEvent object>)
     16 
     17     def perform(self, event=None):
---> 18         self.kernel.new_qt_console()
        self.kernel.new_qt_console = <bound method InternalIPKernel.new_qt_console of <envisage.plugins.ipython_kernel.internal_ipkernel.InternalIPKernel object at 0x7f97466605f0>>

/home/jrocher/Projects/ETS_source/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.pyc in new_qt_console(self=<envisage.plugins.ipython_kernel.internal_ipkernel.InternalIPKernel object>)
     71         console = connect_qtconsole(
     72             self.ipkernel.connection_file, profile=self.ipkernel.profile,
---> 73             argv=['--no-confirm-exit'],
        global argv = undefined
     74         )
     75         self.consoles.append(console)

/home/jrocher/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/ipykernel/connect.pyc in connect_qtconsole(connection_file=u'kernel-27690.json', argv=['--no-confirm-exit'], profile=u'default')
    160         cf = get_connection_file()
    161     else:
--> 162         cf = find_connection_file(connection_file, profile=profile)
        cf = undefined
        global find_connection_file = <function find_connection_file at 0x7f9747a16b18>
        connection_file = u'kernel-27690.json'
        profile = u'default'
    163 
    164     cmd = ';'.join([

/home/jrocher/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/ipykernel/connect.pyc in find_connection_file(filename=u'kernel-27690.json', profile=u'default')
     83     security_dir = profile_dir.security_dir
     84     
---> 85     return jupyter_client.find_connection_file(filename, path=['.', security_dir])
        global jupyter_client.find_connection_file = <function find_connection_file at 0x7f974834aa28>
        filename = u'kernel-27690.json'
        global path = undefined
        security_dir = u'/home/jrocher/.ipython/profile_default/security'
     86 
     87 

/home/jrocher/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/jupyter_client/connect.pyc in find_connection_file(filename=u'kernel-27690.json', path=['.', u'/home/jrocher/.ipython/profile_default/security'], profile=None)
    183     
    184     if not matches:
--> 185         raise IOError("Could not find %r in %r" % (filename, path))
        global IOError = undefined
        filename = u'kernel-27690.json'
        path = ['.', u'/home/jrocher/.ipython/profile_default/security']
    186     elif len(matches) == 1:
    187         return matches[0]

IOError: Could not find u'kernel-27690.json' in ['.', u'/home/jrocher/.ipython/profile_default/security']

FYI, there are some warnings when starting the example:

$ python example.py 
DEBUG:envisage.application:---------- application starting ----------
DEBUG:envisage.plugin_manager:plugin envisage.core starting
DEBUG:envisage.provider_extension_registry:extensions to <envisage.preferences> <[[], [], [], [], []]>
DEBUG:apptools.preferences.preferences:loading preferences from </home/jrocher/.enthought/example.ipython_kernel/preferences.ini>
DEBUG:envisage.provider_extension_registry:extensions to <envisage.class_load_hooks> <[[], [], [], [], []]>
DEBUG:envisage.provider_extension_registry:extensions to <envisage.categories> <[[], [], [], [], []]>
DEBUG:envisage.provider_extension_registry:extensions to <envisage.service_offers> <[[], [], [<envisage.service_offer.ServiceOffer object at 0x7f974ae72290>], [], [<envisage.service_offer.ServiceOffer object at 0x7f974ae724d0>]]>
DEBUG:envisage.service_registry:service <1> registered envisage.plugins.ipython_kernel.internal_ipkernel.InternalIPKernel
DEBUG:envisage.service_registry:service <2> registered envisage.ui.tasks.preferences_dialog.PreferencesDialog
DEBUG:envisage.plugin_manager:plugin envisage.core started
DEBUG:envisage.plugin_manager:plugin example.plugins.ipython_kernel starting
DEBUG:envisage.plugin_manager:plugin example.plugins.ipython_kernel started
DEBUG:envisage.plugin_manager:plugin envisage.plugins.ipython_kernel starting
DEBUG:envisage.plugin_manager:plugin envisage.plugins.ipython_kernel started
DEBUG:envisage.plugin_manager:plugin envisage.plugins.ipython_kernel_ui starting
DEBUG:envisage.plugin_manager:plugin envisage.plugins.ipython_kernel_ui started
DEBUG:envisage.plugin_manager:plugin envisage.ui.tasks starting
DEBUG:envisage.plugin_manager:plugin envisage.ui.tasks started
DEBUG:envisage.application:---------- application started ----------
DEBUG:envisage.ui.tasks.tasks_application:Tasks state location is /home/jrocher/.enthought/example.ipython_kernel/tasks/qt4
Default tasks
DEBUG:envisage.provider_extension_registry:extensions to <envisage.ui.tasks.tasks> <[[], [<envisage.ui.tasks.task_factory.TaskFactory object at 0x7f974ae9a890>], [], [], []]>
/home/jrocher/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/IPython/kernel/__init__.py:13: ShimWarning: The `IPython.kernel` package has been deprecated. You should import from ipykernel or jupyter_client instead.
  "You should import from ipykernel or jupyter_client instead.", ShimWarning)
DEBUG:envisage.provider_extension_registry:extensions to <envisage.ui.tasks.task_extensions> <[[], [], [], [<envisage.ui.tasks.task_extension.TaskExtension object at 0x7f9747989230>], [<envisage.ui.tasks.task_extension.TaskExtension object at 0x7f97479895f0>]]>
DEBUG:envisage.provider_extension_registry:extensions to <ipython_plugin.namespace> <[[], [('app', <__main__.ExampleApplication object at 0x7f974ae9a590>)], [], [], []]>
NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.

To exit, you will have to explicitly quit this process, by either sending
"quit" from a client, or using Ctrl-\ in UNIX-like environments.

To read more about this, see https://github.com/ipython/ipython/issues/2049


To connect another client to this kernel, use:
    --existing kernel-27690.json
INFO:__main__:APPLICATION INITIALIZED

CI broken on master

Our continuous integration appears to be broken on master, as the runs for #109 show. We're seeing a variety of failure modes.

  • 2.7_with_system_site_packages uses an ancient version of Python 2.7 (2.7.6), and tornado complains about an out-of-date SSL for that version.
  • Many failures on Python 3.x related to current Jupyter packages. (See also #107).

Cannot create a new InternalIPKernel after shutting down the first one.

I'm attempting to add a test to test_internal_ipkernel that looks something like this:

    def test_repeated_start_stop(self):
        for count in xrange(5):
            logger.warning("count: %d", count)
            kernel = InternalIPKernel()
            kernel.init_ipkernel(gui_backend=None)
            kernel.shutdown()

Currently, this test fails on the second iteration:

======================================================================
ERROR: test_repeated_start_stop (__main__.TestInternalIPKernel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/mdickinson/Desktop/envisage/envisage/plugins/ipython_kernel/tests/test_internal_ipkernel.py", line 43, in test_repeated_start_stop
    kernel.init_ipkernel(gui_backend=None)
  File "/Users/mdickinson/Desktop/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 62, in init_ipkernel
    self.ipkernel = mpl_kernel(gui_backend)
  File "/Users/mdickinson/Desktop/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 28, in mpl_kernel
    kernel.initialize(argv)
  File "<decorator-gen-120>", line 2, in initialize
  File "/Users/mdickinson/.edm/envs/canopy-data-ci/lib/python2.7/site-packages/traitlets/config/application.py", line 87, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/mdickinson/.edm/envs/canopy-data-ci/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 445, in initialize
    self.init_sockets()
  File "/Users/mdickinson/.edm/envs/canopy-data-ci/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 235, in init_sockets
    self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
  File "/Users/mdickinson/.edm/envs/canopy-data-ci/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 177, in _bind_socket
    s.bind("tcp://%s:%i" % (self.ip, port))
  File "zmq/backend/cython/socket.pyx", line 495, in zmq.backend.cython.socket.Socket.bind (zmq/backend/cython/socket.c:5324)
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:7916)
    raise ZMQError(errno)
ZMQError: Address already in use

This is an important use-case for application using the InternalIPKernel and its associated plugin, and particularly for the test suite for such applications, which could be starting and shutting down the plugin repeatedly.

The tasks PreferencesDialog should support disabling the 'OK' button

The PreferencesDialog will call apply on all the preference panes when 'OK" is pressed. However some times it is useful to be able to veto closing the dialog because the current settings in a pane are invalid or partial

I think that one way of having this behavior is if each PreferencePane has a veto_apply Boolean trait that the PreferencesDialog can monitor to make a decision on closing the window and enabling/disabling the 'OK' button.

"Lorenz" example not working

I just installed Envisage from the latest available Debian packages, version 4.0.0-1. The "Lorenz" example plots only once, and never updates the plot. The following exception is logged:

Exception occurred in traits notification handler for object: <acme.lorenz.lorenz.Lorenz object at 0xa23e3bc>, trait: time, old value: [  0.00000000e+00   1.00000000e+02   1.00000000e-02], new value: [u'0.0' u'100.' u'0.01']
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/traits/trait_notifiers.py", line 360, in call_1
    self.handler( object )
  File "/home/sven/tmp/Lorenz/acme/lorenz/lorenz.py", line 38, in _time_changed
    def _time_changed(self): self.refresh()
  File "/home/sven/tmp/Lorenz/acme/lorenz/lorenz.py", line 29, in refresh
    self.calculatePoints()
  File "/home/sven/tmp/Lorenz/acme/lorenz/lorenz.py", line 49, in calculatePoints
    self.timePoints = arange(*self.time)
TypeError: unsupported operand type(s) for -: 'numpy.unicode_' and 'numpy.unicode_'

I can make the example partly work by naively replacing the failing line with

self.timePoints = arange(*self.time.astype(float))

Other exceptions will still occur with this "fix" in place, though.

attractors example is broken

enthought/ets/envisage/examples/plugins/tasks/attractors

$ python run.py

  File "run.py", line 27, in <module>
    main(sys.argv)
  File "run.py", line 20, in main
    app.run()
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/envisage/ui/tasks/tasks_application.py", line 134, in run
    self._create_windows()
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/envisage/ui/tasks/tasks_application.py", line 287, in _create_windows
    restore=self.always_use_default_layout)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/envisage/ui/tasks/tasks_application.py", line 205, in create_window
    window.add_task(task)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/pyface/tasks/task_window.py", line 182, in add_task
    state.central_pane.create(self.control)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/pyface/tasks/traits_task_pane.py", line 40, in create
    self.ui = self.edit_traits(kind='subpanel', parent=parent)
  File "/Users/tdiller/timdiller/traits/traits/has_traits.py", line 2247, in edit_traits
    handler, id, scrollable, args )
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/view.py", line 433, in ui
    ui.ui( parent, kind )
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/ui.py", line 218, in ui
    self.rebuild( self, parent )
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/toolkit.py", line 140, in ui_subpanel
    ui_panel.ui_subpanel( ui, parent )
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 78, in ui_subpanel
    _ui_panel_for(ui, parent, True)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 84, in _ui_panel_for
    ui.control = control = _Panel(ui, parent, is_subpanel).control
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 142, in __init__
    self.control = panel(ui)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 230, in panel
    panel = _GroupPanel(content[0], ui).control
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 562, in __init__
    layout = self._add_groups(content, inner)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 641, in _add_groups
    panel = _GroupPanel(subgroup, self.ui).control
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 564, in __init__
    layout = self._add_items(content, inner)
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/qt4/ui_panel.py", line 833, in _add_items
    None).set(
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/chaco/chaco_plot_editor.py", line 184, in simple_editor
    description = description )
  File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/traitsui/editor.py", line 133, in __init__
    self.old_value = getattr( self.object, self.name )
AttributeError: 'Plot2dPane' object has no attribute 'Plot'

Remove the envisage.developer package

The envisage.developer package appears to contain experimental, incomplete, untested and non-working code. @rahulporuri recently fixed a NameError in one of the modules (resulting from the use of Hastraits instead of HasTraits) that would have prevented it even from being imported at any time over the last 11 years. (See #130.)

I propose that we remove this package completely.

Fix evil global dictionary of ExtensionPointBinding instances.

The ExtensionPointBinding class keeps a record of all its instances in a WeakKeyDictionary class attribute:

class ExtensionPointBinding(HasTraits):
    """ A binding between a trait on an object and an extension point. """

    #### 'ExtensionPointBinding' *CLASS* interface ############################

    # We keep a reference to each binding alive until its associated object
    # is garbage collected.
    _bindings = weakref.WeakKeyDictionary()

    ...

This makes it awkward to use in unit tests, where it's easy to end up with the values in the WeakKeyDictionary keeping objects alive at the end of the test. It would be good to have a clean, documented way to avoid this problem.

In the specific issue that prompted this bug report, we had an Application object with extension point bindings that themselves contained references back to the Application object. That meant that after setting up the application and then tearing it back down again, the entire Application was still alive by virtue of being referred to by a value in the _bindings dictionary above.

Fix/update docs

  • fix warnings when building docs
  • fix navigation in docs
  • update docs to use enthought sphinx theme

Docs fail to build

$ make html
sphinx-build -b html -d build/doctrees   source build/html
Running Sphinx v1.1.3

Exception occurred:
  File "../../envisage/__init__.py", line 4, in <module>
ImportError: No module named _version
make: *** [html] Error 1

Document extra dependencies

The envisage package makes use of a number of packages that aren't listed as dependencies on the pypi package (

__requires__ = [
'apptools',
'traits',
]
). This is because only apptools and traits are dependencies of the core envisage package.

Other dependencies such as ipykernel, pyface, tornado, traitsui etc are extra dependencies which need to be installed to make full use of the envisage package.

In the future, we might want to make use of the extras_require keyword in setup.py.

Task Layout Persistence

VSplitter and HSplitter.items should be defined as List(Either(PaneItem, Tabbed, Splitter))

you can define a layout like ... left=HSplitter(VSplitter(...), VSplitter(...))

but the following exception is raised when a task window with this layout is closed

traits                                  : 
2013-09-18 21:16:10,283 ERROR   (MainThread) Exception occurred in traits notification handler for object: <envisage.ui.tasks.task_window.TaskWindow object at 0x11eff1b30>, trait: closing, old value: <undefined>, new value: <traits.has_traits.Vetoable object at 0x120b45470>
Traceback (most recent call last):
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_notifiers.py", line 535, in rebind_call_3
    object, trait_name, new )
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_notifiers.py", line 455, in dispatch
    handler( *args )
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/envisage/ui/tasks/tasks_application.py", line 412, in _on_window_closing
    window_layout = window.get_window_layout()
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyface/tasks/task_window.py", line 299, in get_window_layout
    layout = self._window_backend.get_layout()
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyface/ui/qt4/tasks/task_window_backend.py", line 85, in get_layout
    self._main_window_layout.get_layout(layout)
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyface/ui/qt4/tasks/main_window_layout.py", line 41, in get_layout
    sublayout = self.get_layout_for_area(q_dock_area, include_sizes)
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyface/ui/qt4/tasks/main_window_layout.py", line 91, in get_layout_for_area
    item = HSplitter(item1, item2)
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyface/tasks/task_layout.py", line 78, in __init__
    self.items = list(items)
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_types.py", line 2187, in validate
    return TraitListObject( self, object, name, value )
  File "/Users/ross/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_handlers.py", line 2418, in **init**
    raise excp
TraitError: Each element of the 'items' trait of a HSplitter instance must be an implementor of, or can be adapted to implement, PaneItem or None or an implementor of, or can be adapted to implement, Tabbed or None or an instance of the same type as the receiver or None, but a value of VSplitter(PaneItem('pychron.analysis_edit.unknowns', height=184, width=252), VSplitter(PaneItem('pychron.analysis_edit.references', height=182, width=252), PaneItem('pychron.analysis_edit.controls', height=124, width=252))) <class 'pyface.tasks.task_layout.VSplitter'> was specified.

IPythonKernelPlugin: Remove contributed menu action

It leaves no option to an application developer to get the IPython kernel service and the kernel_namespace extension point, but start Qt consoles in some other way. Or even just change the location and name of the menu action.

Developers will need to contribute names to kernel_namespace, anyway, so they have to write some plugin code in any case.

core_plugin_test_case, package_plugin_manager_test_case.py error in 4.3.0

I've run these a number of times (once was enough) and they appear legitimate errors, possibly regressions.

ERROR: dynamically added category


Traceback (most recent call last):
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/core_plugin_test_case.py", line 229, in test_dynamically_added_category
class Baz(HasTraits):
File "/usr/lib64/python2.7/site-packages/traits/has_traits.py", line 659, in new
listener( klass )
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/class_load_hook.py", line 63, in on_class_loaded
self.on_load(cls)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/core_plugin.py", line 245, in import_and_add_category
category_cls = self.application.import_symbol(category.class_name)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/application.py", line 249, in import_symbol
return self._import_manager.import_symbol(symbol_path)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/import_manager.py", line 42, in import_symbol
module_name, globals(), locals(), [symbol_name]
ImportError: No module named baz_category
-------------------- >> begin captured logging << --------------------
envisage.application: DEBUG: ---------- application starting ----------
envisage.plugin_manager: DEBUG: plugin envisage.core starting
envisage.provider_extension_registry: DEBUG: extensions to <envisage.preferences> <[[]]>
apptools.preferences.preferences: DEBUG: loading preferences from </var/tmp/portage/dev-python/envisage-4.3.0-r1/homedir/.enthought/core.plugin.test/preferences.ini>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.class_load_hooks> <[[]]>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.categories> <[[]]>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.service_offers> <[[]]>
envisage.plugin_manager: DEBUG: plugin envisage.core started
envisage.application: DEBUG: ---------- application started ----------
--------------------- >> end captured logging << ---------------------

ERROR: dynamically class load hooks


Traceback (most recent call last):
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/core_plugin_test_case.py", line 339, in test_dynamically_added_class_load_hooks
class Baz(HasTraits):
File "/usr/lib64/python2.7/site-packages/traits/has_traits.py", line 659, in new
listener( klass )
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/class_load_hook.py", line 63, in on_class_loaded
self.on_load(cls)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/core_plugin.py", line 245, in import_and_add_category
category_cls = self.application.import_symbol(category.class_name)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/application.py", line 249, in import_symbol
return self._import_manager.import_symbol(symbol_path)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/import_manager.py", line 42, in import_symbol
module_name, globals(), locals(), [symbol_name]
ImportError: No module named baz_category
-------------------- >> begin captured logging << --------------------
envisage.application: DEBUG: ---------- application starting ----------
envisage.plugin_manager: DEBUG: plugin envisage.core starting
envisage.provider_extension_registry: DEBUG: extensions to <envisage.preferences> <[[]]>
apptools.preferences.preferences: DEBUG: loading preferences from </var/tmp/portage/dev-python/envisage-4.3.0-r1/homedir/.enthought/core.plugin.test/preferences.ini>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.class_load_hooks> <[[]]>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.categories> <[[]]>
envisage.provider_extension_registry: DEBUG: extensions to <envisage.service_offers> <[[]]>
envisage.plugin_manager: DEBUG: plugin envisage.core started
envisage.application: DEBUG: ---------- application started ----------
--------------------- >> end captured logging << ---------------------

FAIL: test_only_find_plugins_matching_a_wildcard_in_the_include_list (envisage.tests.package_plugin_manager_test_case.PackagePluginManagerTestCase)


Traceback (most recent call last):
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/package_plugin_manager_test_case.py", line 78, in test_only_find_plugins_matching_a_wildcard_in_the_include_list
self._test_start_and_stop(plugin_manager, expected)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/package_plugin_manager_test_case.py", line 148, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
AssertionError: Lists differ: ['orange', 'pear'] != ['pear', 'orange']

First differing element 0:
orange
pear

  • ['orange', 'pear']
  • ['pear', 'orange']
    -------------------- >> begin captured logging << --------------------
    envisage.package_plugin_manager: DEBUG: Looking for plugins in /var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/plugins/pear
    envisage.package_plugin_manager: DEBUG: package plugin manager found plugins <[<pear.pear_plugin.PearPlugin object at 0x355cd10>, <orange.orange_plugin.OrangePlugin object at 0x355cbf0>]>
    --------------------- >> end captured logging << ---------------------

FAIL: test_only_find_plugins_whose_ids_are_in_the_include_list (envisage.tests.package_plugin_manager_test_case.PackagePluginManagerTestCase)


Traceback (most recent call last):
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/package_plugin_manager_test_case.py", line 58, in test_only_find_plugins_whose_ids_are_in_the_include_list
self._test_start_and_stop(plugin_manager, expected)
File "/var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/package_plugin_manager_test_case.py", line 148, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
AssertionError: Lists differ: ['orange', 'pear'] != ['pear', 'orange']

First differing element 0:
orange
pear

  • ['orange', 'pear']
  • ['pear', 'orange']
    -------------------- >> begin captured logging << --------------------
    envisage.package_plugin_manager: DEBUG: Looking for plugins in /var/tmp/portage/dev-python/envisage-4.3.0-r1/work/envisage-4.3.0/envisage/tests/plugins/pear
    envisage.package_plugin_manager: DEBUG: package plugin manager found plugins <[<pear.pear_plugin.PearPlugin object at 0x356d1d0>, <orange.orange_plugin.OrangePlugin object at 0x356d290>]>
    --------------------- >> end captured logging << ---------------------

Ran 185 tests in 3.606s

FAILED (errors=2, failures=2)

ImportError: No module named baz_category

How on earth do you get it attempting to import baz_category?? Ought it not be importing plain baz ??

$ python -V Python 2.7.3

Oh, is this packages intended to support py2.6"

  • python2_6: running distutils-r1_run_phase python_test yields

Ran 162 tests in 3.722s

FAILED (errors=17, failures=9)
Looks like we could take this as a no.

Drop pymacs

pymacs appears to be a dead project, perhaps time to drop support for it.

Attractor example is broken (again)

I believe I up to date on all of ETS and yet it seems like our attractor example is broken again:

jrocher$ python run.py 
WARNING:traits.adaptation.adapter:DEPRECATED: traits.adaptation.adapter.callback, use the 'register_factory' function from 'traits.api' instead
Traceback (most recent call last):
  File "run.py", line 27, in <module>
    main(sys.argv)
  File "run.py", line 20, in main
    app.run()
  File "/Users/jrocher/Projects/ETS_trunk/envisage/envisage/ui/tasks/tasks_application.py", line 134, in run
    self._create_windows()
  File "/Users/jrocher/Projects/ETS_trunk/envisage/envisage/ui/tasks/tasks_application.py", line 287, in _create_windows
    restore=self.always_use_default_layout)
  File "/Users/jrocher/Projects/ETS_trunk/envisage/envisage/ui/tasks/tasks_application.py", line 205, in create_window
    window.add_task(task)
  File "/Users/jrocher/Projects/ETS_trunk/pyface/pyface/tasks/task_window.py", line 180, in add_task
    state.central_pane = task.create_central_pane()
  File "/Users/jrocher/Projects/ETS_trunk/envisage/examples/plugins/tasks/attractors/visualize_2d_task.py", line 43, in create_central_pane
    pane = Plot2dPane(models=self.models)
  File "/Users/jrocher/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_types.py", line 2201, in validate
    return TraitListObject( self, object, name, value )
  File "/Users/jrocher/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/traits/trait_handlers.py", line 2309, in __init__
    raise excp
traits.trait_errors.TraitError: Each element of the 'models' trait of a Plot2dPane instance must be an IPlottable2d or None, but a value of <model.lorenz.Lorenz object at 0x124b81830> <class 'model.lorenz.Lorenz'> was specified.

query evaluation in get_service(s) omits lazy population of default traits

Here is one example to reproduce the bug:

from envisage.api import Application
from traits.api import Interface, provides, HasTraits, Str, Int, HasStrictTraits


class IPlumber(Interface):
    """ What plumbers do! """

    # The plumber's name.
    name = Str

    # The plumber's location.
    location = Str

    # The price per hour (in say, Estonian Krooni ;^)
    price = Int

    def fix_leaking_pipe(self, pipe):
        """ Fix a leaking pipe! """

@provides(IPlumber)
class Plumber(HasTraits):
    """ An actual plumber implementation! """

    # The plumber's name.
    name = Str

    # The plumber's location.
    location = Str

    # The price per hour (in say, Estonian Krooni ;^)
    price = Int

    def fix_leaking_pipe(self, pipe):
        """ Fix a leaking pipe! """
        print('fixed!')


@provides(IPlumber)
class Foo(HasTraits):
    foo = Int
    price = Int(20)


if __name__ == '__main__':
    application = Application()
    fred = Plumber()
    foo = Foo()
    fred_id = application.register_service(IPlumber, fred)
    foo_id = application.register_service(IPlumber, foo)

    obj = application.get_services(IPlumber, 'price<30')

    print(obj)

and the problematic code:

def _create_namespace(self, service, properties):
""" Create a namespace in which to evaluate a query. """
namespace = {}
namespace.update(service.__dict__)
namespace.update(properties)
return namespace

egg_plugin_manager_test_case.py fails everything

Please fix this test. Run from either the ebuild or from the source dir, it fails everything.

archtester envisage-4.1.0 # pwd
/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0

archtester envisage-4.1.0 # PYTHONPATH=build-2.7/lib/ nosetests

Ran 158 tests in 3.261s

FAILED (failures=5)

archtester envisage # ebuild envisage-4.1.0.ebuild clean test

................

FAIL: exclude multiple

Traceback (most recent call last):
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 137, in test_exclude_multiple
self._test_start_and_stop(plugin_manager, expected)
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 151, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
AssertionError: Lists differ: ['acme.foo'] != []

First list contains 1 additional elements.
First extra element 0:
acme.foo

  • ['acme.foo']
  • []
    -------------------- >> begin captured logging << --------------------
    envisage.egg_plugin_manager: DEBUG: egg plugin manager found plugins <[]>
    --------------------- >> end captured logging << ---------------------

FAIL: exclude specific

Traceback (most recent call last):
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 111, in test_exclude_specific
self._test_start_and_stop(plugin_manager, expected)
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 151, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
AssertionError: Lists differ: ['acme.bar'] != []

First list contains 1 additional elements.
First extra element 0:
acme.bar

  • ['acme.bar']
  • []
    -------------------- >> begin captured logging << --------------------
    envisage.egg_plugin_manager: DEBUG: egg plugin manager found plugins <[]>
    --------------------- >> end captured logging << ---------------------

FAIL: include multiple

Traceback (most recent call last):
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 85, in test_include_multiple
self._test_start_and_stop(plugin_manager, expected)
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 151, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
-------------------- >> begin captured logging << --------------------
envisage.egg_plugin_manager: DEBUG: egg plugin manager found plugins <[]>

--------------------- >> end captured logging << ---------------------

FAIL: include specific

Traceback (most recent call last):
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 62, in test_include_specific
self._test_start_and_stop(plugin_manager, expected)
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 151, in _test_start_and_stop
self.assertEqual(expected, [plugin.id for plugin in plugin_manager])
AssertionError: Lists differ: ['acme.foo', 'acme.bar'] != []

First list contains 2 additional elements.
First extra element 0:
acme.foo

  • ['acme.foo', 'acme.bar']
  • []
    -------------------- >> begin captured logging << --------------------
    envisage.egg_plugin_manager: DEBUG: egg plugin manager found plugins <[]>
    --------------------- >> end captured logging << ---------------------

FAIL: no include or exclude

Traceback (most recent call last):
File "/mnt/gen2/TmpDir/portage/dev-python/envisage-4.1.0/work/envisage-4.1.0/envisage/tests/egg_plugin_manager_test_case.py", line 37, in test_no_include_or_exclude
self.assert_('acme.foo' in ids)
AssertionError: False is not true
-------------------- >> begin captured logging << --------------------
envisage.egg_plugin_manager: DEBUG: egg plugin manager found plugins <[<envisage.core_plugin.CorePlugin object at 0x31f7d70>]>
--------------------- >> end captured logging << ---------------------


Ran 158 tests in 3.451s

FAILED (failures=5)

  • ERROR: dev-python/envisage-4.1.0 failed (test phase):
  • Testing failed with CPython 2.7 in python_test_function() function

Can't upload the build log anyway but the above is all it would tell.

tasks example failure

I get the following when I try to run the tasks example from master, on OS X Lion (with qt4/PyQt4 and no wx):

[~/Projects/ets/envisage/examples/plugins/tasks/attractors](master)
darren@minerva $ python run.py 
Exception occurred in traits notification handler.
Please check the log file for details.
Exception occurred in traits notification handler for object: <plot_3d_pane.Plot3dPane object at 0x11d453ef0>, trait: active_model, old value: None, new value: <model.lorenz.Lorenz object at 0x11d4536b0>
Traceback (most recent call last):
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_notifiers.py", line 505, in rebind_call_0
    self.dispatch( getattr( self.object(), self.name ) )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_notifiers.py", line 448, in dispatch
    handler( *args )
  File "/Users/darren/Projects/ets/envisage/examples/plugins/tasks/attractors/plot_3d_pane.py", line 49, in _update_scene
    self.scene.mlab.clf()
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2776, in create_default_value
    return klass( *args[1:], **kw )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/mayavi-4.0.1-py2.7-macosx-10.7-x86_64.egg/mayavi/tools/mlab_scene_model.py", line 41, in __init__
    self.engine.current_scene = current_figure
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/mayavi-4.0.1-py2.7-macosx-10.7-x86_64.egg/mayavi/core/engine.py", line 522, in _set_current_scene
    self._current_scene = scene
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2690, in validate
    self.validate_failed( object, name, value )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2553, in validate_failed
    self.error( object, name, value )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_handlers.py", line 168, in error
    value )
TraitError: The '_current_scene' trait of an Engine instance must be an implementor of, or can be adapted to implement, Scene, but a value of None <type 'NoneType'> was specified.
ERROR:traits:Exception occurred in traits notification handler for object: <plot_3d_pane.Plot3dPane object at 0x11d453ef0>, trait: active_model, old value: None, new value: <model.lorenz.Lorenz object at 0x11d4536b0>
Traceback (most recent call last):
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_notifiers.py", line 505, in rebind_call_0
    self.dispatch( getattr( self.object(), self.name ) )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_notifiers.py", line 448, in dispatch
    handler( *args )
  File "/Users/darren/Projects/ets/envisage/examples/plugins/tasks/attractors/plot_3d_pane.py", line 49, in _update_scene
    self.scene.mlab.clf()
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2776, in create_default_value
    return klass( *args[1:], **kw )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/mayavi-4.0.1-py2.7-macosx-10.7-x86_64.egg/mayavi/tools/mlab_scene_model.py", line 41, in __init__
    self.engine.current_scene = current_figure
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/mayavi-4.0.1-py2.7-macosx-10.7-x86_64.egg/mayavi/core/engine.py", line 522, in _set_current_scene
    self._current_scene = scene
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2690, in validate
    self.validate_failed( object, name, value )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_types.py", line 2553, in validate_failed
    self.error( object, name, value )
  File "/Users/darren/Library/Python/2.7/lib/python/site-packages/traits-4.0.1-py2.7-macosx-10.7-x86_64.egg/traits/trait_handlers.py", line 168, in error
    value )
TraitError: The '_current_scene' trait of an Engine instance must be an implementor of, or can be adapted to implement, Scene, but a value of None <type 'NoneType'> was specified.

License headers

It would be good if all source files could contain the proper license header in the file. This greatly helps with license audits.

Tests broken with ipykernel 4.7.0

The recent release of ipykernel 4.7.0 appears to break Envisage.

Sample failures, from https://travis-ci.org/enthought/envisage/jobs/312429428 (the later failures are probably consequences of the first one):

======================================================================
ERROR: test_initial_namespace (envisage.plugins.ipython_kernel.tests.test_internal_ipkernel.TestInternalIPKernel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/tests/test_internal_ipkernel.py", line 45, in test_initial_namespace
    kernel.shutdown()
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 88, in shutdown
    self.ipkernel.shell.exit_now = True
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/traitlets.py", line 585, in __set__
    self.set(obj, value)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/traitlets.py", line 574, in set
    obj._notify_trait(self.name, old_value, new_value)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/traitlets.py", line 1139, in _notify_trait
    type='change',
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/traitlets.py", line 1176, in notify_change
    c(change)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/zmqshell.py", line 472, in _update_exit_now
    loop = self.kernel.io_loop
AttributeError: 'IPythonKernel' object has no attribute 'io_loop'
======================================================================
ERROR: test_io_pub_thread_stopped (envisage.plugins.ipython_kernel.tests.test_internal_ipkernel.TestInternalIPKernel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/tests/test_internal_ipkernel.py", line 49, in test_io_pub_thread_stopped
    kernel.init_ipkernel(gui_backend=None)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 62, in init_ipkernel
    self.ipkernel = gui_kernel(gui_backend)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 28, in gui_kernel
    kernel.initialize(argv)
  File "<decorator-gen-121>", line 2, in initialize
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/config/application.py", line 87, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 448, in initialize
    self.init_sockets()
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 238, in init_sockets
    self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 180, in _bind_socket
    s.bind("tcp://%s:%i" % (self.ip, port))
  File "zmq/backend/cython/socket.pyx", line 495, in zmq.backend.cython.socket.Socket.bind
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc
    raise ZMQError(errno)
ZMQError: Address already in use
======================================================================
ERROR: test_lifecycle (envisage.plugins.ipython_kernel.tests.test_internal_ipkernel.TestInternalIPKernel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/tests/test_internal_ipkernel.py", line 28, in test_lifecycle
    kernel.init_ipkernel(gui_backend=None)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 62, in init_ipkernel
    self.ipkernel = gui_kernel(gui_backend)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 28, in gui_kernel
    kernel.initialize(argv)
  File "<decorator-gen-121>", line 2, in initialize
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/config/application.py", line 87, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 448, in initialize
    self.init_sockets()
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 238, in init_sockets
    self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 180, in _bind_socket
    s.bind("tcp://%s:%i" % (self.ip, port))
  File "zmq/backend/cython/socket.pyx", line 495, in zmq.backend.cython.socket.Socket.bind
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc
    raise ZMQError(errno)
ZMQError: Address already in use
======================================================================
ERROR: test_kernel_namespace_extension_point (envisage.plugins.ipython_kernel.tests.test_ipython_kernel_plugin.TestIPythonKernelPlugin)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/tests/test_ipython_kernel_plugin.py", line 58, in test_kernel_namespace_extension_point
    kernel.init_ipkernel(gui_backend=None)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 62, in init_ipkernel
    self.ipkernel = gui_kernel(gui_backend)
  File "/home/travis/build/enthought/envisage/envisage/plugins/ipython_kernel/internal_ipkernel.py", line 28, in gui_kernel
    kernel.initialize(argv)
  File "<decorator-gen-121>", line 2, in initialize
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/traitlets/config/application.py", line 87, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 448, in initialize
    self.init_sockets()
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 238, in init_sockets
    self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
  File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/ipykernel/kernelapp.py", line 180, in _bind_socket
    s.bind("tcp://%s:%i" % (self.ip, port))
  File "zmq/backend/cython/socket.pyx", line 495, in zmq.backend.cython.socket.Socket.bind
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc
    raise ZMQError(errno)
ZMQError: Address already in use

incompatible with ipython 0.11

envisage/plugins/ipython_shell/view/ipython_shell_view.py uses the old ipython api:

line 9: from IPython.kernel.core.interpreter import Interpreter

IPython.kernel has been replaced by IPython.parallel in ipython 0.11.
Unfortunately Interpreter class does not exist anymore and I don't know with what it was replaced.

Tests fail with python 3.7

I'm seeing:

ERROR: test_exclude_multiple (envisage.tests.egg_plugin_manager_test_case.EggPluginManagerTestCase)
exclude multiple
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/envisage-4.7.1/envisage/tests/egg_plugin_manager_test_case.py", line 116, in test_exclude_multiple
    self._add_eggs_on_path([self.egg_dir])
  File "/builddir/build/BUILD/envisage-4.7.1/envisage/tests/egg_based_test_case.py", line 67, in _add_eggs_on_path
    raise SystemError('Cannot find eggs %s' % errors)
SystemError: Cannot find eggs {}

And I think that is because there are no 3.7 eggs in the testing directory.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.