LPPythonAPI

Ubuntu Open Week - Writing Python programs using the Launchpad API - Barry Warsaw - Fri, Nov 7th, 2008

(02:02:48 PM) barry: jcastro: thanks! hello everybody
(02:03:21 PM) barry: i'm going to to try to provide some instruction on using launchpadlib to write python programs that access launchpad through its webservice
(02:04:08 PM) barry: i've never done an ubuntu open week session before so please be gentle :)
(02:04:16 PM) barry: first some background:
(02:04:52 PM) barry: as you know, there are lots of things you can do through launchpad's web interface.  you can submit and manage bugs, register branches, answer questions ,etc.
(02:05:06 PM) barry: you also have a lot of data in launchpad that you can access through the web ui
(02:05:52 PM) barry: our intent is that anything you can do through the web ui, you shoudl be able to do in a script
(02:06:17 PM) barry: we've published a REST interface to launchpad, making it a "web service"
(02:06:35 PM) barry: and we provide supported python bindings to that REST interface, to make it really easy for you to script launchpad via python
(02:06:58 PM) barry: it's feasible for third parties to write bindings for the REST interface in other languages, though we won't support it officially
(02:07:18 PM) barry: you can get the python bindings from here:
(02:07:37 PM) barry: https://launchpad.net/launchpadlib
(02:07:40 PM) barry: and...
(02:07:53 PM) barry: https://code.launchpad.net/launchpadlib
(02:08:02 PM) barry: and all the documentation is here:
(02:08:09 PM) barry: https://help.launchpad.net/API/launchpadlib
(02:08:19 PM) barry: any questions so far?
(02:09:23 PM) barry: stdin: reminds me that launchpadlib is packaged in intrepid, so it's easier to get
(02:09:27 PM) barry: stdin: thanks
(02:09:38 PM) barry: python-launchpadlib
(02:09:56 PM) barry: we haven't yet put the code in the cheeseshop, but that will happen at some point
(02:11:08 PM) barry: the api docs mentioned above provide a nice starter for scripting launchpad, but there are a couple of things to be aware of
(02:12:11 PM) barry: first, there's an open bug describing a problem scripting the staging server, so it is recommended that you test against edge for now.  be careful though because edge has real data, so try to use read-only changes to start with
(02:12:22 PM) barry: also, you will need a web browser available because launchpadlib must authenticate you through your browser
(02:12:29 PM) barry: your browser is the only client you trust :)
(02:13:37 PM) barry: also, you need to be a launchpad beta tester currently to have access to the launchpad web service
(02:14:20 PM) barry: when you go through the tutorial on the docs page, you will be asked to grant your application various levels of authorization
(02:14:40 PM) b33r_ is now known as b33r
(02:15:37 PM) barry: does anybody have any questions?
(02:16:34 PM) barry: i should also mention that full launchpad functionality is not yet exposed in the web service.  you can do a lot of stuff right now and over time we'll be fleshing out the missing pieces
(02:16:49 PM) barry: our intent is that you should be able to access any data you have permission to in the web ui
(02:16:59 PM) barry: and perform any tasks you have permission to also
(02:17:47 PM) barry: i highly recommend reading the tutorial mentioned above, it will give you a great start into scripting launchpad via python
(02:22:22 PM) barry: alright, so let's go through a simple example
(02:23:01 PM) barry: i'm assuming you already have launchpadlib installed.  if not, and you're having problems with that, let me know
(02:23:42 PM) barry: note that you'll also need wadllib installed.  i would think the intrepid package dtrt, but if you're installing from source, launchpadlib's setup.py doesn't yet depend on wadllib
(02:24:35 PM) barry: you need to start by authenticating to launchpad, through your browser
(02:24:54 PM) barry: make sure your browser is open and that you're logged into launchpad
(02:25:01 PM) barry: then fire up your python interpreter
(02:25:16 PM) barry: start by importing some useful objects:
(02:25:23 PM) barry: >>> from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT
(02:25:58 PM) barry: generally, you will want to set up caching, as this makes interacting with launchpad much faster.  to do this you need to set up a cache directory
(02:26:18 PM) barry: in the following i'm going to use /tmp/cache but you can use anything you have write permission to
(02:26:37 PM) barry: the next step is to authenticate to launchpad (again, note that i'm using edge here)
(02:26:44 PM) barry: launchpad = Launchpad.get_token_and_login('just testing', EDGE_SERVICE_ROOT, '/tmp/cache')
(02:27:08 PM) barry: this creates an aplication for you called "just testing"
(02:27:22 PM) barry: it sets your client to talk to edge and to cache data in /tmp/cache
(02:27:43 PM) barry: you'll now see a message at stdout and your python will be waiting for you to complete the task
(02:28:00 PM) barry: you should also notice your web browser has opened an authentication page
(02:28:13 PM) barry: it's at this point that you are going to grant the appropriate access to  your launchpadlib application
(02:28:31 PM) barry: i   recommend for now to select read-only data
(02:29:02 PM) barry: any questions or problems so far?
(02:29:56 PM) barry: great
(02:30:16 PM) barry: once you've given access to your application, go back to your python prompt and hit return
(02:30:27 PM) barry: your python client is now primed and ready to talk to launchpad
(02:31:03 PM) barry: the 'launchpad' object is your door into the vast array of objects and actions you can take
(02:31:15 PM) barry: you can think of it as the root of a big tree of resources
(02:31:25 PM) barry: i.e. web resources
(02:31:40 PM) barry: 'launchpad' has a number of top level objects directly under it
(02:32:04 PM) barry: and through it you can access bugs, people, etc
(02:32:25 PM) barry: for example, the first thing you can do is view the person object that represents yourself:
(02:32:32 PM) barry: >>> launchpad.me
(02:32:32 PM) barry: <person at https://api.edge.launchpad.net/beta/~barry>
(02:32:56 PM) barry: it's through 'launchpad.me' that you can script changes to your presence in lp
(02:33:22 PM) barry: for example, if i wanted to see my own display name, i could do
(02:33:40 PM) barry: >>> launchpad.me.display_name
(02:33:40 PM) barry: u'Barry Warsaw'
(02:33:50 PM) barry: note that the value of this attribute is a python unicode
(02:34:07 PM) barry: that's important to keep in mind for those of you with non-ascii characters in your name!
(02:34:37 PM) barry: i can find out if i'm a team <wink>
(02:34:41 PM) barry: >>> launchpad.me.is_team
(02:34:41 PM) barry: False
(02:34:56 PM) barry: and i can see my own timezone
(02:35:01 PM) barry: >>> launchpad.me.time_zone
(02:35:01 PM) barry: u'America/New_York'
(02:37:46 PM) barry: one nice thing you can do is use python's dir() function to see all the things you can find out about an object
(02:37:59 PM) barry: >>> dir(launchpad.me)
(02:37:59 PM) barry: ['FIND_ATTRIBUTES', 'FIND_COLLECTIONS', 'FIND_ENTRIES', 'JSON_MEDIA_TYPE', '__class__', '__delattr__', '__dict__', '__doc__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__members__', '__methods__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_create_bound_resource', '_dirty_attributes', '_ensure_representation', '_get_external_param_name', '_get_parameter
(02:37:59 PM) barry: _names', '_root', '_transform_resources_to_links', '_wadl_resource', 'acceptInvitationToBeMemberOf', 'addMember', 'admins', 'confirmed_email_addresses', 'date_created', 'deactivated_members', 'declineInvitationToBeMemberOf', 'display_name', 'expired_members', 'getMembersByStatus', 'hide_email_addresses', 'homepage_content', 'invited_members', 'irc_nicknames', 'is_team', 'is_valid', 'jabber_ids', 'join', 'karma', 'languages', 'latitude',
(02:38:04 PM) barry:  'leave', 'longitude', 'lp_attributes', 'lp_collections', 'lp_entries', 'lp_get_named_operation', 'lp_get_parameter', 'lp_has_parameter', 'lp_operations', 'lp_refresh', 'lp_save', 'mailing_list_auto_subscribe_policy', 'members', 'members_details', 'memberships_details', 'mugshot', 'name', 'open_membership_invitations', 'participants', 'preferred_email_address', 'proposed_members', 'resource_type_link', 'self_link', 'setLocation', 'setLo
(02:38:09 PM) barry: cationVisibility', 'sub_teams', 'super_teams', 'team_owner', 'time_zone', 'visibility', 'wiki_names']
(02:38:12 PM) barry: not all of those are of interest to you though
(02:38:47 PM) barry: method with names starting with an underscore are private
(02:39:13 PM) barry: methods that start with lp_ are special in the sense that they are actions you can take on client-side objects
(02:39:22 PM) barry: they don't correspond to actions in launchpad
(02:39:41 PM) barry: for example, if you make a change to an object, you would need to call lp_save() on it to "push" those changes back to launchpad
(02:41:02 PM) barry: let's say you wanted to get some information on a different user, how would you do that?
(02:41:28 PM) barry: well, there's a 'people' object at the top level, and we can use that to access people by their launchpad id
(02:41:32 PM) barry: e.g.
(02:41:38 PM) barry: >>> launchpad.people['salgado']
(02:41:38 PM) barry: <person at https://api.edge.launchpad.net/beta/~salgado>
(02:42:04 PM) barry: >>> salgado = launchpad.people['salgado']
(02:42:04 PM) barry: >>> salgado.display_name
(02:42:04 PM) barry: u'Guilherme Salgado'
(02:42:26 PM) barry: we can also get people by their email addresses, through a different interface
(02:43:21 PM) barry: >>> salgado = launchpad.people.getByEmail(email='guilherme.salgado@canonical.com')
(02:43:21 PM) barry: >>> salgado.display_name
(02:43:21 PM) barry: u'Guilherme Salgado'
(02:43:29 PM) barry: something important to note here...
(02:43:44 PM) barry: you're used to providing positional arguments in "normal" python
(02:44:05 PM) barry: so by looking at this example, you might ask, why did you type the argument name in the above call?
(02:44:12 PM) barry: (e.g. the 'email=' part)
(02:47:19 PM) barry: the answer is that because of the peculiarities of our wadl definition, the python client side of the rest api doesn't understand positional arguments
(02:47:23 PM) barry: so all method arguments are keyword arguments and must be entered explicitly
(02:48:04 PM) barry: we may fix this some day, but for now, it's something you need to keep in mind
(02:48:09 PM) barry: any questions up 'til now?
(02:48:25 PM) barry: ok
(02:48:26 PM) barry: one other way to find people
(02:49:05 PM) barry: you can actually do a full text search, so if you only know part of a user's name, you can do it like this:
(02:50:03 PM) barry: >>> for person in launchpad.people.find(text='salgado'):
(02:50:03 PM) barry: ...   print person.display_name
(02:50:03 PM) barry: ...
(02:50:03 PM) barry: abel
(02:50:03 PM) barry: agustincsw
(02:50:03 PM) barry: Ariel_salgado
(02:50:03 PM) barry: axlsal
(02:50:03 PM) barry: Bruno Fecchio Salgado
(02:50:03 PM) barry: Camilo Salgado
(02:50:03 PM) barry: and so on...
(02:50:31 PM) barry: similar to the top level object 'people', you have access to bugs, like so:
(02:50:34 PM) barry: >>> bug1 = launchpad.bugs[1]
(02:50:34 PM) barry: >>> bug1.title
(02:50:34 PM) barry: u'Microsoft has a majority market share'
(02:50:38 PM) barry: note that bugs are accessible via their bug id
(02:50:45 PM) barry: currently, the only two top-level objects available are bugs and people
(02:51:50 PM) barry: a lot of the introspective power of python is available to you, so if you're pretty comfortable with python and launchpad, you should be able to build fairly sophisticated applications
(02:52:39 PM) barry: as i mentioned the dir() function above gives you too much information you don't care about, you can use one of the other 'launchpad' objects instead
(02:52:47 PM) barry: e.g. to find out the things you can do to a person, you can try this:
(02:52:57 PM) barry: >>> launchpad.me.lp_operations
(02:52:57 PM) barry: ['leave', 'setLocationVisibility', 'addMember', 'declineInvitationToBeMemberOf', 'join', 'getMembersByStatus', 'setLocation', 'acceptInvitationToBeMemberOf']
(02:53:38 PM) barry: unfortunately, python's built-in help() function is currently not very useful
(02:54:22 PM) barry: a couple of other interesting tidbits
(02:54:47 PM) barry: objects like launchpad.me are called 'entities' and things like launchpad.people are called 'collections'
(02:55:16 PM) barry: thik of entities as the leaves of the big object tree, though of course entities can be linked to other entities or collections
(02:55:59 PM) barry: whenever you make a change to an entity's properties, you need to call 'entity.lp_save()' to save them on launchpad
(02:56:12 PM) barry: otherwise the changes only occur locally and will be lost when you quit your client
(02:56:43 PM) barry: there's also something called a 'hosted file', which you can mostly think of as a binary blob
(02:56:50 PM) barry: your mugshot is that way for example
(02:57:10 PM) barry: to read the data of a hosted file, you need to open it and read it.
(02:57:18 PM) barry: hosted files also have a content_type
(02:57:20 PM) barry: so:
(02:58:16 PM) barry: >>> f = launchpad.me.mugshot.open()
(02:58:16 PM) barry: >>> data = f.read()
(02:58:16 PM) barry: >>> f.content_type
(02:58:16 PM) barry: 'image/jpeg'
(02:58:26 PM) barry: data would now be the image data of your mugshot
(02:58:46 PM) barry: well, i'm just about out of time so let me just repost the documentation link
(02:58:52 PM) barry: https://help.launchpad.net/API/launchpadlib
(02:59:19 PM) barry: and i encourage you to submit enhancement requests and bugs, and in general test out the launchpadlib to script your applications
(02:59:33 PM) barry: i think that's it for me, thanks for your time!

MeetingLogs/openweekintrepid/LPPythonAPI (last edited 2008-11-07 20:00:00 by pool-70-16-60-167)