Source code for envisage.tests.test_extension_point_binding

# (C) Copyright 2007-2023 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Tests for extension point bindings. """

# Standard library imports.
import unittest
import weakref

from traits.api import Any, HasTraits, List

# Enthought library imports.
from envisage.api import (
    bind_extension_point,
    ExtensionPoint,
    unbind_extension_point,
)

# Local imports.
from envisage.tests.mutable_extension_registry import MutableExtensionRegistry


[docs]class BindingTarget(HasTraits): """ Example class whose traits are used as a binding target. """ #: Target trait for extension point binding. target = List(Any())
[docs]class ExtensionPointBindingTestCase(unittest.TestCase): """Tests for extension point binding."""
[docs] def setUp(self): self.extension_registry = MutableExtensionRegistry()
[docs] def tearDown(self): del self.extension_registry
[docs] def test_untyped_extension_point(self): """untyped extension point""" registry = self.extension_registry # Add an extension point. registry.add_extension_point(self._create_extension_point("my.ep")) # Add an extension. registry.add_extension("my.ep", 42) # Declare a class that consumes the extension. class Foo(HasTraits): x = List events = [] f = Foo() f.observe(events.append, "x_items") # Make some bindings. bind_extension_point(f, "x", "my.ep", registry) # Make sure that the object was initialized properly. self.assertEqual(1, len(f.x)) self.assertEqual(42, f.x[0]) # Add another extension. registry.add_extension("my.ep", "a string") # Make sure that the object picked up the new extension... self.assertEqual(2, len(f.x)) self.assertTrue(42 in f.x) self.assertTrue("a string" in f.x) # ... and that the correct trait change event was fired. self.assertEqual(len(events), 1) event = events[0] self.assertEqual(f, event.object) self.assertEqual("x_items", event.name) self.assertEqual(1, len(event.new.added)) self.assertTrue("a string" in event.new.added)
[docs] def test_set_extensions_via_trait(self): """set extensions via trait""" registry = self.extension_registry # Add an extension point. registry.add_extension_point(self._create_extension_point("my.ep")) # Add an extension. registry.add_extension("my.ep", 42) # Declare a class that consumes the extension. class Foo(HasTraits): x = List events = [] f = Foo() f.observe(events.append, "*") # Make some bindings. bind_extension_point(f, "x", "my.ep", registry) # Make sure that the object was initialized properly. self.assertEqual(1, len(f.x)) self.assertEqual(42, f.x[0]) # Set the extensions. f.x = ["a string"] # Make sure that the object picked up the new extension... self.assertEqual(1, len(f.x)) self.assertTrue("a string" in f.x) self.assertEqual(1, len(registry.get_extensions("my.ep"))) self.assertTrue("a string" in registry.get_extensions("my.ep")) # ... and that the correct trait change event was fired. self.assertEqual(len(events), 1) event = events[0] self.assertEqual(f, event.object) self.assertEqual("x", event.name) self.assertEqual(1, len(event.new)) self.assertTrue("a string" in event.new)
[docs] def test_set_extensions_via_registry(self): """set extensions via registry""" registry = self.extension_registry # Add an extension point. registry.add_extension_point(self._create_extension_point("my.ep")) # Add an extension. registry.add_extension("my.ep", 42) # Declare a class that consumes the extension. class Foo(HasTraits): x = List events = [] f = Foo() f.observe(events.append, "*") # Make some bindings. bind_extension_point(f, "x", "my.ep", registry) # Make sure that the object was initialized properly. self.assertEqual(1, len(f.x)) self.assertEqual(42, f.x[0]) # Set the extensions. registry.set_extensions("my.ep", ["a string"]) # Make sure that the object picked up the new extension... self.assertEqual(1, len(f.x)) self.assertTrue("a string" in f.x) # ... and that the correct trait change event was fired. self.assertEqual(len(events), 1) event = events[0] self.assertEqual(f, event.object) self.assertEqual("x", event.name) self.assertEqual(1, len(event.new)) self.assertTrue("a string" in event.new)
[docs] def test_explicit_extension_registry(self): """explicit extension registry""" registry = self.extension_registry # Add an extension point. registry.add_extension_point(self._create_extension_point("my.ep")) # Add an extension. registry.add_extension("my.ep", 42) # Declare a class that consumes the extension. class Foo(HasTraits): x = List f = Foo() # Create an empty extension registry use that in the binding. extension_registry = MutableExtensionRegistry() # Make some bindings. bind_extension_point(f, "x", "my.ep", extension_registry) # Make sure that we pick up the empty extension registry and not the # default one. self.assertEqual(0, len(f.x))
[docs] def test_should_be_able_to_bind_multiple_traits_on_a_single_object(self): registry = self.extension_registry # Add 2 extension points. registry.add_extension_point(self._create_extension_point("my.ep")) registry.add_extension_point( self._create_extension_point("another.ep") ) # Declare a class that consumes both of the extension points. class Foo(HasTraits): x = List y = List f = Foo() # Bind two different traits on the object to the extension points. bind_extension_point(f, "x", "my.ep", registry) bind_extension_point(f, "y", "another.ep", registry) self.assertEqual(0, len(f.x)) self.assertEqual(0, len(f.y)) # Add some contributions to the extension points. registry.add_extension("my.ep", 42) registry.add_extensions("another.ep", [98, 99, 100]) # Make sure both traits were bound correctly. self.assertEqual(1, len(f.x)) self.assertEqual(3, len(f.y))
[docs] def test_unbind_extension_point(self): # Given ... # ... an extension point ... registry = self.extension_registry registry.add_extension_point(self._create_extension_point("my.ep")) # ... and an object with a corresponding trait ... target = BindingTarget() # When we bind the extension point to the trait ... bind_extension_point(target, "target", "my.ep", registry) # Then contributions to the extension point modify the trait. registry.add_extension("my.ep", "a string") self.assertEqual(target.target, ["a string"]) # When we unbind the extension point unbind_extension_point(target, "target", "my.ep", registry) # Then contributions no longer change the trait. registry.add_extension("my.ep", "another string") self.assertEqual(target.target, ["a string"])
[docs] def test_unbinding_removes_references(self): # Given an extension point bound to a trait extension_point = self._create_extension_point("my.ep") self.extension_registry.add_extension_point(extension_point) target = BindingTarget() bind_extension_point( target, "target", "my.ep", self.extension_registry ) # Use a weakref finalizer to keep track of whether 'target' still # has references keeping it alive. target_monitor = weakref.finalize(target, lambda: None) # When we unbind and delete the target object unbind_extension_point( target, "target", "my.ep", self.extension_registry ) del target # Then 'target' should no longer be alive. self.assertFalse(target_monitor.alive)
########################################################################### # Private interface. ########################################################################### def _create_extension_point(self, id, trait_type=List, desc=""): """Create an extension point.""" return ExtensionPoint(id=id, trait_type=trait_type, desc=desc)