Merge lp:~thekorn/launchpadlib/fix.270393.verbose.credentials into lp:launchpadlib

Proposed by Robert Collins
Status: Rejected
Rejected by: j.c.sackett
Proposed branch: lp:~thekorn/launchpadlib/fix.270393.verbose.credentials
Merge into: lp:launchpadlib
Diff against target: 158 lines (+112/-0) (has conflicts)
2 files modified
src/launchpadlib/credentials.py (+93/-0)
src/launchpadlib/launchpad.py (+19/-0)
Text conflict in src/launchpadlib/credentials.py
Text conflict in src/launchpadlib/launchpad.py
To merge this branch: bzr merge lp:~thekorn/launchpadlib/fix.270393.verbose.credentials
Reviewer Review Type Date Requested Status
j.c.sackett (community) Needs Fixing
Review via email: mp+77680@code.launchpad.net

Description of the change

From bug 270393: (probably needs updating for launchpadlib changes)
I have different credential files for different applications and access level on my system, they look like

[1]
consumer_secret =
access_token = abcdef
consumer_key = launchpadfs
access_secret = xxxxxxxxxxxxxxxxxxxxxxxx

and I'm often asking myself which launchpad service I can access on which level with credentials created by loading this file.

So it would be nice to have extra values like

service_root = https://api.staging.launchpad.net/beta/
access_level = read_public

and make the accessible like:

>>> credentials = Credentials()
>>> credentials.load(open("some-file.txt"))
>>> credentials.service_root
'https://api.staging.launchpad.net/beta/'
>>> credentials.access_level
'read_public'

Markus

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

I'm seeing conflicts in this code.

review: Needs Fixing
Revision history for this message
j.c.sackett (jcsackett) wrote :

Is there any intent to fix the conflicts and update this branch? I note it's been sitting since my last comment, and now I see the last commit apparently was in 2009?

Unmerged revisions

32. By Markus Korn

