Diff for "API/launchpadlib"

Not logged in - Log In / Register

Differences between revisions 1 and 22 (spanning 21 versions)
Revision 1 as of 2008-05-08 19:00:57
Size: 145
Editor: 216-15-33-253
Comment:
Revision 22 as of 2008-08-15 21:59:47
Size: 13708
Editor: cpe-24-193-113-134
Comment:
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
This is a stub for information about the Python library for scripting Launchpad through its [:API: web services interface].   https://launchpad.net/launchpadlib

launchpadlib is an open-source Python library that lets you treat the HTTP resources published by Launchpad's web service as Python objects responding to a standard set of commands. With launchpadlib you can integrate your applications into Launchpad without knowing a lot about HTTP client programming.

This document shows how to use a Python client to read and write
Launchpad's data using the launchpadlib library. It doesn't cover the
HTTP requests and responses that go back and forth behind the
scenes: for that, see [[../Hacking|the "hacking" document]]. This document also doesn't cover the full range of what's possible
with Launchpad's web service: for that, see the web service reference
documentation (external link forthcoming).

Launchpad's web service currently exposes the following major parts of Launchpad:

 * People and teams
 * Team memberships
 * Bugs and bugtasks

One part of Launchpad is exposed through the web service, but not
supported by the current version of launchpadlib:

 * Uploaded files, such as bug attachments

As new features and capabilities are added to the web service, you'll be able to access most of them without having to update your copy of launchpadlib. You _will_ have to upgrade launchpadlib to get new client-side features (like support for uploaded files). The Launchpad team will put out an announcement whenever a server-side change means you should upgrade launchpadlib.

= Installation =

The launchpadlib library depends on wadllib, another open-source
library released by the Launchpad team. Get a copy of the wadllib
source with bzr and install it.

{{{
  $ bzr branch lp:wadllib
  $ cd wadllib
  $ sudo ./setup.py install
}}}

Then do the same for launchpadlib.

{{{
  $ bzr branch lp:launchpadlib
  $ cd launchpadlib
  $ sudo ./setup.py install
}}}


= Getting started =

The first step towards using Launchpad's web service is setting up
credentials for your client. Run this code in a Python session:

{{{
    from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT
    launchpad = Launchpad.get_token_and_login('just testing', STAGING_SERVICE_ROOT)
}}}

The first argument is a string that identifies the web service client. We use this string to gauge client
popularity and detect buggy or inefficient clients. Here, though, we're just testing.

The second argument is the URL to the web service. Here, we're using STAGING_SERVICE_ROOT, which is "https://api.staging.launchpad.net/beta/". These examples run against the staging data, so that we don't change real data when we're just trying to see how launchpadlib works.

Once you're ready to write a launchpadlib program that changes real data, you can replace
STAGING_SERVICE_ROOT with EDGE_SERVICE_ROOT.

You'll see a message like this:

