CINXE.COM

Diff for "API/launchpadlib" - Launchpad Help

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta name="robots" content="noindex,nofollow"> <title>Diff for &quot;API/launchpadlib&quot; - Launchpad Help</title> <script type="text/javascript" src="/moin_static198/common/js/common.js"></script> <script type="text/javascript"> <!-- var search_hint = "Search"; //--> </script> <link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="/moin_static198/lp20/css/common.css"> <link rel="stylesheet" type="text/css" charset="utf-8" media="screen" href="/moin_static198/lp20/css/screen.css"> <link rel="stylesheet" type="text/css" charset="utf-8" media="print" href="/moin_static198/lp20/css/print.css"> <link rel="stylesheet" type="text/css" charset="utf-8" media="projection" href="/moin_static198/lp20/css/projection.css"> <!-- css only for MS IE6/IE7 browsers --> <!--[if lt IE 8]> <link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="/moin_static198/lp20/css/msie.css"> <![endif]--> <link rel="alternate" title="Launchpad Help: API/launchpadlib" href="/API/launchpadlib?diffs=1&amp;show_att=1&amp;action=rss_rc&amp;unique=0&amp;page=API%2Flaunchpadlib&amp;ddiffs=1" type="application/rss+xml"> <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-12833497-4']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> <link rel="Start" href="/FrontPage"> <link rel="Alternate" title="Wiki Markup" href="/API/launchpadlib?action=raw"> <link rel="Alternate" media="print" title="Print View" href="/API/launchpadlib?action=print"> <link rel="Up" href="/API"> <link rel="Search" href="/FindPage"> <link rel="Index" href="/TitleIndex"> <link rel="Glossary" href="/WordIndex"> <link rel="Help" href="/HelpOnFormatting"> </head> <body lang="en" dir="ltr"> <div id="header"> <h1> <a href="https://help.launchpad.net/" class="header-link"> <img src=' /moin_static198/lp20/img/logo.png ' /> launchpad <strong>help</strong></a> </h1> <div id="finder"> <div class="fixbox"> <form id="searchform" method="get" action=""> <input type="hidden" name="action" value="fullsearch"> <input type="hidden" name="context" value="180"> <input id="searchinput" type="text" name="value" value="" size="20" onfocus="searchFocus(this)" onblur="searchBlur(this)" onkeyup="searchChange(this)" onchange="searchChange(this)" alt="Search"> </form> </div> <ul class="editbar"><li><span class="disabled">Immutable Page</span></li><li><a class="nbinfo" href="/API/launchpadlib?action=info" rel="nofollow">Info</a></li><li><a class="nbattachments" href="/API/launchpadlib?action=AttachFile" rel="nofollow">Attachments</a></li><li> <form class="actionsmenu" method="GET" action="/API/launchpadlib"> <div> <label>More Actions:</label> <select name="action" onchange="if ((this.selectedIndex != 0) && (this.options[this.selectedIndex].disabled == false)) { this.form.submit(); } this.selectedIndex = 0;"> <option value="raw">Raw Text</option> <option value="print">Print View</option> <option value="RenderAsDocbook">Render as Docbook</option> <option value="show" disabled class="disabled">Delete Cache</option> <option value="show" disabled class="disabled">------------------------</option> <option value="SpellCheck">Check Spelling</option> <option value="LikePages">Like Pages</option> <option value="LocalSiteMap">Local Site Map</option> <option value="show" disabled class="disabled">------------------------</option> <option value="RenamePage" disabled class="disabled">Rename Page</option> <option value="DeletePage" disabled class="disabled">Delete Page</option> <option value="show" disabled class="disabled">------------------------</option> <option value="show" disabled class="disabled">Subscribe User</option> <option value="show" disabled class="disabled">------------------------</option> <option value="show" disabled class="disabled">Remove Spam</option> <option value="show" disabled class="disabled">Revert to this revision</option> <option value="PackagePages">Package Pages</option> <option value="SyncPages">Sync Pages</option> <option value="show" disabled class="disabled">------------------------</option> <option value="Load">Load</option> <option value="Save">Save</option> <option value="SlideShow">SlideShow</option> </select> <input type="submit" value="Do"> </div> <script type="text/javascript"> <!--// Init menu actionsMenuInit('More Actions:'); //--> </script> </form> </li></ul> </div> </div> <div id="locationline"> </div> <div id="sepbar">&nbsp;</div> <div id="login"> <div class="fl"> <h1 class="maintitle"> Diff for &quot;API/launchpadlib&quot; </h1> </div> <div class="fr"> Not logged in - <a href="/?action=login">Log In / Register</a> </div> </div> <div id="pageline"><hr style="display:none;"></div> <div class="message"> </div> <div id="page" lang="en" dir="ltr"> <div id="content"> <span class="diff-header">Differences between revisions 83 and 84</span> <table class="diff"> <tr> <td style="border:0;"> <form action="/API/launchpadlib" method="get"> <div style="text-align:left"> <input name="action" value="diff" type="hidden"> <input name="rev1" value="82" type="hidden"> <input name="rev2" value="83" type="hidden"> <input value="Previous change" type="submit"> </div> </form> </td> <td style="border:0"> </td> <td style="border:0;"> <form action="/API/launchpadlib" method="get"> <div style="text-align:right"> <input name="action" value="diff" type="hidden"> <input name="rev1" value="84" type="hidden"> <input name="rev2" value="84" type="hidden"> <input value="Next change" type="submit" disabled="disabled"> </div> </form> </td> </tr> </table> <table class="diff"> <tr><td class="diff-info"> <div class="diff-info diff-info-header"><a class="diff-nav-link diff-first-link diff-old-rev" href="/API/launchpadlib?action=diff&amp;rev1=1&amp;rev2=84" title="Diff with oldest revision in left pane">⇤</a> <a class="diff-nav-link diff-prev-link diff-old-rev" href="/API/launchpadlib?action=diff&amp;rev1=82&amp;rev2=84" title="Diff with older revision in left pane">←</a> Revision 83 as of 2024-06-03 10:19:03 <span class="diff-no-nav-link diff-next-link diff-old-rev" title="Can't change to revision newer than in right pane">→</span> </div> <div class="diff-info diff-info-rev-size"><span class="diff-info-caption">Size:</span> <span class="diff-info-value">25247</span></div> <div class="diff-info diff-info-rev-author"><span class="diff-info-caption">Editor:</span> <span class="diff-info-value"><span title="ruinedyourlife @ 2a01:cb19:85b4:1d00:fdb7:1617:d252:f9fd[2a01:cb19:85b4:1d00:fdb7:1617:d252:f9fd]"><a class="interwiki" href="https://launchpad.net/~ruinedyourlife" title="ruinedyourlife @ 2a01:cb19:85b4:1d00:fdb7:1617:d252:f9fd[2a01:cb19:85b4:1d00:fdb7:1617:d252:f9fd]">ruinedyourlife</a></span></span></div> <div class="diff-info diff-info-rev-comment"><span class="diff-info-caption">Comment:</span> <span class="diff-info-value">move to api/examples</span></div> </td><td class="diff-info"> <div class="diff-info diff-info-header"> <span class="diff-no-nav-link diff-prev-link diff-new-rev" title="Can't change to revision older than revision in left pane">←</span> Revision 84 as of 2024-07-04 12:12:36 <span class="diff-no-nav-link diff-next-link diff-new-rev" title="No newer revision available for diff">→</span> <span class="diff-no-nav-link diff-last-link diff-old-rev" title="No newer revision available for diff">⇥</span></div> <div class="diff-info diff-info-rev-size"><span class="diff-info-caption">Size:</span> <span class="diff-info-value">25254</span></div> <div class="diff-info diff-info-rev-author"><span class="diff-info-caption">Editor:</span> <span class="diff-info-value"><span title="jugmac00 @ p200300d30f1d3c0066008dd8781c6932.dip0.t-ipconnect.de[2003:d3:f1d:3c00:6600:8dd8:781c:6932]"><a class="interwiki" href="https://launchpad.net/~jugmac00" title="jugmac00 @ p200300d30f1d3c0066008dd8781c6932.dip0.t-ipconnect.de[2003:d3:f1d:3c00:6600:8dd8:781c:6932]">jugmac00</a></span></span></div> <div class="diff-info diff-info-rev-comment"><span class="diff-info-caption">Comment:</span> <span class="diff-info-value">fix broken link</span></div> </td></tr> <tr> <td class="diff-removed"><span>Deletions are marked like this.</span></td> <td class="diff-added"><span>Additions are marked like this.</span></td> </tr> <tr class="diff-title"> <td><a href="#line-208">Line 208</a>:</td> <td><a href="#line-208">Line 208</a>:</td> </tr> <tr> <td class="diff-removed">and what data is stored inside it, you'd visit https://launchpad.net/<span>+api</span>d<span>oc</span>#bug.</td> <td class="diff-added">and what data is stored inside it, you'd visit https://<span>api.</span>launchpad.net/d<span>evel.html</span>#bug.</td> </tr> </table> <div dir="ltr" id="content-below-diff" lang="en"><span class="anchor" id="top"></span> <span class="anchor" id="line-1"></span><p class="line867"><small><a href="/FrontPage">Launchpad Help</a> &gt; <a href="/API">API</a> &gt; Examples </small> <span class="anchor" id="line-2"></span><span class="anchor" id="line-3"></span><div><table style="&amp;quot; float:right; font-size: 0.9em; width:40%; background:#F1F1ED; margin: 0 0 1em 1em; &amp;quot;"><tbody><tr> <td style="&amp;quot; padding:0.5em; &amp;quot;"><p class="line891"><div class="table-of-contents"><p class="table-of-contents-heading">Contents<ol><li> <a href="#launchpadlib">launchpadlib</a></li><li> <a href="#Installation">Installation</a><ol><li> <a href="#The_launchpadlib_in_Ubuntu_.28easy_to_install.29">The launchpadlib in Ubuntu (easy to install)</a></li><li> <a href="#launchpad_using_pip">launchpad using pip</a></li></ol></li><li> <a href="#Getting_started">Getting started</a><ol><li> <a href="#Anonymous_access">Anonymous access</a></li><li> <a href="#Authenticated_access">Authenticated access</a></li><li> <a href="#Authenticated_access_for_website_integration">Authenticated access for website integration</a></li></ol></li><li> <a href="#Getting_help">Getting help</a></li><li> <a href="#The_top-level_objects">The top-level objects</a></li><li> <a href="#Entries">Entries</a><ol><li> <a href="#self_link:_the_permanent_ID">self_link: the permanent ID</a></li><li> <a href="#web_link:_the_link_to_the_Launchpad_website">web_link: the link to the Launchpad website</a></li><li> <a href="#Named_operations">Named operations</a></li></ol></li><li> <a href="#Errors">Errors</a></li><li> <a href="#Collections">Collections</a></li><li> <a href="#Hosted_files">Hosted files</a></li><li> <a href="#Persistent_references_to_Launchpad_objects">Persistent references to Launchpad objects</a></li><li> <a href="#Three_things_to_make_your_client_faster">Three things to make your client faster</a></li><li> <a href="#Planned_improvements">Planned improvements</a></li><li> <a href="#See_also">See also</a></li><li> <a href="#launchpadlib_API_compatibility">launchpadlib API compatibility</a><ol><li> <a href="#A.3E.3D_1.5.5_.28.3E.3D_Ubuntu_Lucid_Lynx.29">&gt;= 1.5.5 (&gt;= Ubuntu Lucid Lynx)</a></li><li> <a href="#A1.8.0_.28no_Ubuntu_release.29">1.8.0 (no Ubuntu release)</a></li><li> <a href="#A.3E.3D_1.9.0_.28.3E.3D_Ubuntu_Natty_Narwhal.29">&gt;= 1.9.0 (&gt;= Ubuntu Natty Narwhal)</a></li></ol></li></ol></div></td> </tr> </tbody></table></div><span class="anchor" id="line-4"></span><span class="anchor" id="line-5"></span><p class="line867"> <h1 id="launchpadlib">launchpadlib</h1> <span class="anchor" id="line-6"></span><span class="anchor" id="line-7"></span><ul><li style="list-style-type:none"><p class="line891"><a class="https" href="https://launchpad.net/launchpadlib">https://launchpad.net/launchpadlib</a> <span class="anchor" id="line-8"></span><span class="anchor" id="line-9"></span></li></ul><p class="line874">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. <span class="anchor" id="line-10"></span><span class="anchor" id="line-11"></span><p class="line874">This document shows how to use a Python client to read and write <span class="anchor" id="line-12"></span>Launchpad's data using the launchpadlib library. It doesn't cover the <span class="anchor" id="line-13"></span>HTTP requests and responses that go back and forth behind the <span class="anchor" id="line-14"></span>scenes: for that, see <a href="/API/Hacking">the &quot;hacking&quot; document</a>. This document also doesn't cover the full range of what's possible <span class="anchor" id="line-15"></span>with Launchpad's web service: for that, see the <a class="http" href="http://launchpad.net/+apidoc/">web service reference documentation</a>. Check out the <a href="/API/Examples">API examples page</a> if you would like to see more sample code. <span class="anchor" id="line-16"></span><span class="anchor" id="line-17"></span><p class="line874">Launchpad's web service currently exposes the following major parts of Launchpad: <span class="anchor" id="line-18"></span><span class="anchor" id="line-19"></span><ul><li>People and teams <span class="anchor" id="line-20"></span></li><li>Team memberships <span class="anchor" id="line-21"></span></li><li>Bugs and bugtasks <span class="anchor" id="line-22"></span></li><li>The project registry <span class="anchor" id="line-23"></span></li><li>Hosted files, such as bug attachments and mugshots. <span class="anchor" id="line-24"></span><span class="anchor" id="line-25"></span></li></ul><p class="line862">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 <em>will</em> 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. <span class="anchor" id="line-26"></span><span class="anchor" id="line-27"></span><p class="line867"> <h1 id="Installation">Installation</h1> <span class="anchor" id="line-28"></span><span class="anchor" id="line-29"></span><p class="line867"> <h2 id="The_launchpadlib_in_Ubuntu_.28easy_to_install.29">The launchpadlib in Ubuntu (easy to install)</h2> <span class="anchor" id="line-30"></span><span class="anchor" id="line-31"></span><p class="line874">If you have the latest version of Ubuntu then to install the launchpadlib available in the Ubuntu repositories, open a terminal and run the command: <span class="anchor" id="line-32"></span><span class="anchor" id="line-33"></span><p class="line867"><span class="anchor" id="line-34"></span><span class="anchor" id="line-35"></span><pre><span class="anchor" id="line-1"></span> $ sudo apt-get install python3-launchpadlib</pre><span class="anchor" id="line-36"></span><span class="anchor" id="line-37"></span><p class="line874">And you are done! <span class="anchor" id="line-38"></span><span class="anchor" id="line-39"></span><p class="line874">If you have an older version of Ubuntu then parts of the instructions below may not work with the version from the repositories but you should be able to install the latest version of launchpadlib manually. <span class="anchor" id="line-40"></span><span class="anchor" id="line-41"></span><p class="line867"> <h2 id="launchpad_using_pip">launchpad using pip</h2> <span class="anchor" id="line-42"></span><span class="anchor" id="line-43"></span><p class="line874">On any platform with a working Python and pip, you should be able to say: <span class="anchor" id="line-44"></span><span class="anchor" id="line-45"></span><p class="line867"><span class="anchor" id="line-46"></span><span class="anchor" id="line-47"></span><pre><span class="anchor" id="line-1-1"></span> pip install launchpadlib</pre><p class="line874"> <span class="anchor" id="line-48"></span><span class="anchor" id="line-49"></span><p class="line867"> <h1 id="Getting_started">Getting started</h1> <span class="anchor" id="line-50"></span><span class="anchor" id="line-51"></span><p class="line874">The first step towards using Launchpad's web service is to choose a cache directory. The documents you retrieve from Launchpad will be stored here, which will save you a lot of time. Run this code in a Python session, substituting an appropriate directory on your computer: <span class="anchor" id="line-52"></span><span class="anchor" id="line-53"></span><p class="line867"><span class="anchor" id="line-54"></span><span class="anchor" id="line-55"></span><pre><span class="anchor" id="line-1-2"></span> cachedir = &quot;/home/me/.launchpadlib/cache/&quot;</pre><span class="anchor" id="line-56"></span><span class="anchor" id="line-57"></span><p class="line874">The next step is to set up credentials for your client. For quick read-only access to Launchpad data, you can get anonymous access. Otherwise, you'll need to authenticate with Launchpad using OAuth. <span class="anchor" id="line-58"></span><span class="anchor" id="line-59"></span><p class="line867"> <h2 id="Anonymous_access">Anonymous access</h2> <span class="anchor" id="line-60"></span><span class="anchor" id="line-61"></span><p class="line862">The <tt class="backtick">Launchpad.login_anonymously()</tt> method will give you automatic read-only access to public Launchpad data. <span class="anchor" id="line-62"></span><span class="anchor" id="line-63"></span><p class="line867"><span class="anchor" id="line-64"></span><span class="anchor" id="line-65"></span><span class="anchor" id="line-66"></span><pre><span class="anchor" id="line-1-3"></span> from launchpadlib.launchpad import Launchpad <span class="anchor" id="line-2"></span> launchpad = Launchpad.login_anonymously('just testing', 'production', cachedir, version='devel')</pre><span class="anchor" id="line-67"></span><span class="anchor" id="line-68"></span><p class="line862">The first argument to <tt class="backtick">Launchpad.login_anonymously()</tt> 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. <span class="anchor" id="line-69"></span><span class="anchor" id="line-70"></span><p class="line862">The second argument tells launchpadlib which Launchpad instance to run against. Here, we're using <tt class="backtick">production</tt>, which is mapped to the web service root on the production Launchpad server: &quot;<a class="https" href="https://api.launchpad.net/">https://api.launchpad.net/</a>&quot;. Anonymous access cannot change the Launchpad dataset, so there's no concern about a bad test program accidentally overwriting data. (If you want to play it safe, you could use 'staging' instead - though staging is sometimes down for extended periods.) <span class="anchor" id="line-71"></span><span class="anchor" id="line-72"></span><p class="line862">The <tt class="backtick">version</tt> argument specifies the API version to use. For historical reasons the default is <tt class="backtick">'1.0'</tt>, and you may want to use this in certain special circumstances, but in most cases you should use <tt class="backtick">'devel'</tt> so that you get a reasonably complete and current interface. <span class="anchor" id="line-73"></span><span class="anchor" id="line-74"></span><p class="line862">The <tt class="backtick">login_anonymously()</tt> method automatically negotiates a read-only credential with Launchpad. You can use your <tt class="backtick">Launchpad</tt> object right away. <span class="anchor" id="line-75"></span><span class="anchor" id="line-76"></span><p class="line867"><span class="anchor" id="line-77"></span><span class="anchor" id="line-78"></span><span class="anchor" id="line-79"></span><span class="anchor" id="line-80"></span><pre><span class="anchor" id="line-1-4"></span> bug_one = launchpad.bugs[1] <span class="anchor" id="line-2-1"></span> print(bug_one.title) <span class="anchor" id="line-3"></span> # Microsoft has a majority market share</pre><span class="anchor" id="line-81"></span><span class="anchor" id="line-82"></span><p class="line862">You'll get an error if you try to modify the dataset, access private data, or access objects like <tt class="backtick">launchpad.me</tt> which assume a particular user is logged in. <span class="anchor" id="line-83"></span><span class="anchor" id="line-84"></span><p class="line862">Note that <tt class="backtick">login_anonymously()</tt> is only available in launchpadlib starting in version 1.5.4. <span class="anchor" id="line-85"></span><span class="anchor" id="line-86"></span><p class="line867"> <h2 id="Authenticated_access">Authenticated access</h2> <span class="anchor" id="line-87"></span><span class="anchor" id="line-88"></span><p class="line874">To get read-write access to Launchpad, or to see a user's private <span class="anchor" id="line-89"></span>data, you'll need to get an OAuth credential for that user. If you're <span class="anchor" id="line-90"></span>writing an application that the user will run on their own computer, <span class="anchor" id="line-91"></span>this is easy: just call the <tt class="backtick">Launchpad.login_with()</tt> method. <span class="anchor" id="line-92"></span><span class="anchor" id="line-93"></span><p class="line874">This method takes two important arguments: the name of your <span class="anchor" id="line-94"></span>application, and the name of the Launchpad server you want to run <span class="anchor" id="line-95"></span>against. The default server name is 'staging', so that you don't <span class="anchor" id="line-96"></span>destroy data by accident while developing. When you do a release, you <span class="anchor" id="line-97"></span>can change this to 'production'. <span class="anchor" id="line-98"></span><span class="anchor" id="line-99"></span><p class="line867"><span class="anchor" id="line-100"></span><span class="anchor" id="line-101"></span><span class="anchor" id="line-102"></span><pre><span class="anchor" id="line-1-5"></span> from launchpadlib.launchpad import Launchpad <span class="anchor" id="line-2-2"></span> launchpad = Launchpad.login_with('My Application', 'staging', version='devel')</pre><span class="anchor" id="line-103"></span><span class="anchor" id="line-104"></span><span class="anchor" id="line-105"></span><p class="line867"><em>If this code complains that 'staging' isn't a URL, then you're not running the most up-to-date launchpadlib. You can replace 'staging' with <tt class="backtick">launchpadlib.launchpad.STAGING_SERVICE_ROOT</tt> to make it work in Ubuntu 9.10's launchpadlib.</em> <span class="anchor" id="line-106"></span><span class="anchor" id="line-107"></span><p class="line874">If you have an existing desktop-wide Launchpad credential, <span class="anchor" id="line-108"></span>launchpadlib will find it and use it. If there's no existing desktop <span class="anchor" id="line-109"></span>credential (because you've never used a launchpadlib application on <span class="anchor" id="line-110"></span>this computer, or because you had a credential that expired), <span class="anchor" id="line-111"></span>launchpadlib will guide you through authorizing a new credential, as <span class="anchor" id="line-112"></span>seen <a href="/API/ThirdPartyIntegration">here</a>. <span class="anchor" id="line-113"></span><span class="anchor" id="line-114"></span><p class="line862">There's one other important argument to <tt class="backtick">login_with()</tt>. You can pass <span class="anchor" id="line-115"></span>in a callback function as <tt class="backtick">credential_save_failed</tt>. That function will <span class="anchor" id="line-116"></span>be invoked if a desktop credential can't be created--either because <span class="anchor" id="line-117"></span>the end-user refused to perform the authorization, or because there <span class="anchor" id="line-118"></span>was a problem storing the credential after authorization. <span class="anchor" id="line-119"></span><span class="anchor" id="line-120"></span><p class="line867"><span class="anchor" id="line-121"></span><span class="anchor" id="line-122"></span><span class="anchor" id="line-123"></span><span class="anchor" id="line-124"></span><span class="anchor" id="line-125"></span><span class="anchor" id="line-126"></span><span class="anchor" id="line-127"></span><span class="anchor" id="line-128"></span><span class="anchor" id="line-129"></span><span class="anchor" id="line-130"></span><pre><span class="anchor" id="line-1-6"></span> import sys <span class="anchor" id="line-2-3"></span> from launchpadlib.launchpad import Launchpad <span class="anchor" id="line-3-1"></span> <span class="anchor" id="line-4"></span> def no_credential(): <span class="anchor" id="line-5"></span> print(&quot;Can't proceed without Launchpad credential.&quot;) <span class="anchor" id="line-6"></span> sys.exit() <span class="anchor" id="line-7"></span> <span class="anchor" id="line-8"></span> launchpad = Launchpad.login_with( <span class="anchor" id="line-9"></span> 'My Application', 'staging', credential_save_failed=no_credential, version='devel')</pre><span class="anchor" id="line-131"></span><span class="anchor" id="line-132"></span><p class="line867"> <h2 id="Authenticated_access_for_website_integration">Authenticated access for website integration</h2> <span class="anchor" id="line-133"></span><span class="anchor" id="line-134"></span><p class="line874">Things are a little more difficult if you want to integrate <span class="anchor" id="line-135"></span>Launchpad's functionality into your own website. You can't call <span class="anchor" id="line-136"></span><tt class="backtick">Launchpad.login_with()</tt>, because that will open up a web browser on <span class="anchor" id="line-137"></span>your webserver--not on your user's computer. <span class="anchor" id="line-138"></span><span class="anchor" id="line-139"></span><p class="line862">Instead, you create a <tt class="backtick">Credentials</tt> object identifying your website <span class="anchor" id="line-140"></span>and call <tt class="backtick">get_request_token()</tt> to ask Launchpad for a request <span class="anchor" id="line-141"></span>token. Be sure to pass in the name of the Launchpad server you want to <span class="anchor" id="line-142"></span>use (probably &quot;production&quot; as <tt class="backtick">web_root</tt>. <span class="anchor" id="line-143"></span><span class="anchor" id="line-144"></span><p class="line867"><span class="anchor" id="line-145"></span><span class="anchor" id="line-146"></span><span class="anchor" id="line-147"></span><span class="anchor" id="line-148"></span><pre><span class="anchor" id="line-1-7"></span> from launchpadlib.credentials import Credentials <span class="anchor" id="line-2-4"></span> credentials = Credentials(&quot;my website&quot;) <span class="anchor" id="line-3-2"></span> request_token_info = credentials.get_request_token(web_root=&quot;production&quot;)</pre><span class="anchor" id="line-149"></span><span class="anchor" id="line-150"></span><p class="line874">You'll get back a string that looks like <span class="anchor" id="line-151"></span>'<a class="https" href="https://launchpad.net/+authorize-token?oauth_token=">https://launchpad.net/+authorize-token?oauth_token=</a>...' This is the <span class="anchor" id="line-152"></span>URL your end-user needs to visit in order to authorize your token. <span class="anchor" id="line-153"></span><span class="anchor" id="line-154"></span><p class="line874">At this point, you should redirect your user to that URL. Then, start <span class="anchor" id="line-155"></span>periodically calling <tt class="backtick">exchange_request_token_for_access_token()</tt>: <span class="anchor" id="line-156"></span><span class="anchor" id="line-157"></span><p class="line867"><span class="anchor" id="line-158"></span><span class="anchor" id="line-159"></span><span class="anchor" id="line-160"></span><span class="anchor" id="line-161"></span><span class="anchor" id="line-162"></span><span class="anchor" id="line-163"></span><span class="anchor" id="line-164"></span><span class="anchor" id="line-165"></span><span class="anchor" id="line-166"></span><span class="anchor" id="line-167"></span><pre><span class="anchor" id="line-1-8"></span> from lazr.restfulclient.errors import HTTPError <span class="anchor" id="line-2-5"></span> complete = False <span class="anchor" id="line-3-3"></span> while not complete: <span class="anchor" id="line-4-1"></span> try: <span class="anchor" id="line-5-1"></span> credentials.exchange_request_token_for_access_token( <span class="anchor" id="line-6-1"></span> web_root=&quot;production&quot;) <span class="anchor" id="line-7-1"></span> complete = True <span class="anchor" id="line-8-1"></span> except HTTPError: <span class="anchor" id="line-9-1"></span> # The user hasn't authorized the token yet.</pre><span class="anchor" id="line-168"></span><span class="anchor" id="line-169"></span><p class="line862">Once <tt class="backtick">exchange_request_token_for_access_token()</tt> successfully <span class="anchor" id="line-170"></span>executes, an authorized access token will be present in <span class="anchor" id="line-171"></span><tt class="backtick">credentials.access_token</tt>. You can then pass the <tt class="backtick">Credentials</tt> object <span class="anchor" id="line-172"></span>into the <tt class="backtick">Launchpad</tt> constructor. <span class="anchor" id="line-173"></span><span class="anchor" id="line-174"></span><p class="line867"><span class="anchor" id="line-175"></span><span class="anchor" id="line-176"></span><span class="anchor" id="line-177"></span><pre><span class="anchor" id="line-1-9"></span> from launchpadlib.launchpad import Launchpad <span class="anchor" id="line-2-6"></span> launchpad = Launchpad(credentials, service_root=&quot;production&quot;)</pre><span class="anchor" id="line-178"></span><span class="anchor" id="line-179"></span><p class="line874">While this system is not ideal, we don't know of any third-party websites that <span class="anchor" id="line-180"></span>are integrating Launchpad functionality in a way that requires OAuth <span class="anchor" id="line-181"></span>tokens. <span class="anchor" id="line-182"></span><span class="anchor" id="line-183"></span><p class="line867"> <h1 id="Getting_help">Getting help</h1> <span class="anchor" id="line-184"></span><span class="anchor" id="line-185"></span><p class="line874">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: <span class="anchor" id="line-186"></span><span class="anchor" id="line-187"></span><ul><li><p class="line891"><tt class="backtick">lp_attributes</tt>: Data fields of this object. You can read from these might be able to write to some of them. <span class="anchor" id="line-188"></span></li><li><p class="line891"><tt class="backtick">lp_collections</tt>: List of launchpad objects associated with this object. <span class="anchor" id="line-189"></span></li><li><p class="line891"><tt class="backtick">lp_entries</tt>: Other Launchpad objects associated with this one. <span class="anchor" id="line-190"></span></li><li><p class="line891"><tt class="backtick">lp_operations</tt>: The names of Launchpad methods you can call on the object. <span class="anchor" id="line-191"></span><span class="anchor" id="line-192"></span></li></ul><p class="line867"><span class="anchor" id="line-193"></span><span class="anchor" id="line-194"></span><span class="anchor" id="line-195"></span><span class="anchor" id="line-196"></span><span class="anchor" id="line-197"></span><pre><span class="anchor" id="line-1-10"></span> print(sorted(bug_one.lp_attributes)) <span class="anchor" id="line-2-7"></span> # ['date_created', 'date_last_message', 'date_last_updated', ... 'tags', 'title'] <span class="anchor" id="line-3-4"></span> print(sorted(bug_one.lp_operations)) <span class="anchor" id="line-4-2"></span> # ['addAttachment', 'addWatch', 'subscribe', 'unsubscribe']</pre><span class="anchor" id="line-198"></span><span class="anchor" id="line-199"></span><p class="line862">If you need more detailed help, you can look the object up in <a class="http" href="http://launchpad.net/+apidoc">the reference documentation</a>. First, find out the type of the object. <span class="anchor" id="line-200"></span><span class="anchor" id="line-201"></span><p class="line867"><span class="anchor" id="line-202"></span><span class="anchor" id="line-203"></span><span class="anchor" id="line-204"></span><pre><span class="anchor" id="line-1-11"></span> print(repr(bug_one)) <span class="anchor" id="line-2-8"></span> # &lt;bug at https://api.staging.launchpad.net/beta/bugs/1&gt;</pre><span class="anchor" id="line-205"></span><span class="anchor" id="line-206"></span><p class="line874">This is a 'bug' type object. Now you use the type of the object as an anchor <span class="anchor" id="line-207"></span>into the reference documentation. To find out the capabilities of this object <span class="anchor" id="line-208"></span>and what data is stored inside it, you'd visit <a class="https" href="https://api.launchpad.net/devel.html#bug">https://api.launchpad.net/devel.html#bug</a>. <span class="anchor" id="line-209"></span><span class="anchor" id="line-210"></span><p class="line874">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. <span class="anchor" id="line-211"></span><span class="anchor" id="line-212"></span><ul><li>The &quot;Default representation&quot; section tells you about the available attributes. <span class="anchor" id="line-213"></span><span class="anchor" id="line-214"></span></li><li class="gap">The &quot;Custom POST methods&quot; and &quot;Custom GET methods&quot; sections tell you about methods the object supports other than the default methods described below. The methods take whatever parameters are listed in &quot;Request query parameters&quot;. (You can ignore the &quot;ws.op&quot; parameter because you're using launchpadlib; that's just the name of the method.) <span class="anchor" id="line-215"></span><span class="anchor" id="line-216"></span><span class="anchor" id="line-217"></span></li></ul><p class="line867"> <h1 id="The_top-level_objects">The top-level objects</h1> <span class="anchor" id="line-218"></span><span class="anchor" id="line-219"></span><p class="line874">The Launchpad object has attributes corresponding to the major parts <span class="anchor" id="line-220"></span>of Launchpad. These are: <span class="anchor" id="line-221"></span><span class="anchor" id="line-222"></span><ul><li><p class="line891"><tt class="backtick">.bugs</tt>: All the bugs in Launchpad <span class="anchor" id="line-223"></span></li><li><p class="line891"><tt class="backtick">.people</tt>: All the people in Launchpad <span class="anchor" id="line-224"></span></li><li><p class="line891"><tt class="backtick">.me</tt>: You <span class="anchor" id="line-225"></span></li><li><p class="line891"><tt class="backtick">.distributions</tt>: All the distributions in Launchpad <span class="anchor" id="line-226"></span></li><li><p class="line891"><tt class="backtick">.projects</tt>: All the projects in Launchpad <span class="anchor" id="line-227"></span></li><li><p class="line891"><tt class="backtick">.project_groups</tt>: All the project groups in Launchpad <span class="anchor" id="line-228"></span><span class="anchor" id="line-229"></span></li></ul><p class="line862">As a super special secret, <tt class="backtick">distributions</tt>, <tt class="backtick">projects</tt> and <tt class="backtick">project_groups</tt> are all actually the same thing. <span class="anchor" id="line-230"></span><span class="anchor" id="line-231"></span><p class="line867"><span class="anchor" id="line-232"></span><span class="anchor" id="line-233"></span><span class="anchor" id="line-234"></span><span class="anchor" id="line-235"></span><pre><span class="anchor" id="line-1-12"></span> me = launchpad.me <span class="anchor" id="line-2-9"></span> print(me.name) <span class="anchor" id="line-3-5"></span> # This should be your user name, e.g. 'salgado'</pre><span class="anchor" id="line-236"></span><span class="anchor" id="line-237"></span><p class="line862">The <tt class="backtick">launchpad.people</tt> attribute gives you access to other people who use <span class="anchor" id="line-238"></span>Launchpad. This code uses launchpad.people to look up the person <span class="anchor" id="line-239"></span>with the Launchpad name &quot;salgado&quot;. <span class="anchor" id="line-240"></span><span class="anchor" id="line-241"></span><p class="line867"><span class="anchor" id="line-242"></span><span class="anchor" id="line-243"></span><span class="anchor" id="line-244"></span><span class="anchor" id="line-245"></span><span class="anchor" id="line-246"></span><pre><span class="anchor" id="line-1-13"></span> people = launchpad.people <span class="anchor" id="line-2-10"></span> salgado = people['salgado'] <span class="anchor" id="line-3-6"></span> print(salgado.display_name) <span class="anchor" id="line-4-3"></span> # Guilherme Salgado</pre><span class="anchor" id="line-247"></span><span class="anchor" id="line-248"></span><p class="line874">You can search for objects in other ways. Here's another way of <span class="anchor" id="line-249"></span>finding &quot;salgado&quot;. <span class="anchor" id="line-250"></span><span class="anchor" id="line-251"></span><p class="line867"><span class="anchor" id="line-252"></span><span class="anchor" id="line-253"></span><span class="anchor" id="line-254"></span><span class="anchor" id="line-255"></span><pre><span class="anchor" id="line-1-14"></span> salgado = people.getByEmail(email=&quot;guilherme.salgado@canonical.com&quot;) <span class="anchor" id="line-2-11"></span> print(salgado.display_name) <span class="anchor" id="line-3-7"></span> # Guilherme Salgado</pre><span class="anchor" id="line-256"></span><span class="anchor" id="line-257"></span><p class="line874">Some searches return more than one object. <span class="anchor" id="line-258"></span><span class="anchor" id="line-259"></span><p class="line867"><span class="anchor" id="line-260"></span><span class="anchor" id="line-261"></span><span class="anchor" id="line-262"></span><span class="anchor" id="line-263"></span><span class="anchor" id="line-264"></span><span class="anchor" id="line-265"></span><span class="anchor" id="line-266"></span><span class="anchor" id="line-267"></span><span class="anchor" id="line-268"></span><pre><span class="anchor" id="line-1-15"></span> for person in people.find(text=&quot;salgado&quot;): <span class="anchor" id="line-2-12"></span> print(person.name) <span class="anchor" id="line-3-8"></span> # agustin-salgado <span class="anchor" id="line-4-4"></span> # ariel-salgado <span class="anchor" id="line-5-2"></span> # axel-salgado <span class="anchor" id="line-6-2"></span> # bruno-salgado <span class="anchor" id="line-7-2"></span> # camilosalgado <span class="anchor" id="line-8-2"></span> # ...</pre><span class="anchor" id="line-269"></span><span class="anchor" id="line-270"></span><p class="line862">Note that, unlike typical Python methods, these methods--<tt class="backtick">find()</tt> and <tt class="backtick">getByEmail()</tt>--don't support positional arguments, only keyword arguments. You can't call <tt class="backtick">people.find(&quot;salgado&quot;)</tt>; it has to be <tt class="backtick">people.find(text=&quot;salgado&quot;)</tt>. <span class="anchor" id="line-271"></span><span class="anchor" id="line-272"></span><span class="anchor" id="line-273"></span><p class="line867"> <h1 id="Entries">Entries</h1> <span class="anchor" id="line-274"></span><span class="anchor" id="line-275"></span><p class="line874">Bugs, people, projects, team memberships, and most other objects published <span class="anchor" id="line-276"></span>through Launchpad's web service, all work pretty much the same way. We <span class="anchor" id="line-277"></span>call all these objects &quot;entries&quot;. Each corresponds to a single piece <span class="anchor" id="line-278"></span>of data within Launchpad. <span class="anchor" id="line-279"></span><span class="anchor" id="line-280"></span><p class="line874">You can use the web service to discover various facts about an <span class="anchor" id="line-281"></span>entry. The launchpadlib makes the facts available as attributes of the <span class="anchor" id="line-282"></span>entry object. <span class="anchor" id="line-283"></span><span class="anchor" id="line-284"></span><p class="line867"><tt class="backtick">name</tt> and <tt class="backtick">display_name</tt> are facts about people. <span class="anchor" id="line-285"></span><span class="anchor" id="line-286"></span><p class="line867"><span class="anchor" id="line-287"></span><span class="anchor" id="line-288"></span><span class="anchor" id="line-289"></span><span class="anchor" id="line-290"></span><span class="anchor" id="line-291"></span><span class="anchor" id="line-292"></span><pre><span class="anchor" id="line-1-16"></span> print(salgado.name) <span class="anchor" id="line-2-13"></span> # salgado <span class="anchor" id="line-3-9"></span> <span class="anchor" id="line-4-5"></span> print(salgado.display_name) <span class="anchor" id="line-5-3"></span> # Guilherme Salgado</pre><span class="anchor" id="line-293"></span><span class="anchor" id="line-294"></span><p class="line867"><tt class="backtick">private</tt> and <tt class="backtick">description</tt> are facts about bugs. <span class="anchor" id="line-295"></span><span class="anchor" id="line-296"></span><p class="line867"><span class="anchor" id="line-297"></span><span class="anchor" id="line-298"></span><span class="anchor" id="line-299"></span><span class="anchor" id="line-300"></span><span class="anchor" id="line-301"></span><span class="anchor" id="line-302"></span><span class="anchor" id="line-303"></span><span class="anchor" id="line-304"></span><pre><span class="anchor" id="line-1-17"></span> print(bug_one.private) <span class="anchor" id="line-2-14"></span> # False <span class="anchor" id="line-3-10"></span> <span class="anchor" id="line-4-6"></span> print(bug_one.description) <span class="anchor" id="line-5-4"></span> # Microsoft has a majority market share in the new desktop PC marketplace. <span class="anchor" id="line-6-3"></span> # This is a bug, which Ubuntu is designed to fix. <span class="anchor" id="line-7-3"></span> # ...</pre><span class="anchor" id="line-305"></span><span class="anchor" id="line-306"></span><span class="anchor" id="line-307"></span><p class="line874">Some of an object's attributes are links to other entries. Bugs have <span class="anchor" id="line-308"></span>an attribute <tt class="backtick">owner</tt>, but the owner of a bug is a person, with <span class="anchor" id="line-309"></span>attributes of its own. <span class="anchor" id="line-310"></span><span class="anchor" id="line-311"></span><p class="line867"><span class="anchor" id="line-312"></span><span class="anchor" id="line-313"></span><span class="anchor" id="line-314"></span><span class="anchor" id="line-315"></span><span class="anchor" id="line-316"></span><span class="anchor" id="line-317"></span><span class="anchor" id="line-318"></span><span class="anchor" id="line-319"></span><pre><span class="anchor" id="line-1-18"></span> owner = bug_one.owner <span class="anchor" id="line-2-15"></span> print(repr(owner)) <span class="anchor" id="line-3-11"></span> # &lt;person at https://api.staging.launchpad.net/beta/~sabdfl&gt; <span class="anchor" id="line-4-7"></span> print(owner.name) <span class="anchor" id="line-5-5"></span> # sabdfl <span class="anchor" id="line-6-4"></span> print(owner.display_name) <span class="anchor" id="line-7-4"></span> # Mark Shuttleworth</pre><span class="anchor" id="line-320"></span><span class="anchor" id="line-321"></span><p class="line874">If you have permission, you can change an entry's attributes and write <span class="anchor" id="line-322"></span>the data back to the server using <tt class="backtick">lp_save()</tt>. <span class="anchor" id="line-323"></span><span class="anchor" id="line-324"></span><p class="line867"><span class="anchor" id="line-325"></span><span class="anchor" id="line-326"></span><span class="anchor" id="line-327"></span><span class="anchor" id="line-328"></span><span class="anchor" id="line-329"></span><span class="anchor" id="line-330"></span><span class="anchor" id="line-331"></span><pre><span class="anchor" id="line-1-19"></span> me = people['my-user-name'] <span class="anchor" id="line-2-16"></span> me.display_name = 'A user who edits through the Launchpad web service.' <span class="anchor" id="line-3-12"></span> me.lp_save() <span class="anchor" id="line-4-8"></span> <span class="anchor" id="line-5-6"></span> print(people['my-user-name'].display_name) <span class="anchor" id="line-6-5"></span> # A user who edits through the Launchpad web service.</pre><span class="anchor" id="line-332"></span><span class="anchor" id="line-333"></span><p class="line874">Having permission means not only being authorized to perform an <span class="anchor" id="line-334"></span>operation on the Launchpad side, but using a launchpadlib <tt class="backtick">Credentials</tt> <span class="anchor" id="line-335"></span>object that authorizes the operation. If you've set up your <span class="anchor" id="line-336"></span>launchpadlib Credentials for read-only access, you won't be able to <span class="anchor" id="line-337"></span>change data through launchpadlib. <span class="anchor" id="line-338"></span><span class="anchor" id="line-339"></span><span class="anchor" id="line-340"></span><p class="line867"> <h2 id="self_link:_the_permanent_ID">self_link: the permanent ID</h2> <span class="anchor" id="line-341"></span><span class="anchor" id="line-342"></span><p class="line862">Every entry has a <tt class="backtick">self_link</tt> attribute. You can treat this as a <span class="anchor" id="line-343"></span>permanent ID for the entry. If your program needs to keep track of <span class="anchor" id="line-344"></span>Launchpad objects across multiple runs, a simple way to do it is to <span class="anchor" id="line-345"></span>keep track of the <tt class="backtick">self_link</tt>s. <span class="anchor" id="line-346"></span><span class="anchor" id="line-347"></span><p class="line867"><span class="anchor" id="line-348"></span><span class="anchor" id="line-349"></span><span class="anchor" id="line-350"></span><span class="anchor" id="line-351"></span><span class="anchor" id="line-352"></span><span class="anchor" id="line-353"></span><pre><span class="anchor" id="line-1-20"></span> print(salgado.self_link) <span class="anchor" id="line-2-17"></span> # https://api.staging.launchpad.net/beta/~salgado <span class="anchor" id="line-3-13"></span> <span class="anchor" id="line-4-9"></span> bug_one.self_link <span class="anchor" id="line-5-7"></span> # https://api.staging.launchpad.net/beta/bugs/1</pre><span class="anchor" id="line-354"></span><span class="anchor" id="line-355"></span><p class="line867"> <h2 id="web_link:_the_link_to_the_Launchpad_website">web_link: the link to the Launchpad website</h2> <span class="anchor" id="line-356"></span><span class="anchor" id="line-357"></span><p class="line862">Most of the entries published by the web service correspond to pages on the Launchpad website. You can get the website URL of an entry with the <tt class="backtick">web_link</tt> attribute: <span class="anchor" id="line-358"></span><span class="anchor" id="line-359"></span><p class="line867"><span class="anchor" id="line-360"></span><span class="anchor" id="line-361"></span><span class="anchor" id="line-362"></span><span class="anchor" id="line-363"></span><span class="anchor" id="line-364"></span><span class="anchor" id="line-365"></span><pre><span class="anchor" id="line-1-21"></span> print(salgado.web_link) <span class="anchor" id="line-2-18"></span> # https://staging.launchpad.net/~salgado <span class="anchor" id="line-3-14"></span> <span class="anchor" id="line-4-10"></span> bug_one.web_link <span class="anchor" id="line-5-8"></span> # https://bugs.staging.launchpad.net/bugs/1</pre><span class="anchor" id="line-366"></span><span class="anchor" id="line-367"></span><p class="line862">Some entries don't correspond to any page on the Launchpad website: these entries won't have a <tt class="backtick">web_link</tt>. <span class="anchor" id="line-368"></span><span class="anchor" id="line-369"></span><p class="line867"> <h2 id="Named_operations">Named operations</h2> <span class="anchor" id="line-370"></span><span class="anchor" id="line-371"></span><p class="line874">Entries can support special operations just like collections, but again note that, these methods don't support positional arguments, only keyword arguments. <span class="anchor" id="line-372"></span><span class="anchor" id="line-373"></span><span class="anchor" id="line-374"></span><p class="line867"> <h1 id="Errors">Errors</h1> <span class="anchor" id="line-375"></span><span class="anchor" id="line-376"></span><p class="line874">When the Launchpad web service encounters an error, it sends back an error message to launchpadlib, which raises an HTTPError exception. You'll see information about the HTTP request that caused the error, and the server-side error message. Depending on the error, you may be able to recover or change your code and try again. <span class="anchor" id="line-377"></span><span class="anchor" id="line-378"></span><p class="line874">If you're using an old version of launchpadlib, the HTTPError may not be this helpful. To see the server-side error message, you'll need to print out the .content of the HTTPError exception. <span class="anchor" id="line-379"></span><span class="anchor" id="line-380"></span><p class="line867"><span class="anchor" id="line-381"></span><span class="anchor" id="line-382"></span><span class="anchor" id="line-383"></span><span class="anchor" id="line-384"></span><span class="anchor" id="line-385"></span><span class="anchor" id="line-386"></span><span class="anchor" id="line-1-1"></span><div class="highlight python"><div class="codearea" dir="ltr" lang="en"> <script type="text/javascript"> function isnumbered(obj) { return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber'; } function nformat(num,chrs,add) { var nlen = Math.max(0,chrs-(''+num).length), res = ''; while (nlen>0) { res += ' '; nlen-- } return res+num+add; } function addnumber(did, nstart, nstep) { var c = document.getElementById(did), l = c.firstChild, n = 1; if (!isnumbered(c)) { if (typeof nstart == 'undefined') nstart = 1; if (typeof nstep == 'undefined') nstep = 1; var n = nstart; while (l != null) { if (l.tagName == 'SPAN') { var s = document.createElement('SPAN'); var a = document.createElement('A'); s.className = 'LineNumber'; a.appendChild(document.createTextNode(nformat(n,4,''))); a.href = '#' + did + '_' + n; s.appendChild(a); s.appendChild(document.createTextNode(' ')); n += nstep; if (l.childNodes.length) { l.insertBefore(s, l.firstChild); } else { l.appendChild(s); } } l = l.nextSibling; } } return false; } function remnumber(did) { var c = document.getElementById(did), l = c.firstChild; if (isnumbered(c)) { while (l != null) { if (l.tagName == 'SPAN' && l.firstChild.className == 'LineNumber') l.removeChild(l.firstChild); l = l.nextSibling; } } return false; } function togglenumber(did, nstart, nstep) { var c = document.getElementById(did); if (isnumbered(c)) { remnumber(did); } else { addnumber(did,nstart,nstep); } return false; } </script> <script type="text/javascript"> document.write('<a href="#" onclick="return togglenumber(\'CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55\', 1, 1);" \ class="codenumbers">Toggle line numbers<\/a>'); </script> <pre dir="ltr" id="CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55" lang="en"><span class="line"><span class="LineNumber"><a href="#CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_1"> 1</a> </span><span class="LineAnchor" id="CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_1"></span><span class="anchor" id="line-1-2"></span><span class="ResWord">try</span>:</span> <span class="line"><span class="LineNumber"><a href="#CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_2"> 2</a> </span><span class="LineAnchor" id="CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_2"></span><span class="anchor" id="line-2-1"></span> <span class="ID">failing_thing</span>()</span> <span class="line"><span class="LineNumber"><a href="#CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_3"> 3</a> </span><span class="LineAnchor" id="CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_3"></span><span class="anchor" id="line-3-1"></span><span class="ResWord">except</span> <span class="ID">HTTPError</span> <span class="ResWord">as</span> <span class="ID">http_error</span>:</span> <span class="line"><span class="LineNumber"><a href="#CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_4"> 4</a> </span><span class="LineAnchor" id="CA-fb78a48ac0526ee8649dc78bfa231d31edb45c55_4"></span><span class="anchor" id="line-4-1"></span> <span class="ResWord">print</span>(<span class="ID">http_error</span>.<span class="ID">content</span>)</span> </pre></div></div><span class="anchor" id="line-387"></span><span class="anchor" id="line-388"></span><span class="anchor" id="line-389"></span><p class="line867"> <h1 id="Collections">Collections</h1> <span class="anchor" id="line-390"></span><span class="anchor" id="line-391"></span><p class="line874">When Launchpad groups similar entries together, we call it a <span class="anchor" id="line-392"></span>collection. You've already seen one collection: the list of people you <span class="anchor" id="line-393"></span>get back when you call launchpad.people.find. <span class="anchor" id="line-394"></span><span class="anchor" id="line-395"></span><p class="line867"><span class="anchor" id="line-396"></span><span class="anchor" id="line-397"></span><span class="anchor" id="line-398"></span><pre><span class="anchor" id="line-1-22"></span> for person in launchpad.people.find(text=&quot;salgado&quot;): <span class="anchor" id="line-2-19"></span> print(person.name)</pre><span class="anchor" id="line-399"></span><span class="anchor" id="line-400"></span><p class="line862">That's a collection of <tt class="backtick">people</tt>-type entries. You can iterate over a <span class="anchor" id="line-401"></span>collection as you can any Python list. <span class="anchor" id="line-402"></span><span class="anchor" id="line-403"></span><p class="line874">Some of an entry's attributes are links to related collections. Bug #1 <span class="anchor" id="line-404"></span>has a number of associated bug tasks, represented as a collection of <span class="anchor" id="line-405"></span>'bug task' entries. <span class="anchor" id="line-406"></span><span class="anchor" id="line-407"></span><p class="line867"><span class="anchor" id="line-408"></span><span class="anchor" id="line-409"></span><span class="anchor" id="line-410"></span><span class="anchor" id="line-411"></span><span class="anchor" id="line-412"></span><span class="anchor" id="line-413"></span><span class="anchor" id="line-414"></span><span class="anchor" id="line-415"></span><span class="anchor" id="line-416"></span><span class="anchor" id="line-417"></span><pre><span class="anchor" id="line-1-23"></span> tasks = bug_one.bug_tasks <span class="anchor" id="line-2-20"></span> print(len(tasks)) <span class="anchor" id="line-3-15"></span> # 17 <span class="anchor" id="line-4-11"></span> for task in tasks: <span class="anchor" id="line-5-9"></span> print(task.bug_target_display_name) <span class="anchor" id="line-6-6"></span> # Computer Science Ubuntu <span class="anchor" id="line-7-5"></span> # Ichthux <span class="anchor" id="line-8-3"></span> # JAK LINUX <span class="anchor" id="line-9-2"></span> # ...</pre><span class="anchor" id="line-418"></span><span class="anchor" id="line-419"></span><p class="line874">The person 'salgado' understands two languages, represented here as a <span class="anchor" id="line-420"></span>collection of two <tt class="backtick">language</tt> entries. <span class="anchor" id="line-421"></span><span class="anchor" id="line-422"></span><p class="line867"><span class="anchor" id="line-423"></span><span class="anchor" id="line-424"></span><span class="anchor" id="line-425"></span><span class="anchor" id="line-426"></span><span class="anchor" id="line-427"></span><pre><span class="anchor" id="line-1-24"></span> for language in salgado.languages: <span class="anchor" id="line-2-21"></span> print(language.self_link) <span class="anchor" id="line-3-16"></span> # https://api.staging.launchpad.net/beta/+languages/en <span class="anchor" id="line-4-12"></span> # https://api.staging.launchpad.net/beta/+languages/pt_BR</pre><span class="anchor" id="line-428"></span><span class="anchor" id="line-429"></span><p class="line874">Because collections can be very large, it's usually a bad idea to <span class="anchor" id="line-430"></span>iterate over them. Bugs generally have a manageable <span class="anchor" id="line-431"></span>number of bug tasks, and people understand a manageable number of <span class="anchor" id="line-432"></span>languages, but Launchpad tracks over 250,000 bugs. If <span class="anchor" id="line-433"></span>you just iterate over a list, launchpadlib will just keep pulling down entries until it runs out, <span class="anchor" id="line-434"></span>which might be forever (or, realistically, until your client is banned for making too many requests). <span class="anchor" id="line-435"></span><span class="anchor" id="line-436"></span><p class="line874">That's why we recommend you slice Launchpad's collections into Python lists, <span class="anchor" id="line-437"></span>and operate on the lists. Here's code that prints descriptions <span class="anchor" id="line-438"></span>for the 10 most recently filed bugs. <span class="anchor" id="line-439"></span><span class="anchor" id="line-440"></span><p class="line867"><span class="anchor" id="line-441"></span><span class="anchor" id="line-442"></span><span class="anchor" id="line-443"></span><span class="anchor" id="line-444"></span><pre><span class="anchor" id="line-1-25"></span> bugs = launchpad.bugs[:10] <span class="anchor" id="line-2-22"></span> for bug in bugs: <span class="anchor" id="line-3-17"></span> print(bug.description)</pre><span class="anchor" id="line-445"></span><span class="anchor" id="line-446"></span><p class="line874">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. <span class="anchor" id="line-447"></span><span class="anchor" id="line-448"></span><p class="line867"><span class="anchor" id="line-449"></span><span class="anchor" id="line-450"></span><span class="anchor" id="line-451"></span><pre><span class="anchor" id="line-1-26"></span> launchpad.bugs[-5:] <span class="anchor" id="line-2-23"></span> # *** ValueError: Collection slices must have a nonnegative start point.</pre><span class="anchor" id="line-452"></span><span class="anchor" id="line-453"></span><p class="line874">And your slice needs to have a definite end point: you can't slice to the end of a collection. <span class="anchor" id="line-454"></span><span class="anchor" id="line-455"></span><p class="line867"><span class="anchor" id="line-456"></span><span class="anchor" id="line-457"></span><span class="anchor" id="line-458"></span><span class="anchor" id="line-459"></span><span class="anchor" id="line-460"></span><span class="anchor" id="line-461"></span><pre><span class="anchor" id="line-1-27"></span> bugs[10:] <span class="anchor" id="line-2-24"></span> # *** ValueError: Collection slices must have a definite, nonnegative end point. <span class="anchor" id="line-3-18"></span> <span class="anchor" id="line-4-13"></span> bugs[:-5] <span class="anchor" id="line-5-10"></span> # *** ValueError: Collection slices must have a definite, nonnegative end point.</pre><span class="anchor" id="line-462"></span><span class="anchor" id="line-463"></span><p class="line874">On the plus side, you can include a step number with your slice, as with a normal Python list: <span class="anchor" id="line-464"></span><span class="anchor" id="line-465"></span><p class="line867"><span class="anchor" id="line-466"></span><span class="anchor" id="line-467"></span><span class="anchor" id="line-468"></span><span class="anchor" id="line-469"></span><pre><span class="anchor" id="line-1-28"></span> every_other_bug = launchpad.bugs[0:10:2] <span class="anchor" id="line-2-25"></span> len(every_other_bug) <span class="anchor" id="line-3-19"></span> # 5</pre><span class="anchor" id="line-470"></span><span class="anchor" id="line-471"></span><span class="anchor" id="line-472"></span><p class="line867"> <h1 id="Hosted_files">Hosted files</h1> <span class="anchor" id="line-473"></span><span class="anchor" id="line-474"></span><p class="line874">Launchpad stores some data in the form of binary files. A good example <span class="anchor" id="line-475"></span>is people's mugshots. With launchpadlib, you can read and write these <span class="anchor" id="line-476"></span>binary files programatically. <span class="anchor" id="line-477"></span><span class="anchor" id="line-478"></span><p class="line874">If you have a launchpadlib reference to one of these hosted files, you <span class="anchor" id="line-479"></span>can read its data by calling the <tt class="backtick">open()</tt> method and treating the result <span class="anchor" id="line-480"></span>as an open filehandle. <span class="anchor" id="line-481"></span><span class="anchor" id="line-482"></span><p class="line867"><span class="anchor" id="line-483"></span><span class="anchor" id="line-484"></span><span class="anchor" id="line-485"></span><span class="anchor" id="line-486"></span><span class="anchor" id="line-487"></span><span class="anchor" id="line-488"></span><span class="anchor" id="line-489"></span><span class="anchor" id="line-490"></span><span class="anchor" id="line-491"></span><pre><span class="anchor" id="line-1-29"></span> mugshot = launchpad.me.mugshot <span class="anchor" id="line-2-26"></span> mugshot_handle = mugshot.open() <span class="anchor" id="line-3-20"></span> mugshot_handle.read() <span class="anchor" id="line-4-14"></span> # [binary data] <span class="anchor" id="line-5-11"></span> mugshot_handle.content_type <span class="anchor" id="line-6-7"></span> # 'image/jpeg' <span class="anchor" id="line-7-6"></span> mugshot_handle.last_modified <span class="anchor" id="line-8-4"></span> # 'Wed, 12 Mar 2008 21:47:05 GMT'</pre><span class="anchor" id="line-492"></span><span class="anchor" id="line-493"></span><p class="line874">You'll get an error if the file doesn't exist: for instance, if a <span class="anchor" id="line-494"></span>person doesn't have a mugshot. <span class="anchor" id="line-495"></span><span class="anchor" id="line-496"></span><p class="line867"><span class="anchor" id="line-497"></span><span class="anchor" id="line-498"></span><span class="anchor" id="line-499"></span><pre><span class="anchor" id="line-1-30"></span> launchpad.people['has-no-mugshot'].mugshot <span class="anchor" id="line-2-27"></span> # *** HTTPError: HTTP Error 404: Not Found</pre><span class="anchor" id="line-500"></span><span class="anchor" id="line-501"></span><p class="line874">To create or overwrite a file, open the hosted file object for <span class="anchor" id="line-502"></span>write. You'll need to provide the access mode (&quot;w&quot;), the MIME type <span class="anchor" id="line-503"></span>of the file you're sending to Launchpad, and the filename you want to <span class="anchor" id="line-504"></span>give it on the server side. <span class="anchor" id="line-505"></span><span class="anchor" id="line-506"></span><p class="line867"><span class="anchor" id="line-507"></span><span class="anchor" id="line-508"></span><span class="anchor" id="line-509"></span><pre><span class="anchor" id="line-1-31"></span> with mugshot.open(&quot;w&quot;, &quot;image/jpeg&quot;, &quot;my-image.jpg&quot;) as mugshot_handle: <span class="anchor" id="line-2-28"></span> mugshot_handle.write(&quot;image data goes here&quot;)</pre><span class="anchor" id="line-510"></span><span class="anchor" id="line-511"></span><p class="line874">If there's something wrong--maybe you provide a file of the wrong <span class="anchor" id="line-512"></span>type--you'll get an <tt class="backtick">HTTPError</tt> with a status code of 400. The <tt class="backtick">content</tt> <span class="anchor" id="line-513"></span>attribute will contain an error message. <span class="anchor" id="line-514"></span><span class="anchor" id="line-515"></span><p class="line867"><span class="anchor" id="line-516"></span><span class="anchor" id="line-517"></span><span class="anchor" id="line-518"></span><span class="anchor" id="line-519"></span><span class="anchor" id="line-520"></span><span class="anchor" id="line-521"></span><span class="anchor" id="line-522"></span><pre><span class="anchor" id="line-1-32"></span> print(http_error.content) <span class="anchor" id="line-2-29"></span> # This image is not exactly 192x192 pixels in size. <span class="anchor" id="line-3-21"></span> <span class="anchor" id="line-4-15"></span> print(http_error.content) <span class="anchor" id="line-5-12"></span> # The file uploaded was not recognized as an image; please <span class="anchor" id="line-6-8"></span> # check it and retry.</pre><span class="anchor" id="line-523"></span><span class="anchor" id="line-524"></span><span class="anchor" id="line-525"></span><p class="line867"> <h1 id="Persistent_references_to_Launchpad_objects">Persistent references to Launchpad objects</h1> <span class="anchor" id="line-526"></span><span class="anchor" id="line-527"></span><p class="line862">Every entry and collection has a unique ID: its URL. You can get this unique ID by calling <tt class="backtick">str()</tt> on the object. <span class="anchor" id="line-528"></span><span class="anchor" id="line-529"></span><p class="line867"><span class="anchor" id="line-530"></span><span class="anchor" id="line-531"></span><span class="anchor" id="line-532"></span><pre><span class="anchor" id="line-1-33"></span> print(str(bug_one)) <span class="anchor" id="line-2-30"></span> # https://api.staging.launchpad.net/beta/bugs/1</pre><span class="anchor" id="line-533"></span><span class="anchor" id="line-534"></span><p class="line862">If you need to keep track of Launchpad objects over time, or pass references to Launchpad objects to other programs, use these strings. If you've got one of these strings, you can turn it into the corresponding Launchpad object by calling <tt class="backtick">launchpad.load()</tt>. <span class="anchor" id="line-535"></span><span class="anchor" id="line-536"></span><p class="line867"><span class="anchor" id="line-537"></span><span class="anchor" id="line-538"></span><span class="anchor" id="line-539"></span><span class="anchor" id="line-540"></span><pre><span class="anchor" id="line-1-34"></span> bug_one = launchpad.load(&quot;https://api.staging.launchpad.net/beta/bugs/1&quot;) <span class="anchor" id="line-2-31"></span> print(bug_one.title) <span class="anchor" id="line-3-22"></span> Microsoft has a majority market share</pre><span class="anchor" id="line-541"></span><span class="anchor" id="line-542"></span><p class="line874">You're bookmarking the Launchpad objects and coming back to them later, just like you'd bookmark pages in your web browser. <span class="anchor" id="line-543"></span><span class="anchor" id="line-544"></span><span class="anchor" id="line-545"></span><p class="line867"> <h1 id="Three_things_to_make_your_client_faster">Three things to make your client faster</h1> <span class="anchor" id="line-546"></span><span class="anchor" id="line-547"></span><p class="line862">1. <strong>Use the latest launchpadlib.</strong> (The versions in the current Ubuntu release should be fine; otherwise run from the branch or the latest tarball.) <span class="anchor" id="line-548"></span><span class="anchor" id="line-549"></span><p class="line862">2. <strong>Profile:</strong> <span class="anchor" id="line-550"></span><span class="anchor" id="line-551"></span><p class="line867"><span class="anchor" id="line-552"></span><span class="anchor" id="line-553"></span><span class="anchor" id="line-554"></span><pre><span class="anchor" id="line-1-35"></span> import httplib2 <span class="anchor" id="line-2-32"></span> httplib2.debuglevel = 1</pre><span class="anchor" id="line-555"></span><span class="anchor" id="line-556"></span><p class="line862">3. <strong>Fetch objects only once:</strong> <span class="anchor" id="line-557"></span><span class="anchor" id="line-558"></span><p class="line874">Don't do this: <span class="anchor" id="line-559"></span><span class="anchor" id="line-560"></span><p class="line867"><span class="anchor" id="line-561"></span><span class="anchor" id="line-562"></span><span class="anchor" id="line-563"></span><pre><span class="anchor" id="line-1-36"></span> if bug.person is not None: <span class="anchor" id="line-2-33"></span> print(bug.person.name)</pre><span class="anchor" id="line-564"></span><span class="anchor" id="line-565"></span><p class="line874">instead <span class="anchor" id="line-566"></span><span class="anchor" id="line-567"></span><p class="line867"><span class="anchor" id="line-568"></span><span class="anchor" id="line-569"></span><span class="anchor" id="line-570"></span><span class="anchor" id="line-571"></span><pre><span class="anchor" id="line-1-37"></span> p = bug.person <span class="anchor" id="line-2-34"></span> if p is not None: <span class="anchor" id="line-3-23"></span> print(p.name)</pre><span class="anchor" id="line-572"></span><span class="anchor" id="line-573"></span><p class="line862">(From <a class="http" href="http://blog.launchpad.net/api/three-tips-for-faster-launchpadlib-api-clients">the blog</a>). <span class="anchor" id="line-574"></span><span class="anchor" id="line-575"></span><p class="line867"> <h1 id="Planned_improvements">Planned improvements</h1> <span class="anchor" id="line-576"></span><span class="anchor" id="line-577"></span><p class="line874">launchpadlib still has deficiencies. We track bugs in the launchpadlib bug tracker <span class="anchor" id="line-578"></span>(<a class="https" href="https://bugs.launchpad.net/launchpadlib">https://bugs.launchpad.net/launchpadlib</a>) and will be working to <span class="anchor" id="line-579"></span>improve launchpadlib throughout the limited beta. <span class="anchor" id="line-580"></span><span class="anchor" id="line-581"></span><p class="line867"> <h1 id="See_also">See also</h1> <span class="anchor" id="line-582"></span><span class="anchor" id="line-583"></span><ul><li><p class="line891"><a class="http" href="http://launchpad.net/+apidoc/">web service reference documentation</a> for a list of all objects, operations, etc <span class="anchor" id="line-584"></span><span class="anchor" id="line-585"></span></li></ul><p class="line867"> <h1 id="launchpadlib_API_compatibility">launchpadlib API compatibility</h1> <span class="anchor" id="line-586"></span><span class="anchor" id="line-587"></span><p class="line874">The API compatibility of the launchpadlib Python library has not always been maintained as well as an author of a program using it would hope. <span class="anchor" id="line-588"></span><span class="anchor" id="line-589"></span><p class="line867"> <h2 id="A.3E.3D_1.5.5_.28.3E.3D_Ubuntu_Lucid_Lynx.29">&gt;= 1.5.5 (&gt;= Ubuntu Lucid Lynx)</h2> <span class="anchor" id="line-590"></span><p class="line862">Version 1.5.5 added the support for accessing various different versions of the remote web-service API (at the time of writing, these versions are known as &quot;beta&quot;, &quot;1.0&quot; and &quot;devel&quot;). Whilst the new <tt class="backtick">version</tt> parameters were compatibly added, there was an incompatible change to the URLs that launchpadlib would accept as <tt class="backtick">service_root</tt> parameters: <span class="anchor" id="line-591"></span><ul><li><p class="line862">launchpadlib 1.5.4 and earlier <strong>requires</strong> URLs of the form <tt class="backtick">https://api.launchpad.net/beta/</tt> <span class="anchor" id="line-592"></span></li><li><p class="line862">launchpadlib 1.5.5 and later <strong>requires</strong> URLs of the form <tt class="backtick">https://api.launchpad.net/</tt> <span class="anchor" id="line-593"></span><span class="anchor" id="line-594"></span></li></ul><p class="line874">and either will break in non-obvious ways if you give it the wrong form. <span class="anchor" id="line-595"></span><span class="anchor" id="line-596"></span><p class="line867"> <h2 id="A1.8.0_.28no_Ubuntu_release.29">1.8.0 (no Ubuntu release)</h2> <span class="anchor" id="line-597"></span><p class="line874">Version 1.8.0 changed things, which 1.9.0 then changed again. And, it never went into any final Ubuntu release. Probably best to just pretend it doesn't exist. <span class="anchor" id="line-598"></span><span class="anchor" id="line-599"></span><p class="line867"> <h2 id="A.3E.3D_1.9.0_.28.3E.3D_Ubuntu_Natty_Narwhal.29">&gt;= 1.9.0 (&gt;= Ubuntu Natty Narwhal)</h2> <span class="anchor" id="line-600"></span><p class="line874">Version 1.9.x's changes versus 1.6.x include a major refactor of how authentication tokens are obtained. Notable consequences: <span class="anchor" id="line-601"></span><ul><li>Different kinds of tokens are obtained, and they are stored differently by default (in GNOME keyring or similar technologies instead of files), meaning it's highly unlikely that tokens stored by launchpadlib 1.6.x will be noticed by 1.9.x, so users will have to re-authorize. <span class="anchor" id="line-602"></span></li><li><p class="line862">Most of the methods by which a <tt class="backtick">Launchpad</tt> object is obtained have changed significantly: <em>(Note, positional parameter indices referred to below are 1-based)</em> <span class="anchor" id="line-603"></span><span class="anchor" id="line-604"></span></li></ul><p class="line867"><strong>Launchpad.<span class="u">init</span>:</strong> <span class="anchor" id="line-605"></span><ul><li><p class="line862">Parameters <tt class="backtick">authorization_engine</tt> and <tt class="backtick">credential_store</tt> inserted at position 2. <strong>It is no longer safe to call <tt class="backtick">Launchpad.__init__</tt> with positional parameters beyond the first in compatible applications!</strong> <span class="anchor" id="line-606"></span><span class="anchor" id="line-607"></span></li></ul><p class="line867"><strong>Launchpad.login:</strong> <span class="anchor" id="line-608"></span><ul><li>Method is now deprecated. <span class="anchor" id="line-609"></span></li><li><p class="line862">Five new parameters inserted at position 8. Mitigating factor: the only parameter after this was <tt class="backtick">version</tt>, which was probably being passed as a keyword argument anyway. <span class="anchor" id="line-610"></span><span class="anchor" id="line-611"></span></li></ul><p class="line867"><strong>Launchpad.get_token_and_login:</strong> <span class="anchor" id="line-612"></span><ul><li>Method is now deprecated. <span class="anchor" id="line-613"></span></li><li><p class="line862">Parameter 6 renamed from <tt class="backtick">authorizer_class</tt> to <tt class="backtick">authorization_engine</tt>. <span class="anchor" id="line-614"></span></li><li><p class="line862">Parameters <tt class="backtick">credential_store</tt> and <tt class="backtick">credential_save_failed</tt> inserted at position 9. Mitigating factor: the only parameter after this was <tt class="backtick">version</tt>, which was probably being passed as a keyword argument anyway. <span class="anchor" id="line-615"></span><span class="anchor" id="line-616"></span></li></ul><p class="line867"><strong>Launchpad.login_with:</strong> <span class="anchor" id="line-617"></span><ul><li><p class="line862">Positional parameter 1 changed from <tt class="backtick">consumer_name</tt> to <tt class="backtick">application_name</tt> to attempt to force common use-cases to acquire a desktop integration rather than consumer-specific token without code changes. <span class="anchor" id="line-618"></span></li><li><p class="line862">Parameter 6 renamed from <tt class="backtick">authorizer_class</tt> to <tt class="backtick">authorization_engine</tt>. <span class="anchor" id="line-619"></span></li><li><p class="line862">New parameter <tt class="backtick">consumer_name</tt> appended to replace the incarnation removed at position 1. (But it does not actually work - see <a class="https" href="https://launchpad.net/bugs/755313">https://launchpad.net/bugs/755313</a>) <span class="anchor" id="line-620"></span></li><li><p class="line862">New parameters <tt class="backtick">credential_save_failed</tt> and <tt class="backtick">credential_store</tt> appended. <span class="anchor" id="line-621"></span></li></ul><span class="anchor" id="bottom"></span></div></div><p id="pageinfo" class="info" lang="en" dir="ltr">API/launchpadlib (last edited 2024-07-04 12:12:36 by <span title="jugmac00 @ p200300d30f1d3c0066008dd8781c6932.dip0.t-ipconnect.de[2003:d3:f1d:3c00:6600:8dd8:781c:6932]"><a class="interwiki" href="https://launchpad.net/~jugmac00" title="jugmac00 @ p200300d30f1d3c0066008dd8781c6932.dip0.t-ipconnect.de[2003:d3:f1d:3c00:6600:8dd8:781c:6932]">jugmac00</a></span>)</p> <div id="pagebottom"></div> </div> <div id="footer"> <p class="menu"> <a href="https://help.launchpad.net/Legal">Terms of use</a> | <a href="https://launchpad.net/feedback">Help improve Launchpad</a> | <a href="https://launchpad.net/faq">FAQ</a> | <a href="/RecentChanges">Recent Changes</a></p> <p> <a rel="license" href="http://creativecommons.org/licenses/by/2.0/uk/"> <span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">Launchpad Help</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://canonical.com/" property="cc:attributionName" rel="cc:attributionURL">Canonical Ltd</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/2.0/uk/">Creative Commons Attribution 2.0 UK: England &amp; Wales License</a>. <img alt="Creative Commons License" style="border-width:0;vertical-align:middle;" src="https://licensebuttons.net/l/by/2.0/uk/80x15.png" /></a> </p> <p>&copy; 2004-2019 <a href="https://canonical.com/" target="_blank">Canonical Limited.</a></p> </div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10