API Versioning

Bazaar

API Versioning

Status

Date:2007-06-26

bzrlib has a rich API which is used both internally, and externally by plugins and scripts. To allow the API to change, specifically to allow support for features and methods to be removed, without causing hard to diagnose bugs in the clients of the API, bzrlib provides explicit API compatibility data, and a compact API to allow scripts and plugins to ascertain if the bzrlib they are using is compatible to the API they were written against.

Motivation

To allow plugins to apply their own policy for compatibility with bzrlib, without requiring a new release on every library release. Plugins should also be able to use the API to export their own compatibility information for code reuse between plugins.

Terminology

An API is a collection of python objects/modules/packages which can be used by plugins and scripts. The bzrlib API covers all of bzrlib, but we can be more precise - e.g. the WorkingTree API. An API version is a tuple (major, minor, point).

API versions

For simplicity we treat API’s as being compatible with a range of versions: the current release of the API, and some oldest version which is also compatible. While we could say that there is a set of older versions with which the current version is compatible, a range is easier to express, and easier for a human to look at and understand, and finally easier to manage. The oldest version with which the API for a python object is compatible is obtained by looking up the api_minimum_version attribute on the python object handed to require_api, and failing that the bzrlib api_minimum_version is returned. The current version of the API is obtained by looking for an api_current_version attribute, and if that is not found, an version_info attribute (of which the first 3 elements are used). If no current version can be found, the bzrlib version_info attribute is used to generate a current API version. This lookup sequence allows users with simple setups (and no python style version_info tuple) to still export an API version, and for new API’s to be managed more granularly later on with a smooth transition - everything starts off in lockstep with bzrlib’s master version.

API versions are compared lexically to answer the question ‘is the requested version X <= the current version, and >= the minimum version’.

Managing API versions

The minimum API versions should be adjusted to the oldest API version with which client code of the API will successfully run. It should not be changed simply because of adding things in a compatible manner, or deprecating features, but rather when errors will occur if client code is not updated. Versions for API’s from bzrlib are given the version numbers that bzrlib has had for consistency. Plugins should also take this approach and use the version numbering scheme the plugin used.

Exported API’s

Currently we export a single API - the bzrlib API - and no finer grained APIs. The API versioning support was introduced in bzrlib 0.18. For plugins or tools that want to dynamically check for the presence of the API versioning API, you should compare bzrlib.version_info[0:3] with (0, 18, 0).

API Covers
bzrlib All of bzrlib

Use Cases

Some examples of using the API.

Requiring bzrlib 0.18 in a plugin

In the plugins __init__.py:

import bzrlib
from bzrlib.api import require_api
from bzrlib.errors import IncompatibleAPI
try:
  require_api(bzrlib, (0, 18, 0))
except IncompatibleAPI:
  raise ImportError("A bzrlib compatible with 0.18 is required.")

Exporting an API from a plugin

In the plugin foo exporting the API (in __init__.py):

version_info = (0, 0, 1, 'beta', 1)
api_version = (0, 0, 1)

In a plugin depending on that plugin (in __init__.py):

import bzrlib.plugins.foo
from bzrlib.api import require_api
from bzrlib.errors import IncompatibleAPI
try:
  require_api(bzrlib.plugins.foo, (0, 0, 1))
except IncompatibleAPI:
  raise ImportError("A bzrlib compatible with 0.0.1 is required.")