{{{
 The authorization page
 (https://staging.launchpad.net/+authorize-token?oauth_token=xxxxxxxxx)
 should be opening in your browser. After you have authorized this
 program to access Launchpad on your behalf you should come back here
 and press <Enter> to finish the authentication process.
}}}

Your web browser will open to a page at launchpad.net. You'll be asked
to login to Launchpad, and grant some level of access to your new
credentials. The level of access you choose will determine how much you
can do through launchpadlib with these credentials. This lets your users
delegate a portion of their Launchpad permissions to your program,
without having to trust it completely.

Once you grant access, hit Enter within your Python session. You'll
get back a Launchpad object. Now you can access the web service.

Here's some code that retrieves a bug from Launchpad and prints its
title.

{{{
    bug_one = launchpad.bugs[1]
    print bug_one.title
    # Microsoft has a majority market share
}}}

Before proceeding further, save your credentials so that you don't
have to do the get_token_and_login dance again the next time you need
to access the web service.

{{{
    launchpad.credentials.save(file("some-file.txt", "w"))
}}}

Let's create a new Launchpad object from saved credentials right now.

{{{
    from launchpadlib.credentials import Credentials
    credentials = Credentials()
    credentials.load(open("some-file.txt"))
    launchpad = Launchpad(credentials, STAGING_SERVICE_ROOT)

    bug_one = launchpad.bugs[1]
    print bug_one.title
    # Microsoft has a majority market share
}}}


= Getting help =

If you don't know the capabilities of one of the objects you've got, you can call dir() on it. You'll see all of its fields and all the custom methods it supports. Unfortunately, you'll also see a bunch of launchpadlib-specific junk that you don't care about. That's why we've made available these four lists:

 * lp_attributes: Data fields of this object. You can read from these might be able to write to some of them.
 * lp_collections: List of launchpad objects associated with this object.
 * lp_entries: Other Launchpad objects associated with this one.
 * lp_operations: The names of Launchpad methods you can call on the object.

{{{
   print sorted(bug_one.lp_attributes)
   # ['date_created', 'date_last_message', 'date_last_updated', ... 'tags', 'title']
   print sorted(bug_one.lp_operations)
   # ['addAttachment', 'addWatch', 'subscribe', 'unsubscribe']
}}}

If you need more detailed help, you can look the object up in [[http://people.ubuntu.com/~flacoste/launchpad-api-doc.html|the reference documentation]]. First, find out the type of the object.

{{{
    print repr(bug_one)
    # <bug at https://api.staging.launchpad.net/beta/bugs/1>
}}}

This is a 'bug' type object. Now you use the type of the object as an anchor into the reference documentation. To find out the capabilities of this object and what data is stored inside it, you'd visit http://people.ubuntu.com/~flacoste/launchpad-api-doc.html#bug.

As you'll see, the reference documentation still needs some work, and it's geared more towards web service hackers than launchpadlib users, but it will tell you about all of this object's attributes and all the supported operations.

 * The "Default representation" section tells you about the available attributes.

 * The "Custom POST methods" and "Custom GET methods" sections tell you about methods the object supports other than the default methods described below. The methods take whatever parameters are listed in "Request query parameters". (You can ignore the "ws.op" parameter because you're using launchpadlib; that's just the name of the method.)


= The top-level objects =

The Launchpad object has attributes corresponding to the major parts
of Launchpad. Currently there are two of these attributes,
launchpad.bugs, launchpad.people, and launchpad.me. You've already seen
launchpad.bugs. launchpad.me is an alias for your own user account.

{{{
    me = launchpad.me
    print me.name
    # This should be your user name, e.g. 'salgado'
}}}

The launchpad.people attribute gives you access to other people who use
Launchpad. This code uses launchpad.people to look up the person
with the Launchpad name "salgado".

{{{
    people = launchpad.people
    salgado = people['salgado']
    print salgado.display_name
    # Guilherme Salgado
}}}

You can search for objects in other ways. Here's another way of
finding "salgado".

{{{
    salgado = people.getByEmail(email="guilherme.salgado@canonical.com")
    print salgado.display_name
    # Guilherme Salgado
}}}

Some searches return more than one object.

{{{
    for person in people.find(text="salgado"):
        print person.name
    # agustin-salgado
    # ariel-salgado
    # axel-salgado
    # bruno-salgado
    # camilosalgado
    # ...
}}}


== Entries ==

Bugs, people, projects, team memberships, and most other objects published
through Launchpad's web service, all work pretty much the same way. We
call all these objects "entries". Each corresponds to a single piece
of data within Launchpad.

You can use the web service to discover various facts about an
entry. The launchpadlib makes the facts available as attributes of the
entry object.

'name' and 'display_name' are facts about people.

{{{
    print salgado.name
    # salgado

    print salgado.display_name
    # Guilherme Salgado
}}}

'private' and 'description' are facts about bugs.

{{{
    print bug_one.private
    # False

    print bug_one.description
    # Microsoft has a majority market share in the new desktop PC marketplace.
    # This is a bug, which Ubuntu is designed to fix.
    # ...
}}}

Every entry has a 'self_link' attribute. You can treat this as a
permanent ID for the entry. If your program needs to keep track of
Launchpad objects across multiple runs, a simple way to do it is to
keep track of the self_links.

{{{
    print salgado.self_link
    # https://api.staging.launchpad.net/beta/~salgado

    bug_one.self_link
    # https://api.staging.launchpad.net/beta/bugs/1
}}}

Some of an object's attributes are links to other entries. Bugs have
an attribute 'owner', but the owner of a bug is a person, with
attributes of its own.

{{{
    owner = bug_one.owner
    print repr(owner)
    # <person at https://api.staging.launchpad.net/beta/~sabdfl>
    print owner.name
    # sabdfl
    print owner.display_name
    # Mark Shuttleworth
}}}

If you have permission, you can change an entry's attributes and write
the data back to the server.

{{{
    me = people['my-user-name']
    me.display_name = 'A user who edits through the Launchpad web service.'
    me.lp_save()

    print people['my-user-name'].display_name
    # A user who edits through the Launchpad web service.
}}}

Having permission means not only being authorized to perform an
operation on the Launchpad side, but using a launchpadlib Credentials
object that authorizes the operation. If you've set up your
launchpadlib Credentials for read-only access, you won't be able to
change the dataset through launchpadlib.

Some entries also support special operations--see the reference
documentation for details. A bugtask entry supports an operation called "transitionToAssignee".
This operation takes a single argument called "assignee", which should be a Launchpad person.
Here it is in action.

{{{
    task = list(bug_one.bug_tasks)[0]
    old_assignee = task.assignee
    print old_assignee
    # <team at https://api.staging.launchpad.net/beta/~compscibuntu-bugs>
    task.transitionToAssignee(assignee=me)
    print task.owner.display_name
    # A user who edits through the Launchpad web service.
}}}


== Collections ==

When Launchpad groups similar entries together, we call it a
collection. You've already seen one collection: the list of people you
get back when you call launchpad.people.find.

{{{
    for person in launchpad.people.find(text="salgado"):
        print person.name
}}}

That's a collection of 'people'-type entries. You can iterate over a
collection as you can any Python list.

Some of an entry's attributes are links to related collections. Bug #1
has a number of associated bug tasks, represented as a collection of
'bug task' entries.

{{{
    tasks = bug_one.bug_tasks
    print len(tasks)
    # 17
    for task in tasks:
        print task.bug_target_display_name
    # Computer Science Ubuntu
    # Ichthux
    # JAK LINUX
    # ...
}}}

The person 'salgado' understands two languages, represented here as a
collection of two 'language' entries.

{{{
    for language in salgado.languages:
        print language.self_link
    # https://api.staging.launchpad.net/beta/+languages/en
    # https://api.staging.launchpad.net/beta/+languages/pt_BR
}}}

Because collections can be very large, it's usually a bad idea to
iterate over them. Bugs generally have a manageable
number of bug tasks, and people understand a manageable number of
languages, but Launchpad tracks over 250,000 bugs. If
you just iterate over a list, launchpadlib will just keep pulling down entries until it runs out,
which might be forever (or, realistically, until your client is banned for making too many requests).

That's why we recommend you slice Launchpad's collections into Python lists,
and operate on the lists. Here's code that prints descriptions
for the 10 most recently filed bugs.

{{{
    bugs = launchpad.bugs[:10]
    for bug in bugs:
        print bug.description
}}}

For performance reasons, we've put a couple restrictions on collection slices that don't apply to slices on regular Python lists. You can only slice from the beginning of a collection, not the end.

{{{
    launchpad.bugs[-5:]
    # *** ValueError: Collection slices must have a nonnegative start point.
}}}

And your slice needs to have a definite end point: you can't slice to the end of a list.

{{{
    bugs[10:]
    # *** ValueError: Collection slices must have a definite, nonnegative end point.

    bugs[:-5]
    # *** ValueError: Collection slices must have a definite, nonnegative end point.
}}}

On the plus side, you can include a step number with your slice, as with a normal Python list:

{{{
    every_other_bug = launchpad.bugs[0:10:2]
    len(every_other_bug)
    # 5
}}}

= Planned improvements =

launchpadlib still has deficiencies. We track bugs in the launchpadlib bug tracker
(https://bugs.launchpad.net/launchpadlib) and will be working to
improve launchpadlib throughout the limited beta.

launchpadlib

launchpadlib is an open-source Python library that lets you treat the HTTP resources published by Launchpad's web service as Python objects responding to a standard set of commands. With launchpadlib you can integrate your applications into Launchpad without knowing a lot about HTTP client programming.

This document shows how to use a Python client to read and write Launchpad's data using the launchpadlib library. It doesn't cover the HTTP requests and responses that go back and forth behind the scenes: for that, see the "hacking" document. This document also doesn't cover the full range of what's possible with Launchpad's web service: for that, see the web service reference documentation (external link forthcoming).

Launchpad's web service currently exposes the following major parts of Launchpad:

  • People and teams
  • Team memberships
  • Bugs and bugtasks

One part of Launchpad is exposed through the web service, but not supported by the current version of launchpadlib:

  • Uploaded files, such as bug attachments

As new features and capabilities are added to the web service, you'll be able to access most of them without having to update your copy of launchpadlib. You _will_ have to upgrade launchpadlib to get new client-side features (like support for uploaded files). The Launchpad team will put out an announcement whenever a server-side change means you should upgrade launchpadlib.

Installation

The launchpadlib library depends on wadllib, another open-source library released by the Launchpad team. Get a copy of the wadllib source with bzr and install it.

  $ bzr branch lp:wadllib
  $ cd wadllib
  $ sudo ./setup.py install

Then do the same for launchpadlib.

  $ bzr branch lp:launchpadlib
  $ cd launchpadlib
  $ sudo ./setup.py install

Getting started

The first step towards using Launchpad's web service is setting up credentials for your client. Run this code in a Python session:

    from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT
    launchpad = Launchpad.get_token_and_login('just testing', STAGING_SERVICE_ROOT)

The first argument is a string that identifies the web service client. We use this string to gauge client popularity and detect buggy or inefficient clients. Here, though, we're just testing.

The second argument is the URL to the web service. Here, we're using STAGING_SERVICE_ROOT, which is "https://api.staging.launchpad.net/beta/". These examples run against the staging data, so that we don't change real data when we're just trying to see how launchpadlib works.

Once you're ready to write a launchpadlib program that changes real data, you can replace STAGING_SERVICE_ROOT with EDGE_SERVICE_ROOT.

You'll see a message like this:

 The authorization page
 (https://staging.launchpad.net/+authorize-token?oauth_token=xxxxxxxxx)
 should be opening in your browser. After you have authorized this
 program to access Launchpad on your behalf you should come back here
 and press <Enter> to finish the authentication process.

Your web browser will open to a page at launchpad.net. You'll be asked to login to Launchpad, and grant some level of access to your new credentials. The level of access you choose will determine how much you can do through launchpadlib with these credentials. This lets your users delegate a portion of their Launchpad permissions to your program, without having to trust it completely.

Once you grant access, hit Enter within your Python session. You'll get back a Launchpad object. Now you can access the web service.

Here's some code that retrieves a bug from Launchpad and prints its title.

    bug_one = launchpad.bugs[1]
    print bug_one.title
    # Microsoft has a majority market share

Before proceeding further, save your credentials so that you don't have to do the get_token_and_login dance again the next time you need to access the web service.

    launchpad.credentials.save(file("some-file.txt", "w"))

Let's create a new Launchpad object from saved credentials right now.

    from launchpadlib.credentials import Credentials
    credentials = Credentials()
    credentials.load(open("some-file.txt"))
    launchpad = Launchpad(credentials, STAGING_SERVICE_ROOT)

    bug_one = launchpad.bugs[1]
    print bug_one.title
    # Microsoft has a majority market share

Getting help

If you don't know the capabilities of one of the objects you've got, you can call dir() on it. You'll see all of its fields and all the custom methods it supports. Unfortunately, you'll also see a bunch of launchpadlib-specific junk that you don't care about. That's why we've made available these four lists:

  • lp_attributes: Data fields of this object. You can read from these might be able to write to some of them.
  • lp_collections: List of launchpad objects associated with this object.
  • lp_entries: Other Launchpad objects associated with this one.
  • lp_operations: The names of Launchpad methods you can call on the object.

   print sorted(bug_one.lp_attributes)
   # ['date_created', 'date_last_message', 'date_last_updated', ... 'tags', 'title']
   print sorted(bug_one.lp_operations)
   # ['addAttachment', 'addWatch', 'subscribe', 'unsubscribe']

If you need more detailed help, you can look the object up in the reference documentation. First, find out the type of the object.

    print repr(bug_one)
    # <bug at https://api.staging.launchpad.net/beta/bugs/1>

This is a 'bug' type object. Now you use the type of the object as an anchor into the reference documentation. To find out the capabilities of this object and what data is stored inside it, you'd visit http://people.ubuntu.com/~flacoste/launchpad-api-doc.html#bug.

As you'll see, the reference documentation still needs some work, and it's geared more towards web service hackers than launchpadlib users, but it will tell you about all of this object's attributes and all the supported operations.

  • The "Default representation" section tells you about the available attributes.
  • The "Custom POST methods" and "Custom GET methods" sections tell you about methods the object supports other than the default methods described below. The methods take whatever parameters are listed in "Request query parameters". (You can ignore the "ws.op" parameter because you're using launchpadlib; that's just the name of the method.)

The top-level objects

The Launchpad object has attributes corresponding to the major parts of Launchpad. Currently there are two of these attributes, launchpad.bugs, launchpad.people, and launchpad.me. You've already seen launchpad.bugs. launchpad.me is an alias for your own user account.

    me = launchpad.me
    print me.name
    # This should be your user name, e.g. 'salgado'

The launchpad.people attribute gives you access to other people who use Launchpad. This code uses launchpad.people to look up the person with the Launchpad name "salgado".

    people = launchpad.people
    salgado = people['salgado']
    print salgado.display_name
    # Guilherme Salgado

You can search for objects in other ways. Here's another way of finding "salgado".

    salgado = people.getByEmail(email="guilherme.salgado@canonical.com")
    print salgado.display_name
    # Guilherme Salgado

Some searches return more than one object.

    for person in people.find(text="salgado"):
        print person.name
    # agustin-salgado
    # ariel-salgado
    # axel-salgado
    # bruno-salgado
    # camilosalgado
    # ...

Entries

Bugs, people, projects, team memberships, and most other objects published through Launchpad's web service, all work pretty much the same way. We call all these objects "entries". Each corresponds to a single piece of data within Launchpad.

You can use the web service to discover various facts about an entry. The launchpadlib makes the facts available as attributes of the entry object.

'name' and 'display_name' are facts about people.

    print salgado.name
    # salgado

    print salgado.display_name
    # Guilherme Salgado

'private' and 'description' are facts about bugs.

    print bug_one.private
    # False

    print bug_one.description
    # Microsoft has a majority market share in the new desktop PC marketplace.
    # This is a bug, which Ubuntu is designed to fix.
    # ...

Every entry has a 'self_link' attribute. You can treat this as a permanent ID for the entry. If your program needs to keep track of Launchpad objects across multiple runs, a simple way to do it is to keep track of the self_links.

    print salgado.self_link
    # https://api.staging.launchpad.net/beta/~salgado

    bug_one.self_link
    # https://api.staging.launchpad.net/beta/bugs/1

Some of an object's attributes are links to other entries. Bugs have an attribute 'owner', but the owner of a bug is a person, with attributes of its own.

    owner = bug_one.owner
    print repr(owner)
    # <person at https://api.staging.launchpad.net/beta/~sabdfl>
    print owner.name
    # sabdfl
    print owner.display_name
    # Mark Shuttleworth

If you have permission, you can change an entry's attributes and write the data back to the server.

    me = people['my-user-name']
    me.display_name = 'A user who edits through the Launchpad web service.'
    me.lp_save()

    print people['my-user-name'].display_name
    # A user who edits through the Launchpad web service.

Having permission means not only being authorized to perform an operation on the Launchpad side, but using a launchpadlib Credentials object that authorizes the operation. If you've set up your launchpadlib Credentials for read-only access, you won't be able to change the dataset through launchpadlib.

Some entries also support special operations--see the reference documentation for details. A bugtask entry supports an operation called "transitionToAssignee". This operation takes a single argument called "assignee", which should be a Launchpad person. Here it is in action.

    task = list(bug_one.bug_tasks)[0]
    old_assignee = task.assignee
    print old_assignee
    # <team at https://api.staging.launchpad.net/beta/~compscibuntu-bugs>
    task.transitionToAssignee(assignee=me)
    print task.owner.display_name
    # A user who edits through the Launchpad web service.

Collections

When Launchpad groups similar entries together, we call it a collection. You've already seen one collection: the list of people you get back when you call launchpad.people.find.

    for person in launchpad.people.find(text="salgado"):
        print person.name

That's a collection of 'people'-type entries. You can iterate over a collection as you can any Python list.

Some of an entry's attributes are links to related collections. Bug #1 has a number of associated bug tasks, represented as a collection of 'bug task' entries.

    tasks = bug_one.bug_tasks
    print len(tasks)
    # 17
    for task in tasks:
        print task.bug_target_display_name
    # Computer Science Ubuntu
    # Ichthux
    # JAK LINUX
    # ...

The person 'salgado' understands two languages, represented here as a collection of two 'language' entries.

    for language in salgado.languages:
        print language.self_link
    # https://api.staging.launchpad.net/beta/+languages/en
    # https://api.staging.launchpad.net/beta/+languages/pt_BR

Because collections can be very large, it's usually a bad idea to iterate over them. Bugs generally have a manageable number of bug tasks, and people understand a manageable number of languages, but Launchpad tracks over 250,000 bugs. If you just iterate over a list, launchpadlib will just keep pulling down entries until it runs out, which might be forever (or, realistically, until your client is banned for making too many requests).

That's why we recommend you slice Launchpad's collections into Python lists, and operate on the lists. Here's code that prints descriptions for the 10 most recently filed bugs.

    bugs = launchpad.bugs[:10]
    for bug in bugs:
        print bug.description    

For performance reasons, we've put a couple restrictions on collection slices that don't apply to slices on regular Python lists. You can only slice from the beginning of a collection, not the end.

    launchpad.bugs[-5:]
    # *** ValueError: Collection slices must have a nonnegative start point.

And your slice needs to have a definite end point: you can't slice to the end of a list.

    bugs[10:]
    # *** ValueError: Collection slices must have a definite, nonnegative end point.

    bugs[:-5]
    # *** ValueError: Collection slices must have a definite, nonnegative end point.

On the plus side, you can include a step number with your slice, as with a normal Python list:

    every_other_bug = launchpad.bugs[0:10:2]
    len(every_other_bug)
    # 5

Planned improvements

launchpadlib still has deficiencies. We track bugs in the launchpadlib bug tracker (https://bugs.launchpad.net/launchpadlib) and will be working to improve launchpadlib throughout the limited beta.

API/launchpadlib (last edited 2022-10-21 20:00:52 by clinton-fung)