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)