Edgewall Software
Modify

Opened 18 years ago

Closed 18 years ago

Last modified 18 years ago

#2403 closed enhancement (fixed)

Proposal to modify ExtensionPoint to allow specialisation

Reported by: trac-form@… Owned by: Christopher Lenz
Priority: low Milestone: 0.10
Component: general Version: 0.9
Severity: minor Keywords:
Cc: Branch:
Release Notes:
API Changes:
Internal Changes:

Description

By turning ExtensionPoint into a descriptor it moves the decision of what to return, into the ExtensionPoint object. This allows one to sub-class ExtensionPoint and customise its behaviour. It has no negative side-effects that I can think of.

To illustrate how this could be useful, the following example lets the user choose a single active interface implementation out of the set of available extensions.

This is useful for user-configurable extension selection, say of a database backend, or a UI front-end; any situation where only a single implementation should be used.

class SingletonExtensionPoint(ExtensionPoint):
    def __get__(self, instance, owner):
        xtnpt = instance._extension_points.get(self.name)
        if xtnpt:
            extensions = ComponentMeta._registry.get(xtnpt.interface, [])
            seek = instance.compmgr._active_components.get(xtnpt.interface, None)
            if seek:
                for extension in extensions:
                    if extension.__name__ == seek:
                        return extension
                raise AttributeError("can't find active interface '%s' named '%s'" % (xtnpt.interface.__name__, seek))
            else:
                raise AttributeError("no component active for '%s' interface" % xtnpt.interface.__name__)

class AnInterface(Interface):
    def do_stuff():
        pass

class ImplementationOfAnInterface(Component):
    implements(AnInterface)

    def do_stuff(self):
        print "ImplementationOfAnInterface.do_stuff()"

class M(ComponentManager, Component):
    _active_components = {}

    aninterface = SingletonExtensionPoint(AnInterface)

    def set_active(self, interface, component):
        self._active_components[interface] = component

m = M()
m.set_active(AnInterface, 'ImplementationOfAnInterface')
i = m.aninterface

Attachments (1)

extension-specialisation.diff (2.0 KB ) - added by trac-form@… 18 years ago.
Implementation of proposal

Download all attachments as: .zip

Change History (12)

by trac-form@…, 18 years ago

Implementation of proposal

comment:1 by anonymous, 18 years ago

Type: defectenhancement

comment:2 by trac-form@…, 18 years ago

Slight bug-fix in the SingletonExtensionPoint example:

return extension

should be

return instance.compmgr[extension]

comment:3 by Christopher Lenz, 18 years ago

Milestone: 1.0
Owner: changed from Jonas Borgström to Christopher Lenz
Status: newassigned

Yeah, changing ExtensionPoint to a descriptor is a good idea.

comment:4 by trac-form@…, 18 years ago

1.0? Boooooooooooo :(

comment:5 by Christian Boos, 18 years ago

Also, the patch/proposal doesn't seem to be complete, I tested it on top of the FlexibleWikiPageNames branch, and it raises the following error:

Traceback (most recent call last):
   ...
File "D:\Workspace\install\lib\python\trac\devel\Lib\site-packages\trac\wiki\api.py", line 204, in get_wiki_syntax
    p = self.wikipagenames_providers
  File "D:\Workspace\install\lib\python\trac\devel\Lib\site-packages\trac\core.py", line 63, in __get__
    seek = instance.compmgr._active_components.get(xtnpt.interface,
AttributeError: 'Environment' object has no attribute '_active_components'

The Environment.set_active method seems to be missing as well.

Also, what would you suggest for a standard way to assign the appropriate implementation. There should be a simple (automated?) way to get them from the TracIni, or otherwise pick a default implementation.

comment:6 by trac-form@…, 18 years ago

In the example above, M is the ComponentManager and implements set_active and _active_components. The patch is intentionally minimal, behaving identically to the existing code, but allows the possibility of alternative ExtensionPoint semantics, such as the example SingletonExtensionPoint above. I can provide a more complete implementation if interested.

SingletonExtensionPoint was just an example, but if something similar were to be implemented it would require modifications to Environment, perhaps with a default method in ComponentManager.

I had envisaged using TracIni as you suggest; it would seem to be quite intuitive.

Perhaps something like the following?

[selected_components]
IDatabaseProvider = SQLiteDB
ISourceControlSystem = SubversionSCS

comment:7 by Christian Boos, 18 years ago

Have a look at r2563, which integrates the proposed implementation for ExtensionPoint and introduces a SingleExtensionPoint which implements a similar way for selecting a single implementation for a given interface to what I already did as a special case, in the FlexibleWikiPageNames branch.

Everything works fine.

comment:8 by trac-form@…, 18 years ago

I like it. It definitely makes life easier.

comment:9 by Christopher Lenz, 18 years ago

Resolution: fixed
Status: assignedclosed

[2603] makes extension points descriptors as to your proposal.

I don't think a generic singleton-style extension point implementation makes much sense right now, and selecting one component by disabling the others doesn't seem that elegant IMO.

comment:10 by Christopher Lenz, 18 years ago

Milestone: 1.00.10

comment:11 by Matthew Good, 18 years ago

An implementation of the SingletonExtensionPoint has been added in [2866].

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Christopher Lenz.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Christopher Lenz to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.