/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2006 Canonical Ltd
0.4.4 by Martin Pool
Start forming xmlrpc requests
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
0.4.4 by Martin Pool
Start forming xmlrpc requests
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.4.4 by Martin Pool
Start forming xmlrpc requests
16
17
0.4.17 by Martin Pool
Allow xmlrpc service url to be overridden by $BZR_LP_XMLRPC_URL
18
import os
4505.4.1 by Jonathan Lange
Trap gaierror and reraise appropriate ConnectionError.
19
import socket
0.4.7 by Martin Pool
Start making provision to test using a mock xmlrpc transport.
20
from urlparse import urlsplit, urlunsplit
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
21
import urllib
0.4.4 by Martin Pool
Start forming xmlrpc requests
22
import xmlrpclib
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
23
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
24
from bzrlib.lazy_import import lazy_import
25
lazy_import(globals(), """
26
from bzrlib import urlutils
27
""")
28
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
29
from bzrlib import (
30
    config,
31
    errors,
2900.2.22 by Vincent Ladeuil
Polishing.
32
    __version__ as _bzrlib_version,
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
33
    )
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
34
from bzrlib.transport.http import _urllib2_wrappers
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
35
36
# for testing, do
37
'''
38
export BZR_LP_XMLRPC_URL=http://xmlrpc.staging.launchpad.net/bazaar/
39
'''
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
40
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
41
class InvalidLaunchpadInstance(errors.BzrError):
42
43
    _fmt = "%(lp_instance)s is not a valid Launchpad instance."
44
45
    def __init__(self, lp_instance):
46
        errors.BzrError.__init__(self, lp_instance=lp_instance)
47
48
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
49
class NotLaunchpadBranch(errors.BzrError):
50
4031.2.8 by Jonathan Lange
Say "registered on", not "hosted on".
51
    _fmt = "%(url)s is not registered on Launchpad."
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
52
53
    def __init__(self, url):
54
        errors.BzrError.__init__(self, url=url)
55
56
4776.2.6 by Vincent Ladeuil
Fixed as per review comments.
57
class XMLRPCTransport(xmlrpclib.Transport):
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
58
4776.3.1 by Vincent Ladeuil
Fix python2.4 compatibility with xmlrpclib.
59
    def __init__(self, scheme):
4776.3.2 by John Arbash Meinel
Clarify the comment as to why we are checking __init__
60
        # In python2.4 xmlrpclib.Transport is a old-style class, and does not
61
        # define __init__, so we check first
4776.3.1 by Vincent Ladeuil
Fix python2.4 compatibility with xmlrpclib.
62
        init = getattr(xmlrpclib.Transport, '__init__', None)
63
        if init is not None:
64
            init(self)
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
65
        self._scheme = scheme
66
        self._opener = _urllib2_wrappers.Opener()
67
        self.verbose = 0
68
69
    def request(self, host, handler, request_body, verbose=0):
70
        self.verbose = verbose
71
        url = self._scheme + "://" + host + handler
72
        request = _urllib2_wrappers.Request("POST", url, request_body)
4776.2.4 by Vincent Ladeuil
Note that User-Agent is lost (we use the bzrlib one though).
73
        # FIXME: _urllib2_wrappers will override user-agent with its own
74
        # request.add_header("User-Agent", self.user_agent)
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
75
        request.add_header("Content-Type", "text/xml")
76
77
        response = self._opener.open(request)
78
        if response.code != 200:
79
            raise xmlrpclib.ProtocolError(host + handler, response.code,
80
                                          response.msg, response.info())
81
        return self.parse_response(response)
82
83
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
84
class LaunchpadService(object):
0.4.27 by Martin Pool
doc
85
    """A service to talk to Launchpad via XMLRPC.
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
86
0.4.27 by Martin Pool
doc
87
    See http://bazaar-vcs.org/Specs/LaunchpadRpc for the methods we can call.
88
    """
0.4.6 by Martin Pool
Put the rest of the parameters into the registration request.
89
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
90
    LAUNCHPAD_DOMAINS = {
91
        'production': 'launchpad.net',
92
        'edge': 'edge.launchpad.net',
93
        'staging': 'staging.launchpad.net',
94
        'demo': 'demo.launchpad.net',
95
        'dev': 'launchpad.dev',
96
        }
97
3211.1.1 by Ian Clatworthy
Extends the launchpad plugin's implementation of lp spec urls (Tim Penhey)
98
    # NB: these should always end in a slash to avoid xmlrpclib appending
