API from Python?

Hi all

We’re doing some experimentation around plugging RT into a "dashboard"
type application that pulls other (internal) application data together.
Problem is, our preferred scripting language is Python. We have enough
Perl knowledge to survive, but no in-depth competence.

Is there a viable way of calling the RT API from Python? Or is this simply
not going to happen? Any ideas, war stories, etc, welcome.

Thanks,
Keith

Use the REST interface?
Cambridge Energy Alliance: Save money & the planet

Thanks, but I’m thinking of also how to get information out of RT. I could
use the command line interface and parse the output, but I was wondering
if there was a way of using the API from Python.
Umm, REST allows you to get stuff too. See the perl client library for hints
RT::Client::REST - talk to RT installation using REST protocol. - metacpan.org

Cambridge Energy Alliance: Save money & the planet

Hello.

There are 2 modules on CPAN: pyperl to use Perl from Python and
Inline::Python to use Python from Perl. I don’t know if they are still
working.2008/8/13 Keith Edmunds kae@midnighthax.com:

Hi all

We’re doing some experimentation around plugging RT into a “dashboard”
type application that pulls other (internal) application data together.
Problem is, our preferred scripting language is Python. We have enough
Perl knowledge to survive, but no in-depth competence.

Is there a viable way of calling the RT API from Python? Or is this simply
not going to happen? Any ideas, war stories, etc, welcome.

Alexandr Ciornii, http://chorny.net

Thanks, but I’m thinking of also how to get information out of RT. I could
use the command line interface and parse the output, but I was wondering
if there was a way of using the API from Python.
Umm, REST allows you to get stuff too. See the perl client library for hints
RT::Client::REST - talk to RT installation using REST protocol. - metacpan.org

The command-line interface actually uses the REST interface for getting
data into and out of RT. :slight_smile:

Yes, one can (and should :slight_smile: use the REST interface from python. It
takes a fair bit of hacking around, and reading bin/rt.in and
html/REST/1.0/dhandler (which do a lot of things implicitly, making
them poor-to-wretched as “documentation” :slight_smile: Hopefully this will save
you some reverse engineering and let you get some simple tools off the
ground.

I use pycurl, mostly because our RT instance uses kerberos auth, and
pycurl actually handles that (otherwise I tend to prefer pure-python
approaches.)

Note also that all of this is based on 3.6.1, which is I think the
first release where the REST interface worked at all with Custom
Fields; I seem to recall the later 3.6’s didn’t improve on this, but
3.8.0 might (before you harp on how old that makes 3.6, recall that
there wasn’t a 3.7…)

Searching is about as much of a pain as it is with searchbuilder; at
least in 3.6.1 (which we’re still running), it fails in much the same
ways as well (I just discovered that we have a custom field with a
value of “Won’t fix” and the REST interface can’t match it - but
neither can the web interface :-}

A simple search is just a matter of doing a GET on:

query = urllib.quote(rawquery)
query_url = RT_RESTBASE + “/search/ticket?” + (“format=%s” % format) + (“&query=%s” % query)

format is “l” or “s” (depending on the output you want.) RT_RESTBASE
is “your-site/rt/REST/1.0”.

This particular code is in a tool called “rt_list_mine”, so:

rawquery = “owner=‘%s@metacarta.com’” % os.getenv(“USER”)

(if you aren’t us, you need to change that, of course :slight_smile:

If I’ve given the optional --status argument,

rawquery = rawquery + “AND ‘CF.{Ticket Status}’='” + status + “'”

Note that that’s a CF (“custom field”) - you can get sample syntax for
these strings by building a search in the webui and looking at the SQL
box (or just going to “Advanced” and cut&pasting it from there.) The
important thing is that this goes through the urllib.quote above.

Just this past week I took another shot at this, which is why it’s
fresh in mind: actually updating a ticket from python code is an
entirely different thing. First step is to clear your mind of the
idea that the ticket is a REST object. It’s simply a url with an edit
method that lets you stuff a text representation of your fields into
the ticket. This is what the CLI does - as far as I can tell (since
it doesn’t actually work with kerberos) it fetches the fields of the
ticket, lets you edit them, then posts them back to cause an update.
(At least as of 3.6.1, I don’t see how this works, because with the
fields I’m using, it appends the posted data…)

Anyway, we have a simple svn-linkage where we have a custom field
which has a renderer that posts off to another service and gets back a
given revisions changed-files, log message, and link to svnweb. In
order to update that from the command line, I use this code:

def update_ticket(ticket, revision):
“”“add a revision to a ticket”“”
assert ticket, “please supply a ticket number”
assert revision, “please supply a revision”
# we don’t actually need to edit the ticket like bin/rt does…
content = {
“id”: “ticket/%s” % ticket,
“CF-Revisions”: “r%s” % revision,
}
postcontent = “\n”.join([“%s: %s” % (k, v) for k, v in content.items()]) + “\n”
status, res = basepost(make_rest_url(“edit”), [(“content”, postcontent)])
print status, res
if status != 200:
return res

basepost just posts to the url; it’s using “c.setopt(c.HTTPPOST, postdata)”
underneath, which is a relatively new pycurl feature, thus the
list-of-fields structure of the argument (saves dealing with mime
encoding altogether.) make_rest_url just adds the given string to
RT_RESTBASE above, so that’s posting to /rt/REST/1.0/edit. (In
theory, you can encode the ticket in the URL; in practice, using the
id field in the content made more sense.)

To get an idea what the fields are actually called (which isn’t the
same as what they’re displayed as in the UI), you can fetch a sample
ticket using the REST show interface (instead of the search interface
above) with a similar POST:

basepost(RT_RESTBASE + “/ticket/show”, [(“id”, “17747”)])

In theory the output you get back could all be posted up using the
technique used in update_ticket. In practice, you’ll get failures
like

  • a field named “CF-Release notes?” will give you a Syntax Error
  • you’ll get complaints about “LastUpdated: Immutable field” which
    you can ignore, since they don’t prevent the update from going
    through :slight_smile:
  • there’s some confusion about updating list fields; they’ll come
    back from a /ticket/show as having just commas in them, but that
    will go away if you do any update through the web UI.

Hope this saves you some reverse engineering :slight_smile: I’d like to see a
more solid REST interface - ok, what I really want is an emacs mode,
like I had for PRMS/GNATS! - but my renewed patience for the perl
expired about halfway through implementing update_ticket above :slight_smile:

		_Mark_ <eichin@metacarta.com>

Note also that all of this is based on 3.6.1, which is I think the
first release where the REST interface worked at all with Custom
Fields; I seem to recall the later 3.6’s didn’t improve on this,

Actually, there have been a bunch of fixes to the Custom Field
code in the 3.6 branch.

Searching for “Won’t Fix” as a value in a select custom field
works in 3.8. I don’t believe that fix is in 3.6

but
3.8.0 might (before you harp on how old that makes 3.6, recall that
there wasn’t a 3.7…)

3.7 was the unstable branch that became 3.8, just like there wasn’t
a 3.5 between 3.4 and 3.6

It would be great if all the other python usage information in
this post made it into the wiki in some form.

-kevin

Thanks for all the comments and examples of how to use Python to talk to
RT: all very helpful.

Keith