If you try to look up a non-existent project with lplib.projects[project_name], it will normally raise a KeyError except when the project_name starts with a space. In that case, it returns a bogus Entry object. Oddly, https://edge.launchpad.net/api/beta/%20foo displays a NotFound exception, but https://api.edge.launchpad.net/beta/%20foo, which launchpadlib uses, returns the bogus Entry object.
Here is how you can recreate the problem with launchpadlib/contrib/lpapi.py.
$ ~/work/trunk/bin/py lpapi.py
>>> lp = lp_factory('edge')
Loading credentials...
>>> project = lp.projects[' foo']
>>> type(project)
<class 'lazr.restfulclient.resource.Entry'>
>>> project.lp_attributes
['resource_type_link']
>>> project.lp_collections
['cves', 'branches', 'packagesets', 'distributions', 'projects', 'project_groups', 'translation_import_queue_entries', 'people', 'bugs']
>>> project.lp_entries
['me', 'pillars']
>>> print project
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/home/egrubbs/canonical/lp-sourcedeps/eggs/lazr.restfulclient-0.9.5-py2.4.egg/lazr/restfulclient/resource.py", line 564, in __str__
return self.self_link
File "/home/egrubbs/canonical/lp-sourcedeps/eggs/lazr.restfulclient-0.9.5-py2.4.egg/lazr/restfulclient/resource.py", line 571, in __getattr__
return super(Entry, self).__getattr__(name)
File "/home/egrubbs/canonical/lp-sourcedeps/eggs/lazr.restfulclient-0.9.5-py2.4.egg/lazr/restfulclient/resource.py", line 308, in __getattr__
raise AttributeError("'%s' object has no attribute '%s'"
AttributeError: 'Entry' object has no attribute 'self_link'
Here is the actual web request that launchpadlib is making. It appears that this is an error in lazr.restful.
(Pdb)
> /home/egrubbs/canonical/lp-sourcedeps/eggs/lazr.restfulclient-0.9.5-py2.4.egg/lazr/restfulclient/_browser.py(214)get()
-> response, content = self._request(url, extra_headers=headers)
(Pdb) url
'https://api.edge.launchpad.net/beta/ foo'
(Pdb) response
{'status': '200', 'content-length': '913', 'via': '1.0 wildcard.edge.launchpad.net', 'content-location': 'https://api.edge.launchpad.net/beta/ foo', 'x-powered-by': 'Zope (www.zope.org), Python (www.python.org)', 'vary': 'Cookie,Authorization,Accept', 'server': 'zope.server.http (HTTP)', 'connection': 'close', 'etag': '"bf97412f779135f204f5df44d1e7f65b2e4bb44a"', 'date': 'Thu, 01 Oct 2009 14:21:27 GMT', 'content-type': 'application/json'}
(Pdb) content
'{"me_link": "https://api.edge.launchpad.net/beta/people/+me", "cves_collection_link": "https://api.edge.launchpad.net/beta/bugs/cve", "branches_collection_link": "https://api.edge.launchpad.net/beta/branches", "packagesets_collection_link": "https://api.edge.launchpad.net/beta/package-sets", "distributions_collection_link": "https://api.edge.launchpad.net/beta/distros", "projects_collection_link": "https://api.edge.launchpad.net/beta/projects", "project_groups_collection_link": "https://api.edge.launchpad.net/beta/projectgroups", "translation_import_queue_entries_collection_link": "https://api.edge.launchpad.net/beta/+imports", "pillars_link": "https://api.edge.launchpad.net/beta/pillars", "bugs_collection_link": "https://api.edge.launchpad.net/beta/bugs", "resource_type_link": "https://api.edge.launchpad.net/beta/#service-root", "people_collection_link": "https://api.edge.launchpad.net/beta/people"}'
(Pdb)
lazr.restfulclient should URL-escape the names when it does lookups. This is just one instance of a general problem.
This isn't a very serious bug, and since bad code now results in an error rather than silent weirdness (albeit not a very helpful error), I think it's less serious still.