0.4.7 by Martin Pool
Start making provision to test using a mock xmlrpc transport.
99
    # '/RPC2'
3955.3.2 by Jonathan Lange
Tighten up the code a little, changing the dev service to use https,
100
    LAUNCHPAD_INSTANCE = {}
101
    for instance, domain in LAUNCHPAD_DOMAINS.iteritems():
102
        LAUNCHPAD_INSTANCE[instance] = 'https://xmlrpc.%s/bazaar/' % domain
103
3211.1.1 by Ian Clatworthy
Extends the launchpad plugin's implementation of lp spec urls (Tim Penhey)
104
    # We use edge as the default because:
3200.2.2 by Robert Collins
* The launchpad plugin now uses the ``edge`` xmlrpc server to avoid
105
    # Beta users get redirected to it
106
    # All users can use it
107
    # There is a bug in the launchpad side where redirection causes an OOPS.
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
108
    DEFAULT_INSTANCE = 'edge'
109
    DEFAULT_SERVICE_URL = LAUNCHPAD_INSTANCE[DEFAULT_INSTANCE]
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
110
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
111
    transport = None
112
    registrant_email = None
113
    registrant_password = None
114
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
115
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
116
    def __init__(self, transport=None, lp_instance=None):
0.4.23 by Martin Pool
(register-branch) fix ordering of parameters and restore transport-level test.
117
        """Construct a new service talking to the launchpad rpc server"""
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
118
        self._lp_instance = lp_instance
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
119
        if transport is None:
120
            uri_type = urllib.splittype(self.service_url)[0]
4776.2.6 by Vincent Ladeuil
Fixed as per review comments.
121
            transport = XMLRPCTransport(uri_type)
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
122
            transport.user_agent = 'bzr/%s (xmlrpclib/%s)' \
2900.2.22 by Vincent Ladeuil
Polishing.
123
                    % (_bzrlib_version, xmlrpclib.__version__)
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
124
        self.transport = transport
125
0.4.23 by Martin Pool
(register-branch) fix ordering of parameters and restore transport-level test.
126
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
127
    @property
128
    def service_url(self):
129
        """Return the http or https url for the xmlrpc server.
130
131
        This does not include the username/password credentials.
132
        """
133
        key = 'BZR_LP_XMLRPC_URL'
134
        if key in os.environ:
135
            return os.environ[key]
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
136
        elif self._lp_instance is not None:
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
137
            try:
138
                return self.LAUNCHPAD_INSTANCE[self._lp_instance]
139
            except KeyError:
140
                raise InvalidLaunchpadInstance(self._lp_instance)
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
141
        else:
142
            return self.DEFAULT_SERVICE_URL
143
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
144
    def get_proxy(self, authenticated):
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
145
        """Return the proxy for XMLRPC requests."""
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
146
        if authenticated:
147
            # auth info must be in url
148
            # TODO: if there's no registrant email perhaps we should
149
            # just connect anonymously?
150
            scheme, hostinfo, path = urlsplit(self.service_url)[:3]
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
151
            if '@' in hostinfo:
152
                raise AssertionError(hostinfo)
153
            if self.registrant_email is None:
154
                raise AssertionError()
155
            if self.registrant_password is None:
156
                raise AssertionError()
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
157
            # TODO: perhaps fully quote the password to make it very slightly
158
            # obscured
159
            # TODO: can we perhaps add extra Authorization headers
160
            # directly to the request, rather than putting this into
161
            # the url?  perhaps a bit more secure against accidentally
162
            # revealing it.  std66 s3.2.1 discourages putting the
163
            # password in the url.
164
            hostinfo = '%s:%s@%s' % (urllib.quote(self.registrant_email),
165
                                     urllib.quote(self.registrant_password),
166
                                     hostinfo)
167
            url = urlunsplit((scheme, hostinfo, path, '', ''))
168
        else:
169
            url = self.service_url
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
170
        return xmlrpclib.ServerProxy(url, transport=self.transport)
171
172
    def gather_user_credentials(self):
173
        """Get the password from the user."""
2978.5.1 by John Arbash Meinel
Fix bug #162494, 'bzr register-branch' needs proper auth handling.
174
        the_config = config.GlobalConfig()
175
        self.registrant_email = the_config.user_email()
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
176
        if self.registrant_password is None:
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
177
            auth = config.AuthenticationConfig()
178
            scheme, hostinfo = urlsplit(self.service_url)[:2]
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
179
            prompt = 'launchpad.net password for %s: ' % \
