= The Malone (Launchpad) XMLRPC Interface = Malone currently provides an XML-RPC interface for filing bugs. == Synopsis == {{{ #!/usr/bin/python from xmlrpclib import ServerProxy s = ServerProxy("https://test@canonical.com:test@xmlrpc.launchpad.net/bugs/") s.filebug(dict( distro="ubuntu", package="mozilla-firefox", summary="the summary", comment="the description", subscribers=["foo.bar@canonical.com"])) }}} == For the truly interested == >>> from canonical.launchpad.xmlrpc import FileBugAPI >>> filebug_api = FileBugAPI(None, None) === The filebug API === The filebug API is: {{{ filebug_api.filebug(params) }}} params is a dict, with the following keys: REQUIRED ARGS: * summary: A string * comment: A string OPTIONAL ARGS: * product: The product name, as a string. Default None. * distro: The distro name, as a string. Default None. * package: A string, allowed only if distro is specified. Default None. * security_related: Is this a security vulnerability? Default False. * subscribers: A list of email addresses. Default None. Either product or distro must be provided. The bug owner is the currently authenticated user, taken from the request. The return value is the bug URL, in short form, e.g.: http://launchpad.net/bugs/42 == Examples == First, let's define a simple event listener to show that the ISQLObjectCreatedEvent is being published when a bug is reported through the XML-RPC interface. {{{ >>> from canonical.launchpad.event.interfaces import ISQLObjectCreatedEvent >>> from canonical.launchpad.ftests.event import TestEventListener >>> from canonical.launchpad.interfaces import IBug >>> def on_created_event(obj, event): ... print "SQLObjectCreatedEvent: %r" % obj >>> on_created_listener = TestEventListener( ... IBug, ISQLObjectCreatedEvent, on_created_event) }}} === Reporting a product bug === (We'll define a simple function to extract the bug ID from the URL return value.) {{{ >>> def get_bug_id_from_url(url): ... return int(url.split("/")[-1]) >>> login("test@canonical.com") >>> params = dict( ... product='firefox', summary='the summary', comment='the comment') >>> bug_url = filebug_api.filebug(params) SQLObjectCreatedEvent: >>> print bug_url http://launchpad.dev/bugs/... >>> from zope.component import getUtility >>> from canonical.launchpad.interfaces import IBugSet >>> bugset = getUtility(IBugSet) >>> bug = bugset.get(get_bug_id_from_url(bug_url)) >>> print bug.title the summary >>> print bug.description the comment >>> print bug.owner.name name12 >>> firefox_bug = bug.bugtasks[0] >>> print firefox_bug.product.name firefox }}} === Reporting a distro bug === {{{ >>> params = dict( ... distro='ubuntu', summary='another bug', comment='another comment') >>> bug_url = filebug_api.filebug(params) SQLObjectCreatedEvent: >>> print bug_url http://launchpad.dev/bugs/... >>> bug = bugset.get(get_bug_id_from_url(bug_url)) >>> print bug.title another bug >>> print bug.description another comment >>> print bug.owner.name name12 >>> ubuntu_bug = bug.bugtasks[0] >>> print ubuntu_bug.distribution.name ubuntu >>> ubuntu_bug.sourcepackagename is None True }}} === Reporting a package bug === {{{ >>> params = dict( ... distro='ubuntu', package='evolution', summary='email is cool', ... comment='email is nice', security_related=True, ... subscribers=["no-priv@canonical.com"]) >>> bug_url = filebug_api.filebug(params) SQLObjectCreatedEvent: >>> print bug_url http://launchpad.dev/bugs/... >>> bug = bugset.get(get_bug_id_from_url(bug_url)) >>> print bug.title email is cool >>> print bug.description email is nice >>> bug.security_related True >>> bug.private True >>> sorted(p.name for p in bug.getDirectSubscribers()) [u'name12', u'no-priv', u'ubuntu-team'] >>> bug.getIndirectSubscribers() [] >>> evolution_bug = bug.bugtasks[0] >>> print evolution_bug.distribution.name ubuntu >>> print evolution_bug.sourcepackagename.name evolution }}} == Error Handling == Malone's xmlrpc interface provides extensive error handling. The various error conditions it recognizes are: Failing to specify a product or distribution. {{{ >>> params = dict() >>> filebug_api.filebug(params) }}} Specifying *both* a product and distribution. {{{ >>> params = dict(product='firefox', distro='ubuntu') >>> filebug_api.filebug(params) }}} Specifying a non-existent product. {{{ >>> params = dict(product='nosuchproduct') >>> filebug_api.filebug(params) }}} Specifying a non-existent distribution. {{{ >>> params = dict(distro='nosuchdistro') >>> filebug_api.filebug(params) }}} Specifying a non-existent package. {{{ >>> params = dict(distro='ubuntu', package='nosuchpackage') >>> filebug_api.filebug(params) }}} Missing summary. {{{ >>> params = dict(product='firefox') >>> filebug_api.filebug(params) }}} Missing comment. {{{ >>> params = dict(product='firefox', summary='the summary') >>> filebug_api.filebug(params) }}} Invalid subscriber. {{{ >>> params = dict( ... product='firefox', summary='summary', comment='comment', ... subscribers=["foo.bar@canonical.com", "nosuch@subscriber.com"]) >>> filebug_api.filebug(params) >>> on_created_listener.unregister() }}}