On Sat, Jan 20, 2007 at 01:35:02PM +0100, Emmanuel Blot wrote:
> This means that an API break may prevent admins to upgrade to Trac
> because of their installed 3rd party components, make them angry about
> Trac:
> * need to revert to the previous release
> * increase the general feeling about how hard Trac is to
> install/upgrade/maitain, etc.
These are all good points. I know myself how tedious it is upgrading
plugins to a new API version. It's not "fun" coding, it's just boring.
The less of this we subject plugin authors to, the more likely it is
that they will keep working on them.
I think what we need here is guidlines of some sort. Are we actually
trying to maintain backwards compatibility? If so, for how long? If a
change can't be done with breaking API compatibility do we just put it
in ApiChanges and move on?
Some of these problems could be dealt with programatically. eg.
versioned API's.
Personally, I think the following guidelines would be okay:
- Always try to maintain API compatibility.
- If an interface must be changed, try to maintain the old interface
for at least one minor (eg. 0.10 -> 0.11) version change, logging
deprecation warnings when it's used. Document the API change in
ApiChanges/<version>
- If the old interface can't be maintained, document it as such in
ApiChanges/<version>.
Interface deprecation warnings could be automated:
eg.
class ISomeInterface(Interface):
deprecated = True
def interface_method(req):
pass
and for individual method signature changes:
class ISomeOtherInterface(Interface)
def interface_method(req):
pass
interface_method.deprecated = True
These would log warnings whenever the interface was used.
Or perhaps go another route and have components declare what version of
an interface they conform to.
> I think that if we can keep an existing API, at least for a single
> major release, that would be really nice.
>
> Maybe a warning could be added in the log ('DEBUG' level) when an
> outdated API is still in used by a plugin/macro component, to warn the
> admin that the next upgrade will fail if it does not upgrade this 3rd
> party tool.
We've discussed this in the past, specifically interface validation. I
can't really see a reason *not* to add it, and it would definitely help
plugin authors. Here's a patch implementing some basic checks:
http://swapoff.org/files/interface-check.diff
And the "violations" in Trac proper follow. While a lot of these are
simply naming warts, some of them are actual errors (including those
mentioned in #4139).
DEBUG: Interface method trac.db.api.IDatabaseConnector.get_connection(self,
**kwargs) contains varargs, can't check interface conformance for component
trac.db.mysql_backend.MySQLConnector.
DEBUG: Interface method trac.db.api.IDatabaseConnector.init_db(self, **kwargs)
contains varargs, can't check interface conformance for component
trac.db.mysql_backend.MySQLConnector.
DEBUG: Interface method trac.db.api.IDatabaseConnector.get_connection(self,
**kwargs) contains varargs, can't check interface conformance for component
trac.db.postgres_backend.PostgreSQLConnector.
DEBUG: Interface method trac.db.api.IDatabaseConnector.init_db(self, **kwargs)
contains varargs, can't check interface conformance for component
trac.db.postgres_backend.PostgreSQLConnector.
DEBUG: Interface method trac.db.api.IDatabaseConnector.get_connection(self,
**kwargs) contains varargs, can't check interface conformance for component
trac.db.sqlite_backend.SQLiteConnector.
DEBUG: Interface method trac.db.api.IDatabaseConnector.init_db(self, **kwargs)
contains varargs, can't check interface conformance for component
trac.db.sqlite_backend.SQLiteConnector.
WARNING: Component method trac.db.sqlite_backend.SQLiteConnector.to_sql(cls,
table) arguments differ in name from the Interface method
trac.db.api.IDatabaseConnector.to_sql(self, table)
WARNING: Component method
trac.wiki.intertrac.InterTracDispatcher.render_macro(self, req, name, content)
arguments differ in name from the Interface method
trac.wiki.api.IWikiMacroProvider.render_macro(self, formatter, name, content)
WARNING: Component method
trac.mimeview.pygments_renderer.PygmentsRenderer.render(self, context,
mimetype, content, filename=None, rev=None) arguments differ in name from the
Interface method trac.mimeview.api.IHTMLPreviewRenderer.render(self, context,
mimetype, content, filename=None, url=None)
ERROR: Component method
trac.mimeview.pygments_renderer.PygmentsRenderer.render_preference_panel(self,
req, panel) does not match Interface method
trac.prefs.api.IPreferencePanelProvider.render_preference_panel(self, req,
panel, path_info)
WARNING: Component method
trac.mimeview.pygments_renderer.PygmentsRenderer.render_preference_panel(self,
req, panel) arguments differ in name from the Interface method
trac.prefs.api.IPreferencePanelProvider.render_preference_panel(self, req,
panel, path_info)
ERROR: Component method
trac.prefs.web_ui.PreferencesModule.render_preference_panel(self, req, panel)
does not match Interface method
trac.prefs.api.IPreferencePanelProvider.render_preference_panel(self, req,
panel, path_info)
WARNING: Component method
trac.prefs.web_ui.PreferencesModule.render_preference_panel(self, req, panel)
arguments differ in name from the Interface method
trac.prefs.api.IPreferencePanelProvider.render_preference_panel(self, req,
panel, path_info)
WARNING: Component method trac.ticket.query.QueryModule.convert_content(self,
req, mimetype, query, key) arguments differ in name from the Interface method
trac.mimeview.api.IContentConverter.convert_content(self, req, mimetype,
content, key)
WARNING: Component method trac.ticket.web_ui.TicketModule.convert_content(self,
req, mimetype, ticket, key) arguments differ in name from the Interface method
trac.mimeview.api.IContentConverter.convert_content(self, req, mimetype,
content, key)
WARNING: Component method
trac.versioncontrol.web_ui.browser.BrowserModule.annotate_row(self, context,
row, lineno, line, blame_annotator) arguments differ in name from the Interface
method trac.mimeview.api.IHTMLPreviewAnnotator.annotate_row(self, context, row,
number, line, annotations)
WARNING: Component method
trac.versioncontrol.svn_fs.SubversionConnector.get_repository(self, type, dir,
authname) arguments differ in name from the Interface method
trac.versioncontrol.api.IRepositoryConnector.get_repository(self, repos_type,
repos_dir, authname)
WARNING: Component method
trac.admin.web_ui.PermissionAdminPanel.render_admin_panel(self, req, cat, page,
path_info) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.admin.web_ui.BasicsAdminPanel.render_admin_panel(self, req, cat, page,
path_info) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.admin.web_ui.LoggingAdminPanel.render_admin_panel(self, req, cat, page,
path_info) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.admin.web_ui.PluginAdminPanel.render_admin_panel(self, req, cat, page, _)
arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.ticket.admin.ComponentAdminPage.render_admin_panel(self, req, cat, page,
component) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.ticket.admin.MilestoneAdminPage.render_admin_panel(self, req, cat, page,
milestone) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method
trac.ticket.admin.VersionAdminPage.render_admin_panel(self, req, cat, page,
version) arguments differ in name from the Interface method
trac.admin.api.IAdminPanelProvider.render_admin_panel(self, req, category,
page, path_info)
WARNING: Component method trac.wiki.interwiki.InterWikiMap.render_macro(self,
req, name, content) arguments differ in name from the Interface method
trac.wiki.api.IWikiMacroProvider.render_macro(self, formatter, name, content)
--
Evolution: Taking care of those too stupid to take care of themselves.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac
Development" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/trac-dev?hl=en
-~----------~----~----~----~------~----~------~--~---