Skip to content

Commit

Permalink
Remove "contributes_to" decorator and supporting code (#402)
Browse files Browse the repository at this point in the history
* CLN : Remove contributes_to decorator

and supporting code, tests

	modified:   envisage/api.py
	modified:   envisage/extension_point.py
	modified:   envisage/plugin.py
	modified:   envisage/tests/test_plugin.py

* FIX : flake8 - unused import

	modified:   envisage/plugin.py

* FIX : Specifically handle case where there are no traits that contribute

to the extension point
otherwise, it just goes into the else clause which raises an error

	modified:   envisage/plugin.py
  • Loading branch information
Poruri Sai Rahul authored Apr 27, 2021
1 parent 182ecd9 commit 342c4d0
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 146 deletions.
3 changes: 1 addition & 2 deletions envisage/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
- :class:`~.CorePlugin`
- :class:`~.EggPluginManager`
- :class:`~.ExtensionPoint`
- :func:`~.contributes_to`
- :class:`~.ExtensionPointBinding`
- :func:`~.bind_extension_point`
- :class:`~.ExtensionProvider`
Expand Down Expand Up @@ -70,7 +69,7 @@
from .core_plugin import CorePlugin
from .egg_plugin_manager import EggPluginManager
from .extension_registry import ExtensionRegistry
from .extension_point import ExtensionPoint, contributes_to
from .extension_point import ExtensionPoint
from .extension_point_binding import (
ExtensionPointBinding,
bind_extension_point,
Expand Down
41 changes: 0 additions & 41 deletions envisage/extension_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,47 +24,6 @@
from .i_extension_point import IExtensionPoint


def contributes_to(id):
""" A factory for extension point decorators!
As an alternative to making contributions via traits, you can use this
decorator to mark any method on a 'Plugin' as contributing to an extension
point (note this is *only* used on 'Plugin' instances!).
e.g. Using a trait you might have something like::
class MyPlugin(Plugin):
messages = List(contributes_to='acme.messages')
def _messages_default(self):
return ['Hello', 'Hola']
whereas, using the decorator, it would be::
class MyPlugin(Plugin):
@contributes_to('acme.messages')
def _get_messages(self):
return ['Hello', 'Hola']
There is not much in it really, but the decorator version looks a little
less like 'magic' since it doesn't require the developer to know about
Traits default initializers. However, if you know that you will want to
dynamically change your contributions then use the trait version because
all you have to do is change the value of the trait and the framework will
react accordingly.
"""

def decorator(fn):
""" A decorator for marking methods as extension contributors. """

fn.__extension_point__ = id

return fn

return decorator


# Exception message template.
INVALID_TRAIT_TYPE = (
'extension points must be "List"s e.g. List, List(Int)'
Expand Down
62 changes: 1 addition & 61 deletions envisage/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
""" The default implementation of the 'IPlugin' interface. """

# Standard library imports.
import inspect
import logging
import os
from os.path import exists, join
Expand Down Expand Up @@ -131,26 +130,8 @@ def get_extensions(self, extension_point_id):
# fine to allow mutiple traits!
trait_names = self.trait_names(contributes_to=extension_point_id)

# FIXME: This is a temporary fix, which was necessary due to the
# namespace refactor, but should be removed at some point.
if len(trait_names) == 0:
old_id = "enthought." + extension_point_id
trait_names = self.trait_names(contributes_to=old_id)
# if trait_names:
# print 'deprecated:', old_id

if len(trait_names) == 0:
# If there is no contributing trait then look for any decorated
# methods.
extensions = self._harvest_methods(extension_point_id)

# FIXME: This is a temporary fix, which was necessary due to the
# namespace refactor, but should be removed at some point.
if not extensions:
old_id = "enthought." + extension_point_id
extensions = self._harvest_methods(old_id)
# if extensions:
# print 'deprecated:', old_id
extensions = []

elif len(trait_names) == 1:
extensions = self._get_extensions_from_trait(trait_names[0])
Expand Down Expand Up @@ -372,47 +353,6 @@ def _get_service_protocol(self, trait):

return protocol

def _harvest_methods(self, extension_point_id):
""" Harvest all method-based contributions. """

extensions = []
# Using inspect.getmembers(self) here will cause an infinite recursion,
# so use an internal HasTraits method for inspecting the MRO of the
# instance's type to find all methods instead.
for name in self._each_trait_method(self):
value = getattr(self, name)
if self._is_extension_method(value, extension_point_id):
result = value()
if not isinstance(result, list):
result = [result]

extensions.extend(result)

return extensions

def _is_extension_method(self, value, extension_point_id):
""" Return True if the value is an extension method.
i.e. If the method is one that makes a contribution to the extension
point. Currently there is exactly one way to make a method make a
contribution, and that is to mark it using the 'contributes_to'
decorator, e.g::
@contributes_to('acme.motd.messages')
def get_messages(self):
...
messages = [...]
...
return messages
"""

is_extension_method = inspect.ismethod(
value
) and extension_point_id == getattr(value, "__extension_point__", None)

return is_extension_method

def _register_service_factory(self, trait_name, trait):
""" Register a service factory for the specified trait. """

Expand Down
43 changes: 1 addition & 42 deletions envisage/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# Enthought library imports.
from envisage.api import Application, ExtensionPoint
from envisage.api import IPluginActivator, Plugin, contributes_to
from envisage.api import IPluginActivator, Plugin
from envisage.tests.ets_config_patcher import ETSConfigPatcher
from traits.api import HasTraits, Instance, Int, Interface, List
from traits.api import provides
Expand Down Expand Up @@ -260,47 +260,6 @@ class PluginB(Plugin):
# contributing to the same extension point.
self.assertEqual([1, 2, 3], application.get_extensions("x"))

def test_contributes_to_decorator(self):
""" contributes to decorator """

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

class PluginB(Plugin):
id = "B"

@contributes_to("x")
def _x_contributions(self):
return [1, 2, 3]

a = PluginA()
b = PluginB()

application = TestApplication(plugins=[a, b])
self.assertEqual([1, 2, 3], application.get_extensions("x"))

def test_contributes_to_decorator_ignored_if_trait_present(self):
""" contributes to decorator ignored if trait present """

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

class PluginB(Plugin):
id = "B"
x = List([1, 2, 3], contributes_to="x")

@contributes_to("x")
def _x_contributions(self):
return [4, 5, 6]

a = PluginA()
b = PluginB()

application = TestApplication(plugins=[a, b])
self.assertEqual([1, 2, 3], application.get_extensions("x"))

def test_add_plugins_to_empty_application(self):
""" add plugins to empty application """

Expand Down

0 comments on commit 342c4d0

Please sign in to comment.