{{{#!div style="float: right; margin: 0 1em" ← [../0.11] | [../1.0] → }}} = !TracDev/ApiChanges/0.12 = [[PageOutline(2-4,Summary,inline)]] == Prerequisites == Python 2.3 support has been dropped. Python versions 2.4, 2.5, 2.6 and 2.7 are supported. === Modified Dependencies === The bundled version of [http://jquery.com jQuery] is now 1.4.2 instead of 1.2.6 in Trac 0.11. Among other things, this means that previously deprecated selector syntax is now no longer supported. See [http://docs.jquery.com/Release:jQuery_1.3#Changes jQuery 1.3 API changes], [http://jquery14.com/day-01/jquery-14 jQuery 1.4 API changes] and [http://jquery14.com/day-12 jQuery 1.4.1 API changes] for details. === New Dependencies === ==== Babel (optional) ==== The internationalization support (i18) for Trac is depending on [http://babel.edgewall.org/ Babel]. It's perfectly fine to go on using Trac without it, but then of course the interface will remain in English. == Modifications made to the 0.12 API == === Modified Interfaces === ==== `IWikiMacroProvider` ^[source:trunk/trac/wiki/api.py@8372:85#L72 (0.12)] [source:branches/0.11-stable/trac/wiki/api.py@8372:90#L77 (0.11)]^ ==== #IWikiMacroProvider Added an optional argument `args` to `IWikiMacroProvider.expand_macro()` to contain the shebang-line arguments when using wiki processor syntax. For example, with the following content: {{{ {{{ #!MyMacro test=123 other="This is a text" This is the content. }}} }}} The macro `MyMacro` will have its `expand_macro()` called with `args={'test': '123', 'other': 'This is a text'}`. See also #8204. ==== `IWikiPageManipulator` ^[source:trunk/trac/wiki/api.py@8429:64#L52 (0.12)] [source:branches/0.11-stable/trac/wiki/api.py@8429:69#L57 (0.11)]^ ==== #IWikiPageManipulator This interface has not actually been changed, but the implementation has been fixed so that it actually does what it promises, that is, validate a wiki page ''after it's been populated'' from user input. Previously, `page.text` would contain the old text, and the new text would typically be retrieved with `req.args.get('text')` as a workaround. The `page` now has the new text in `page.text`, and the old text in `page.old_text`. See also #7731. === Other Changes === ==== `Environment.get_db_cnx` is deprecated #get_db_cnx Due to the new support for automated transaction management, `Connection` instances should no longer be acquired using the familiar `get_db_cnx` method, as it doesn't tell whether the connection will be used as part of a write transaction or purely for queries. Instead, one should use: - `env.get_read_db` for obtaining a `Connection` suitable for read queries (i.e. `SELECT`) - the `env.with_transaction` decorator, for using a `db` parameter in a transaction function which should be committed when the last such automatic transaction in the control flow completes successfully (see [#with_transaction details] further down) Using `env.get_db_cnx` still works, but any explicit transaction management will risk to prematurely end a higher level transaction set up via `with_transaction` at a previous level in the control flow. ==== `prevnext_nav` support for i18n ^[source:trunk/trac/web/chrome.py@8597:158-164#L158 (0.12)] [source:branches/0.11-stable/trac/web/chrome.py@8550:139-144#L139 (0.11)]^ ==== #prevnext_nav The `prevnext_nav` function used for adding contextual navigation links was not i18n friendly. In order to make the need for adaptation obvious, the arity of the function has changed and the label for the previous and next links have to be spelled out in full. ==== `Href` with an empty base ^[source:trunk/trac/web/tests/href.py@8551:61-62,76-78#L57 (0.12)] [source:branches/0.11-stable/trac/web/tests/href.py@8551:63-64,79-81#L57 (0.11)]^ ==== #Href The `Href` class has been changed to ensure that it always generates valid URLs, even with an empty base. In 0.11, the following uses all return an empty string: {{{ #!python # 0.11 >>> href = Href('') # Also applies to Href('/') >>> href() '' >>> href('/') '' }}} In 0.12, the same expressions return a valid relative URL: {{{ #!python # 0.12 >>> href = Href('') >>> href() '/' >>> href('/') '/' }}} This change will break plugins that use the following idiom to concatenate the base URL with a path starting with a slash: {{{ #!python # 0.12 >>> href = Href('') >>> path = '/path/to/page' >>> href() + path # Broken '//path/to/page' }}} For this specific use case, a new syntax has been added to avoid doubled slashes: {{{ #!python # 0.12 and 0.11.6 >>> href = Href('') >>> path = '/path/to/page' >>> href + path # New syntax '/path/to/page' }}} The new syntax has been backported to 0.11-stable in 0.11.6 to facilitate compatibility of plugins with both 0.11.6 and 0.12. If compatibility with older releases of the 0.11.x branch is required, the following code can be used: {{{ #!python # 0.12 and 0.11.x >>> href = Href('') >>> path = '/path/to/page' >>> href().rstrip('/') + path # Compatibility '/path/to/page' }}} See also #8159. ==== [TracStandalone tracd] and HTTP/1.1 ==== Since 0.11.5, tracd could be used with the `--http11` flag, which would select the use of the HTTP/1.1 protocol and most notably activate Keep-Alive connections. This is now the default behavior in 0.12. This has some important consequences for plugins which send content directly to the client. They should take care of setting the `Content-Length` header properly, otherwise the browser will simply "hang". This means that any: {{{ #!python req.write(content) }}} must be preceded by a: {{{ #!python req.send_header('Content-Length', len(content)) }}} Don't forget to do that for ''any'' data directly sent back to the client, including responses for XHRs (e.g. r8300). This requires some discipline in the coding, but the benefit is a huge performance boost for tracd, so it's well worth the price. In order to make errors more immediately visible, the `Request.write` method is more strict in 0.12: it only accepts `str` data parameter, and will also raise an exception if the Content-Length header was not set prior to the call. See #8020 and #8675 for details. ==== `Environment.get_repository()` ^[source:trunk/trac/env.py@9156:316#L315 (0.12)] [source:branches/0.11-stable/trac/env.py@8353:287#L286 (0.11)]^ ==== #EnvGetRepository The standard way of retrieving a repository object is now through the methods of `RepositoryManager`. The method `Environment.get_repository()` has been retained for backward compatibility, and a new argument `reponame` has been added to allow retrieving other repositories than the default repository. The `authname` argument has been kept for backward compatibility, but is not used anymore (see [#Authz authz permission checking] below). ==== Authz permission checking ==== #Authz Permission checking using an [http://svnbook.red-bean.com/en/1.5/svn.serverconfig.pathbasedauthz.html authz]-type file has been moved from an `Authorizer` instance used by `SubversionRepository` to a fine-grained permission policy `AuthzSourcePolicy` defined in [source:trunk/trac/versioncontrol/svn_authz.py@9125#L112 svn_authz.py]. This allows using authz files not only for Subversion repositories, but also for other repository types. Consequently, the `Authorizer`, `PermissionDenied` and `RealSubversionAuthorizer` classes as well as the `SubversionAuthorizer` function have been removed. See #7116 for details. ==== `Repository` constructor ^[source:trunk/trac/versioncontrol/api.py@9125:677,683-686#L674 (0.12)] [source:branches/0.11-stable/trac/versioncontrol/api.py@8353:191#L188 (0.11)]^ ==== #Repository Due to the [#Authz authz] changes above, the `authz` argument has been removed from the `Repository` constructor. Conversely, a new argument `params` has been added to the `Repository` constructor. `params` is a dictionary containing various parameters for the repository, and is stored as a `.params` attribute in `Repository`. The value for the key `"name"` is the repository name (available as `.reponame`) as displayed in the source browser. The value for the key `"id"` (available as `.id`) is the surrogate key identifying the repository in the database. Both changes need to be taken into account by derived classes (typically in plugins implementing version control backends), which must propagate the arguments up to `Repository.__init__()` See #7116 for details on the `authz` argument, and #8731 for the `params` argument. ==== `Repository` revision transformation ^[source:trunk/trac/versioncontrol/api.py@9559:875-882#L857 (0.12)]^ ==== #Repository.display_rev In addition to `Repository.normalize_rev(rev)`, which returns a (unique) normalized representation of the given revision (usually a full revision number or hash), and `Repository.short_rev(rev)`, which returns a short representation of the a revision to be used e.g. for source annotation, a new `Repository.display_rev(rev)` method can be implemented by version control backends to return a representation of a revision suitable for display to the user. By default, `display_rev()` calls `normalize_rev()`. See #9230 for details. ==== `Node` constructor ^[source:trunk/trac/versioncontrol/api.py@9125:905#L887 (0.12)] [source:branches/0.11-stable/trac/versioncontrol/api.py@8353:368#L354 (0.11)]^ ==== #Node The `Repository` instance to which a node belongs is now passed as an additional `repos` argument to the `Node` constructor, and stored in the `.repos` attribute. This argument must be forwarded by `Node` subclasses (typically in plugins implementing version control backends). See #7116 for details. ==== `Changeset` constructor ^[source:trunk/trac/versioncontrol/api.py@9125:1021#L1004 (0.12)] [source:branches/0.11-stable/trac/versioncontrol/api.py@8353:473#L459 (0.11)]^ ==== #Changeset The `Repository` instance to which a changeset belongs is now passed as an additional `repos` argument to the `Changeset` constructor, and stored in the `.repos` attribute. This argument must be forwarded by `Changeset` subclasses (typically in plugins implementing version control backends). See #7116 for details. ==== `CachedRepository` constructor ^[source:trunk/trac/versioncontrol/cache.py@9125:44#L38 (0.12)] [source:branches/0.11-stable/trac/versioncontrol/cache.py@8353:45#L39 (0.11)]^ ==== #CachedRepository In 0.11, the first argument to the `CachedRepository` constructor was a callable that would return a DB instance when called. In 0.12, the first argument has been changed to an `Environment` instance. Subclasses of `CachedRepository` must therefore be changed accordingly, and components implementing `IRepositoryConnector` and returning a `CachedRepository` or a subclass must pass `self.env` instead of a `getdb` callable. Moreover, the `authz` argument has been removed as well, as described [#Repository above]. ==== Text template syntax ==== Text template processing has been changed from the [genshi:wiki:Documentation/text-templates.html#legacy-text-template-syntax legacy text template syntax] to the [genshi:wiki:Documentation/text-templates.html new text template syntax]. The main difference is that directives are now enclosed in `{% %}` and can be placed anywhere in the text, whereas they were previously placed on their own line with a leading `#`. All text templates used by plugins must therefore be converted to the new syntax. The same applies to overridden templates placed in the `templates` folder of environments. See #8513 for details. ==== Timestamp storage in database ==== Timestamps associated with resources and stored in the database have been changed from second to microsecond resolution. This should not affect plugins that use the model classes to access resources. However, plugins accessing the database tables directly need to be adapted. Conversion between `datetime` objects and microsecond timestamps can be performed with the new functions `from_utimestamp()` and `to_utimestamp()` in [source:trunk/trac/util/datefmt.py@9210:64,72#L63 trac/util/datefmt.py]. See #6466 for details. == New in the 0.12 API == === New Classes === ==== `trac.cache.CacheManager` ^[source:trunk/trac/cache.py@#L91 (0.12)]^ ==== #CacheManager There's a new cache subsystem in [source:trunk/trac/cache.py trac.cache] allowing Component instances to cache any data in a safe way. Whenever the cache entry is invalidated, the cached value will be automatically refreshed at the next retrieval, //even if the invalidation occurs in a different process//. This makes the `config.touch()` trick obsolete. New decorator: `trac.cache.cached` ^[source:trunk/trac/cache.py@#L49 (0.12)]^ See TracDev/CacheManager for details. ==== `trac.util.text.empty` ^[source:trunk/trac/util/text.py@#L30 (0.12)]^ ==== #empty Special marker object used to represent a NULL value from the database as an empty string, yet be able to distinguish it from `''` when really necessary. === New Interfaces === ==== `trac.admin.api.IAdminCommandProvider` ^[source:trunk/trac/admin/api.py@9700:56-77#L55 (0.12)]^ ==== #IAdminCommandProvider The `IAdminCommandProvider` interface allows components to provide additional `trac-admin` commands. It supports short and long help texts, as well as command and argument auto-completion. See #7770 for details. ==== `trac.env.ISystemInfoProvider` ^[source:trunk/trac/env.py@9251:44-51#L43 (0.12)]^ ==== #ISystemInfoProvider The `ISystemInfoProvider` interface allows components to provide version information about external packages they use. This information is displayed on the "About Trac" page, as well as in internal error reports. This interface replaces the direct mutation of the `env.systeminfo` list that was used previously (the list is still present for backward compatibility). The advantage of using an interface for this is that it ensures that the components are loaded when the system information is requested. See #8908 for details. ==== `trac.ticket.api.IMilestoneChangeListener` ^[source:trunk/trac/ticket/api.py@8828:141-157#L140 (0.12)]^ ==== #IMilestoneChangeListener Components implementing the `IMilestoneChangeListener` interface are notified upon creation, modification and deletion of milestones. The milestone model object is passed to each handler. Moreover, on modification an additional dictionary is passed, containing the attributes that were modified and their previous values. See #6543 for details. ==== `trac.versioncontrol.api.IRepositoryChangeListener` ^[source:trunk/trac/versioncontrol/api.py@9125:83-95#L82 (0.12)]^ ==== #IRepositoryChangeListener Components implementing the `IRepositoryChangeListener` interface are notified when new changesets are added to a repository, and when metadata for changesets is modified. Both events are generated by `trac-admin $ENV changeset` commands, and therefore require that hooks in the repositories call these commands on commit and revision property changes, as described in [wiki:0.12/TracRepositoryAdmin#ExplicitSync TracRepositoryAdmin]. See #7723 for details. ==== `trac.versioncontrol.api.IRepositoryProvider` ^[source:trunk/trac/versioncontrol/api.py@9154:65-87#L64 (0.12)]^ ==== #IRepositoryProvider Components implementing `IRepositoryProvider` provide information about repositories managed by a Trac instance. There are currently two components implementing this interface: the first one extracts repository information from the `[repositories]` section of [wiki:0.12/TracRepositoryAdmin#ReposTracIni trac.ini], the second from [wiki:0.12/TracRepositoryAdmin#ReposDatabase the database]. Plugins can implement additional providers, for example to automatically include all repositories located below a given directory (similar to the `SVNParentPath` directive of [http://svnbook.red-bean.com/en/1.5/svn.ref.mod_dav_svn.conf.html mod_dav_svn]). === Other news === ==== `trac.db.util.with_transaction()` ^[source:trunk/trac/db/util.py@9701:23-78#L22 (0.12)]^ ==== #with_transaction The `@with_transaction(env)` decorator replaces the current practice of getting a database connection with `env.get_db_cnx()` and issuing an explicit commit or rollback. Applied to a local function, it calls that function with a database connection as an argument, and either issues a commit if the function terminates normally, or a rollback if the function raises an exception. In the latter case, the exception is re-raised. This makes transactions much more robust, as we can guarantee that any mutating operations on the database are either committed or rolled back. This should avoid issues like #8443, where transactions were kept open in IDLE state. This mechanism also handles transaction nesting automatically, by only committing or rolling back in the outermost transaction block. This avoids having to pass a `db` argument around, like was typically done in model object methods like [source:trunk/trac/wiki/model.py@9701:120#L119 WikiPage.save()]. The `db` argument is still supported for backward compatibility in methods that were present in 0.11, but is deprecated and should not be used in new code. To avoid having to import `with_transaction` from `trac.db.util` in every module using transactions, it can also be called conveniently on the environment as `@env.with_transaction()`. Implementing this mechanism as a function decorator is an intermediate solution until the `with` statement and context managers become available (once we drop support for Python 2.4). See #8751 for details and related notes about [#get_db_cnx get_db_cnx] deprecation above.