Edgewall Software

Extension Point : ITicketManipulator


The ITicketManipulator can manipulate and validate tickets before saving.


The Trac ticketing system is extendable by plugins. These plugins might add additional fields or introduce new restrictions on existing fields. They might want to automatically manage some fields. Any such ticket manipulations or validations can be added by implementing the ITicketManipulator interface.


Implementing the interface follows the standard guidelines found in TracDev/ComponentArchitecture and of course TracDev/PluginDevelopment.

The validate_ticket method is called when a user creates or modifies a ticket. Returning a list of messages rejects the (changed) ticket, returning [] accepts it.

Note that the validate_ticket method can also be used to manipulate the ticket's fields before they are saved.

Note that the validate_ticket method is also called during preview. Check if 'submit' in req.args or 'preview' in req.args to determine if the validated ticket is getting saved or just previewed.

Since 1.3.2, validate_comment is called when appending or editing a ticket comment. The method is optional, and therefore only invoked when the method is present on the class implementing ITicketManipulator. Check for 'edit_comment' in req.args or 'preview_comment' in req.args to determine if the ticket comment edit is being submitted or previewed.

Note that the previous values of a changed ticket can be accessed in ticket._old. (See #10495.)

The prepare_ticket method should always be implemented as an empty dummy method for compatibility reasons:

    def prepare_ticket(self, req, ticket, fields, actions):


One might want to maintain a wiki page with the MostFrequentDuplicates. One could take this idea further and implement a minimal example ITicketManipulator implementation that warns about tickets already listed there:

import re
from trac.core import Component, implements
from trac.ticket.api import ITicketManipulator

class MostFrequentDuplicates(Component):

    def prepare_ticket(self, req, ticket, fields, actions):

    def validate_ticket(self, req, ticket):
        for id, summary in self.mostfrequentduplicates:
            if summary == ticket['summary'] and int(id) != ticket['id']:
                return [(None, "Duplicate of ticket #%s" % id)]
        return []
    _page_name = 'MostFrequentDuplicates'
    _duplicate_re = re.compile(r" - #(\d*): '''(.*)'''")

    def mostfrequentduplicates(self, db):
        """List of (id, summary) values."""
        from trac.wiki.model import WikiPage
        duplicates = []
        content = WikiPage(self.env, MostFrequentDuplicates._page_name, db=db).text
        for line in content.split('\n'):
            m = re.match(MostFrequentDuplicates._duplicate_re, line)
            if m:
        return duplicates

Available Implementations

Additional Information and References

Last modified 3 years ago Last modified on Jul 23, 2020, 8:33:53 PM
Note: See TracWiki for help on using the wiki.