* added Credentials.service_root. This way it is easier to discover the
  usage of a certain file of credentials. This is a first step of fixing
  (LP: #270393)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/launchpadlib/credentials.py'
2--- src/launchpadlib/credentials.py 2011-01-10 14:34:03 +0000
3+++ src/launchpadlib/credentials.py 2011-09-30 10:28:17 +0000
4@@ -34,6 +34,7 @@
5 import stat
6 import time
7 from urllib import urlencode
8+<<<<<<< TREE
9 from urlparse import urljoin
10 import webbrowser
11
12@@ -49,6 +50,16 @@
13
14 from launchpadlib import uris
15
16+=======
17+
18+from ConfigParser import SafeConfigParser, NoOptionError
19+from launchpadlib.errors import CredentialsFileError, HTTPError
20+from launchpadlib._oauth.oauth import OAuthConsumer, OAuthToken
21+
22+
23+CREDENTIALS_FILE_VERSION = '1'
24+STAGING_WEB_ROOT = 'https://staging.launchpad.net/'
25+>>>>>>> MERGE-SOURCE
26 request_token_page = '+request-token'
27 access_token_page = '+access-token'
28 authorize_token_page = '+authorize-token'
29@@ -67,6 +78,7 @@
30 """
31 _request_token = None
32
33+<<<<<<< TREE
34 URI_TOKEN_FORMAT = "uri"
35 DICT_TOKEN_FORMAT = "dict"
36
37@@ -91,6 +103,87 @@
38
39 def get_request_token(self, context=None, web_root=uris.STAGING_WEB_ROOT,
40 token_format=URI_TOKEN_FORMAT):
41+=======
42+ def __init__(self, consumer_name=None, consumer_secret='',
43+ access_token=None, service_root=None):
44+ """The user's Launchpad API credentials.
45+
46+ :param consumer_name: The name of the consumer (application)
47+ :param consumer_secret: The secret of the consumer
48+ :param access_token: The authenticated user access token
49+ :param service_root: The root uri of the service or None
50+ :type access_token: `AccessToken`
51+ """
52+ self.consumer = None
53+ self.service_root = service_root
54+ if consumer_name is not None:
55+ self.consumer = Consumer(consumer_name, consumer_secret)
56+ self.access_token = access_token
57+
58+ def load(self, readable_file):
59+ """Load credentials from a file-like object.
60+
61+ This overrides the consumer and access token given in the constructor
62+ and replaces them with the values read from the file.
63+
64+ :param readable_file: A file-like object to read the credentials from
65+ :type readable_file: Any object supporting the file-like `read()`
66+ method
67+ """
68+ # Attempt to load the access token from the file.
69+ parser = SafeConfigParser()
70+ parser.readfp(readable_file)
71+ # Check the version number and extract the access token and
72+ # secret. Then convert these to the appropriate instances.
73+ if not parser.has_section(CREDENTIALS_FILE_VERSION):
74+ raise CredentialsFileError('No configuration for version %s' %
75+ CREDENTIALS_FILE_VERSION)
76+ consumer_key = parser.get(
77+ CREDENTIALS_FILE_VERSION, 'consumer_key')
78+ consumer_secret = parser.get(
79+ CREDENTIALS_FILE_VERSION, 'consumer_secret')
80+ self.consumer = Consumer(consumer_key, consumer_secret)
81+ access_token = parser.get(
82+ CREDENTIALS_FILE_VERSION, 'access_token')
83+ access_secret = parser.get(
84+ CREDENTIALS_FILE_VERSION, 'access_secret')
85+ self.access_token = AccessToken(access_token, access_secret)
86+ try:
87+ self.service_root = parser.get(
88+ CREDENTIALS_FILE_VERSION, 'service_root') or None
89+ except NoOptionError:
90+ self.service_root = None
91+
92+ def save(self, writable_file):
93+ """Write the credentials to the file-like object.
94+
95+ :param writable_file: A file-like object to write the credentials to
96+ :type writable_file: Any object supporting the file-like `write()`
97+ method
98+ :raise CredentialsFileError: when there is either no consumer or no
99+ access token
100+ """
101+ if self.consumer is None:
102+ raise CredentialsFileError('No consumer')
103+ if self.access_token is None:
104+ raise CredentialsFileError('No access token')
105+
106+ parser = SafeConfigParser()
107+ parser.add_section(CREDENTIALS_FILE_VERSION)
108+ parser.set(CREDENTIALS_FILE_VERSION,
109+ 'consumer_key', self.consumer.key)
110+ parser.set(CREDENTIALS_FILE_VERSION,
111+ 'consumer_secret', self.consumer.secret)
112+ parser.set(CREDENTIALS_FILE_VERSION,
113+ 'access_token', self.access_token.key)
114+ parser.set(CREDENTIALS_FILE_VERSION,
115+ 'access_secret', self.access_token.secret)
116+ parser.set(CREDENTIALS_FILE_VERSION,
117+ 'service_root', str(self.service_root or ''))
118+ parser.write(writable_file)
119+
120+ def get_request_token(self, context=None, web_root=STAGING_WEB_ROOT):
121+>>>>>>> MERGE-SOURCE
122 """Request an OAuth token to Launchpad.
123
124 Also store the token in self._request_token.
125
126=== modified file 'src/launchpadlib/launchpad.py'
127--- src/launchpadlib/launchpad.py 2011-09-29 15:48:31 +0000
128+++ src/launchpadlib/launchpad.py 2011-09-30 10:28:17 +0000
129@@ -291,6 +291,7 @@
130 :return: The web service root
131 :rtype: `Launchpad`
132 """
133+<<<<<<< TREE
134 cls._warn_of_deprecated_login_method("get_token_and_login")
135 return cls._authorize_token_and_login(
136 consumer_name, service_root, cache, timeout, proxy_info,
137@@ -609,3 +610,21 @@
138 os.makedirs(cache_path, 0700)
139 return (service_root, launchpadlib_dir, cache_path, service_root_dir)
140
141+=======
142+ credentials = Credentials(consumer_name)
143+ web_root_uri = URI(service_root)
144+ web_root_uri.path = ""
145+ web_root_uri.host = web_root_uri.host.replace("api.", "", 1)
146+ web_root = str(web_root_uri.ensureSlash())
147+ authorization_url = credentials.get_request_token(web_root=web_root)
148+ webbrowser.open(authorization_url)
149+ print ("The authorization page (%s) should be opening in your "
150+ "browser. After you have authorized this program to "
151+ "access Launchpad on your behalf you should come back "
152+ "here and press <Enter> to finish the authentication "
153+ "process." % authorization_url)
154+ sys.stdin.readline()
155+ credentials.exchange_request_token_for_access_token(web_root)
156+ credentials.service_root = service_root
157+ return cls(credentials, service_root, cache, timeout, proxy_info)
158+>>>>>>> MERGE-SOURCE

Subscribers

People subscribed via source and target branches