180
                    self.registrant_email
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
181
            # We will reuse http[s] credentials if we can, prompt user
182
            # otherwise
183
            self.registrant_password = auth.get_password(scheme, hostinfo,
2978.5.1 by John Arbash Meinel
Fix bug #162494, 'bzr register-branch' needs proper auth handling.
184
                                                         self.registrant_email,
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
185
                                                         prompt=prompt)
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
186
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
187
    def send_request(self, method_name, method_params, authenticated):
188
        proxy = self.get_proxy(authenticated)
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
189
        method = getattr(proxy, method_name)
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
190
        try:
191
            result = method(*method_params)
192
        except xmlrpclib.ProtocolError, e:
193
            if e.errcode == 301:
194
                # TODO: This can give a ProtocolError representing a 301 error, whose
195
                # e.headers['location'] tells where to go and e.errcode==301; should
196
                # probably log something and retry on the new url.
197
                raise NotImplementedError("should resend request to %s, but this isn't implemented"
198
                        % e.headers.get('Location', 'NO-LOCATION-PRESENT'))
199
            else:
200
                # we don't want to print the original message because its
201
                # str representation includes the plaintext password.
202
                # TODO: print more headers to help in tracking down failures
203
                raise errors.BzrError("xmlrpc protocol error connecting to %s: %s %s"
204
                        % (self.service_url, e.errcode, e.errmsg))
4505.4.1 by Jonathan Lange
Trap gaierror and reraise appropriate ConnectionError.
205
        except socket.gaierror, e:
206
            raise errors.ConnectionError(
207
                "Could not resolve '%s'" % self.domain,
208
                orig_error=e)
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
209
        return result
210
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
211
    @property
212
    def domain(self):
213
        if self._lp_instance is None:
214
            instance = self.DEFAULT_INSTANCE
215
        else:
216
            instance = self._lp_instance
217
        return self.LAUNCHPAD_DOMAINS[instance]
218
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
219
    def get_web_url_from_branch_url(self, branch_url, _request_factory=None):
3955.3.4 by Jonathan Lange
Some error cases, plus a docstring.
220
        """Get the Launchpad web URL for the given branch URL.
221
222
        :raise errors.InvalidURL: if 'branch_url' cannot be identified as a
223
            Launchpad branch URL.
224
        :return: The URL of the branch on Launchpad.
225
        """
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
226
        scheme, hostinfo, path = urlsplit(branch_url)[:3]
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
227
        if _request_factory is None:
228
            _request_factory = ResolveLaunchpadPathRequest
229
        if scheme == 'lp':
230
            resolve = _request_factory(path)
3955.3.9 by Jonathan Lange
Catch errors.
231
            try:
232
                result = resolve.submit(self)
233
            except xmlrpclib.Fault, fault:
234
                raise errors.InvalidURL(branch_url, str(fault))
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
235
            branch_url = result['urls'][0]
236
            path = urlsplit(branch_url)[2]
237
        else:
238
            domains = (
239
                'bazaar.%s' % domain
240
                for domain in self.LAUNCHPAD_DOMAINS.itervalues())
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
241
            if hostinfo not in domains:
242
                raise NotLaunchpadBranch(branch_url)
3955.3.7 by Jonathan Lange
Test the launchpad-open command. Fix up some minor bugs.
243
        return urlutils.join('https://code.%s' % self.domain, path)
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
244
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
245
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
246
class BaseRequest(object):
247
    """Base request for talking to a XMLRPC server."""
248
249
    # Set this to the XMLRPC method name.
250
    _methodname = None
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
251
    _authenticated = True
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
252
253
    def _request_params(self):
254
        """Return the arguments to pass to the method"""
255
        raise NotImplementedError(self._request_params)
256
257
    def submit(self, service):
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
258
        """Submit request to Launchpad XMLRPC server.
259
260
        :param service: LaunchpadService indicating where to send
261
            the request and the authentication credentials.
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
262
        """
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
263
        return service.send_request(self._methodname, self._request_params(),
264
                                    self._authenticated)
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
265
266
1668.1.12 by Martin Pool
(launchpad plugin) Improved --dry-run that uses a dummy xmlrpc service.
267
class DryRunLaunchpadService(LaunchpadService):
268
    """Service that just absorbs requests without sending to server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
269
1668.1.12 by Martin Pool
(launchpad plugin) Improved --dry-run that uses a dummy xmlrpc service.
270
    The dummy service does not need authentication.
271
    """
272
2898.4.1 by James Henstridge
Make it possible to make unauthenticated XML-RPC requests.
273
    def send_request(self, method_name, method_params, authenticated):
1668.1.12 by Martin Pool
(launchpad plugin) Improved --dry-run that uses a dummy xmlrpc service.
274
        pass
275
276
    def gather_user_credentials(self):
277
        pass
278
279
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
280
class BranchRegistrationRequest(BaseRequest):
281
    """Request to tell Launchpad about a bzr branch."""
282
283
    _methodname = 'register_branch'
0.4.7 by Martin Pool
Start making provision to test using a mock xmlrpc transport.
284
0.4.23 by Martin Pool
(register-branch) fix ordering of parameters and restore transport-level test.
285
    def __init__(self, branch_url,
0.4.15 by Martin Pool
(register-branch) Add command-line options
286
                 branch_name='',
287
                 branch_title='',
288
                 branch_description='',
0.4.23 by Martin Pool
(register-branch) fix ordering of parameters and restore transport-level test.
289
                 author_email='',
0.4.15 by Martin Pool
(register-branch) Add command-line options
290
                 product_name='',
291
                 ):
3246.4.3 by Daniel Watkins
Replaced another assert.
292
        if not branch_url:
293
            raise errors.InvalidURL(branch_url, "You need to specify a non-empty branch URL.")
0.4.4 by Martin Pool
Start forming xmlrpc requests
294
        self.branch_url = branch_url
0.4.15 by Martin Pool
(register-branch) Add command-line options
295
        if branch_name:
296
            self.branch_name = branch_name
0.4.14 by Martin Pool
Update xmlrpc api
297
        else:
0.4.15 by Martin Pool
(register-branch) Add command-line options
298
            self.branch_name = self._find_default_branch_name(self.branch_url)
299
        self.branch_title = branch_title
300
        self.branch_description = branch_description
301
        self.author_email = author_email
302
        self.product_name = product_name
0.4.4 by Martin Pool
Start forming xmlrpc requests
303
304
    def _request_params(self):
305
        """Return xmlrpc request parameters"""
0.4.6 by Martin Pool
Put the rest of the parameters into the registration request.
306
        # This must match the parameter tuple expected by Launchpad for this
307
        # method
0.4.4 by Martin Pool
Start forming xmlrpc requests
308
        return (self.branch_url,
0.4.15 by Martin Pool
(register-branch) Add command-line options
309
                self.branch_name,
0.4.14 by Martin Pool
Update xmlrpc api
310
                self.branch_title,
0.4.6 by Martin Pool
Put the rest of the parameters into the registration request.
311
                self.branch_description,
0.4.14 by Martin Pool
Update xmlrpc api
312
                self.author_email,
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
313
                self.product_name,
0.4.4 by Martin Pool
Start forming xmlrpc requests
314
               )
315
0.4.15 by Martin Pool
(register-branch) Add command-line options
316
    def _find_default_branch_name(self, branch_url):
0.4.14 by Martin Pool
Update xmlrpc api
317
        i = branch_url.rfind('/')
318
        return branch_url[i+1:]
319
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
320
321
class BranchBugLinkRequest(BaseRequest):
322
    """Request to link a bzr branch in Launchpad to a bug."""
323
324
    _methodname = 'link_branch_to_bug'
325
326
    def __init__(self, branch_url, bug_id):
0.4.26 by Martin Pool
(register-branch) Add test for link_branch_to_bug and fix its parameters
327
        self.bug_id = bug_id
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
328
        self.branch_url = branch_url
329
330
    def _request_params(self):
331
        """Return xmlrpc request parameters"""
332
        # This must match the parameter tuple expected by Launchpad for this
333
        # method
334
        return (self.branch_url, self.bug_id, '')
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
335
336
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
337
class ResolveLaunchpadPathRequest(BaseRequest):
338
    """Request to resolve the path component of an lp: URL."""
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
339
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
340
    _methodname = 'resolve_lp_path'
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
341
    _authenticated = False
342
343
    def __init__(self, path):
3246.4.1 by Daniel Watkins
Replaced problematic assertion with exception call.
344
        if not path:
345
            raise errors.InvalidURL(path=path,
4416.7.1 by Neil Martinsen-Burrell
Fix 238764 refer to projects rather than products in launchpad plugin
346
                                    extra="You must specify a project.")
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
347
        self.path = path
348
349
    def _request_params(self):
350
        """Return xmlrpc request parameters"""
351
        return (self.path,)