Added TODO and did PEP 8 cleanup.
This commit is contained in:
		
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,2 +1,2 @@ | ||||
| default: | ||||
| 	python discovery.py | ||||
| pep8: | ||||
| 	find apiclient samples -name "*.py" | xargs pep8 --ignore=E111,E202 | ||||
|   | ||||
							
								
								
									
										21
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| TODO | ||||
| ==== | ||||
|  - Unit tests against copies of current discovery docs | ||||
|  | ||||
|  - Flag required parameters | ||||
|  | ||||
|  - Check the regex when accepting values | ||||
|  | ||||
|  - OAuth cmdline sample should start local http server to catch response. | ||||
|  | ||||
|  - 'Extra Discovery' for pagination | ||||
|  | ||||
|  - Implement requests as Command objects, either for immediate | ||||
|    execution, or for batching. | ||||
|  | ||||
|  - Requests for multiple APIs at one time. | ||||
|  | ||||
|  - 2.x and 3.x compatible | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -27,9 +27,12 @@ import simplejson | ||||
| import urlparse | ||||
| import uritemplate | ||||
|  | ||||
| class HttpError(Exception): pass | ||||
|  | ||||
| DISCOVERY_URI = 'http://www.googleapis.com/discovery/0.1/describe{?api,apiVersion}' | ||||
| class HttpError(Exception): | ||||
|   pass | ||||
|  | ||||
| DISCOVERY_URI = 'http://www.googleapis.com/discovery/0.1/describe' + | ||||
|   '{?api,apiVersion}' | ||||
|  | ||||
|  | ||||
| def key2method(key): | ||||
| @@ -73,6 +76,7 @@ def key2param(key): | ||||
|  | ||||
|  | ||||
| class JsonModel(object): | ||||
|  | ||||
|   def request(self, headers, params): | ||||
|     model = params.get('body', None) | ||||
|     query = '?alt=json&prettyprint=true' | ||||
| @@ -80,13 +84,14 @@ class JsonModel(object): | ||||
|     if model == None: | ||||
|       return (headers, params, query, None) | ||||
|     else: | ||||
|       model = {'data': model } | ||||
|       model = {'data': model} | ||||
|       headers['Content-Type'] = 'application/json' | ||||
|       del params['body'] | ||||
|       return (headers, params, query, simplejson.dumps(model)) | ||||
|  | ||||
|   def response(self, resp, content): | ||||
|     # Error handling is TBD | ||||
|     # Error handling is TBD, for example, do we retry | ||||
|     # for some operation/error combinations? | ||||
|     if resp.status < 300: | ||||
|       return simplejson.loads(content)['data'] | ||||
|     else: | ||||
| @@ -97,7 +102,7 @@ class JsonModel(object): | ||||
|  | ||||
|  | ||||
| def build(service, version, http=httplib2.Http(), | ||||
|     discoveryServiceUrl = DISCOVERY_URI, auth = None, model = JsonModel()): | ||||
|     discoveryServiceUrl=DISCOVERY_URI, auth=None, model=JsonModel()): | ||||
|   params = { | ||||
|       'api': service, | ||||
|       'apiVersion': version | ||||
| @@ -117,6 +122,7 @@ def build(service, version, http=httplib2.Http(), | ||||
|       self._model = model | ||||
|  | ||||
|   def createMethod(theclass, methodName, methodDesc): | ||||
|  | ||||
|     def method(self, **kwargs): | ||||
|       return createResource(self._http, self._baseUrl, self._model, | ||||
|           methodName, methodDesc) | ||||
|   | ||||
| @@ -10,38 +10,14 @@ A detailed description of discovery. | ||||
|  | ||||
| __author__ = 'jcgregorio@google.com (Joe Gregorio)' | ||||
|  | ||||
| # TODO | ||||
| # - Add normalize_ that converts max-results into MaxResults | ||||
| # | ||||
| # - Each 'resource' should be its own object accessible | ||||
| #   from the service object returned from discovery. | ||||
| # | ||||
| # - Methods can either execute immediately or return  | ||||
| #   RestRequest objects which can be batched.  | ||||
| # | ||||
| # - 'Body' parameter for non-GET requests  | ||||
| # | ||||
| # - 2.x and 3.x compatible | ||||
|  | ||||
| # JS also has the idea of a TransportRequest and a Transport. | ||||
| # The Transport has a doRequest() method that takes a request | ||||
| # and a callback function. | ||||
| #  | ||||
|  | ||||
|  | ||||
| # Discovery doc notes | ||||
| # - Which parameters are optional vs mandatory | ||||
| # - Is pattern a regex? | ||||
| # - Inconsistent naming max-results vs userId | ||||
|  | ||||
|  | ||||
| from apiclient.discovery import build | ||||
|  | ||||
| import httplib2 | ||||
| import simplejson | ||||
| import re | ||||
|  | ||||
| import oauth2 as oauth | ||||
| import re | ||||
| import simplejson | ||||
|  | ||||
|  | ||||
| def oauth_wrap(consumer, token, http): | ||||
|     """ | ||||
| @@ -51,7 +27,7 @@ def oauth_wrap(consumer, token, http): | ||||
|  | ||||
|     Returns: | ||||
|        A modified instance of http that was passed in. | ||||
|        | ||||
|  | ||||
|     Example: | ||||
|  | ||||
|       h = httplib2.Http() | ||||
| @@ -61,14 +37,15 @@ def oauth_wrap(consumer, token, http): | ||||
|     subclass of httplib2.Authenication because | ||||
|     it never gets passed the absolute URI, which is | ||||
|     needed for signing. So instead we have to overload | ||||
|     'request' with a closure that adds in the  | ||||
|     'request' with a closure that adds in the | ||||
|     Authorization header and then calls the original version | ||||
|     of 'request()'. | ||||
|     """ | ||||
|     request_orig = http.request | ||||
|     signer = oauth.SignatureMethod_HMAC_SHA1() | ||||
|  | ||||
|     def new_request(uri, method="GET", body=None, headers=None, redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None): | ||||
|     def new_request(uri, method="GET", body=None, headers=None, | ||||
|         redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None): | ||||
|       """Modify the request headers to add the appropriate | ||||
|       Authorization header.""" | ||||
|       req = oauth.Request.from_consumer_and_token( | ||||
| @@ -78,19 +55,23 @@ def oauth_wrap(consumer, token, http): | ||||
|         headers = {} | ||||
|       headers.update(req.to_header()) | ||||
|       headers['user-agent'] = 'jcgregorio-test-client' | ||||
|       return request_orig(uri, method, body, headers, redirections, connection_type) | ||||
|       return request_orig(uri, method, body, headers, | ||||
|           redirections, connection_type) | ||||
|  | ||||
|     http.request = new_request | ||||
|     return http | ||||
|  | ||||
|  | ||||
| def get_wrapped_http(): | ||||
|   f = open("oauth_token.dat", "r") | ||||
|   oauth_params = simplejson.loads(f.read()) | ||||
|  | ||||
|   consumer = oauth.Consumer(oauth_params['consumer_key'], oauth_params['consumer_secret']) | ||||
|   token = oauth.Token(oauth_params['oauth_token'], oauth_params['oauth_token_secret']) | ||||
|   consumer = oauth.Consumer( | ||||
|       oauth_params['consumer_key'], oauth_params['consumer_secret']) | ||||
|   token = oauth.Token( | ||||
|       oauth_params['oauth_token'], oauth_params['oauth_token_secret']) | ||||
|  | ||||
|   # Create a simple monkeypatch for httplib2.Http.request  | ||||
|   # Create a simple monkeypatch for httplib2.Http.request | ||||
|   # just adds in the oauth authorization header and then calls | ||||
|   # the original request(). | ||||
|   http = httplib2.Http() | ||||
| @@ -99,14 +80,14 @@ def get_wrapped_http(): | ||||
|  | ||||
| def main(): | ||||
|   http = get_wrapped_http() | ||||
|   p = build("buzz", "v1", http = http) | ||||
|   p = build("buzz", "v1", http=http) | ||||
|   activities = p.activities() | ||||
|   activitylist = activities.list(scope='@self', userId='@me') | ||||
|   print activitylist['items'][0]['title'] | ||||
|   activities.insert(userId='@me', body={ | ||||
|     'title': 'Testing insert', | ||||
|     'object': { | ||||
|       'content': u'Just a short note to show that insert is working. ☄',  | ||||
|       'content': u'Just a short note to show that insert is working. ☄', | ||||
|       'type': 'note'} | ||||
|     } | ||||
|   ) | ||||
|   | ||||
| @@ -9,7 +9,7 @@ try: | ||||
| except ImportError: | ||||
|     from cgi import parse_qs, parse_qsl | ||||
|  | ||||
| httplib2.debuglevel=4 | ||||
| httplib2.debuglevel = 4 | ||||
| headers = {"user-agent": "jcgregorio-buzz-client", | ||||
|     'content-type': 'application/x-www-form-urlencoded' | ||||
|     } | ||||
| @@ -17,18 +17,22 @@ headers = {"user-agent": "jcgregorio-buzz-client", | ||||
| consumer_key = 'anonymous' | ||||
| consumer_secret = 'anonymous' | ||||
|  | ||||
| request_token_url = 'https://www.google.com/accounts/OAuthGetRequestToken?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
| access_token_url = 'https://www.google.com/accounts/OAuthGetAccessToken?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
| authorize_url = 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
| request_token_url = 'https://www.google.com/accounts/OAuthGetRequestToken' + | ||||
|   '?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
| access_token_url = 'https://www.google.com/accounts/OAuthGetAccessToken' + | ||||
|   '?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
| authorize_url = 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken' + | ||||
|   '?domain=anonymous&scope=https://www.googleapis.com/auth/buzz' | ||||
|  | ||||
| consumer = oauth.Consumer(consumer_key, consumer_secret) | ||||
| client = oauth.Client(consumer) | ||||
|  | ||||
| # Step 1: Get a request token. This is a temporary token that is used for  | ||||
| # having the user authorize an access token and to sign the request to obtain  | ||||
| # Step 1: Get a request token. This is a temporary token that is used for | ||||
| # having the user authorize an access token and to sign the request to obtain | ||||
| # said access token. | ||||
|  | ||||
| resp, content = client.request(request_token_url, "POST", headers=headers, body="oauth_callback=oob") | ||||
| resp, content = client.request(request_token_url, "POST", headers=headers, | ||||
|     body="oauth_callback=oob") | ||||
| if resp['status'] != '200': | ||||
|   print content | ||||
|   raise Exception("Invalid response %s." % resp['status']) | ||||
| @@ -38,9 +42,9 @@ request_token = dict(parse_qsl(content)) | ||||
| print "Request Token:" | ||||
| print "    - oauth_token        = %s" % request_token['oauth_token'] | ||||
| print "    - oauth_token_secret = %s" % request_token['oauth_token_secret'] | ||||
| print  | ||||
| print | ||||
|  | ||||
| # Step 2: Redirect to the provider. Since this is a CLI script we do not  | ||||
| # Step 2: Redirect to the provider. Since this is a CLI script we do not | ||||
| # redirect. In a web application you would redirect the user to the URL | ||||
| # below. | ||||
|  | ||||
| @@ -56,20 +60,21 @@ authorize_url = urlparse.urlunparse(url) | ||||
|  | ||||
| print "Go to the following link in your browser:" | ||||
| print authorize_url | ||||
| print  | ||||
| print | ||||
|  | ||||
| # After the user has granted access to you, the consumer, the provider will | ||||
| # redirect you to whatever URL you have told them to redirect to. You can  | ||||
| # redirect you to whatever URL you have told them to redirect to. You can | ||||
| # usually define this in the oauth_callback argument as well. | ||||
| accepted = 'n' | ||||
| while accepted.lower() == 'n': | ||||
|     accepted = raw_input('Have you authorized me? (y/n) ') | ||||
| oauth_verifier = raw_input('What is the PIN? ') | ||||
| oauth_verifier = raw_input('What is the PIN? ').strip() | ||||
|  | ||||
|  | ||||
| # Step 3: Once the consumer has redirected the user back to the oauth_callback | ||||
| # URL you can request the access token the user has approved. You use the  | ||||
| # URL you can request the access token the user has approved. You use the | ||||
| # request token to sign this request. After this is done you throw away the | ||||
| # request token and use the access token returned. You should store this  | ||||
| # request token and use the access token returned. You should store this | ||||
| # access token somewhere safe, like a database, for future use. | ||||
| token = oauth.Token(request_token['oauth_token'], | ||||
|     request_token['oauth_token_secret']) | ||||
| @@ -83,13 +88,14 @@ print "Access Token:" | ||||
| print "    - oauth_token        = %s" % access_token['oauth_token'] | ||||
| print "    - oauth_token_secret = %s" % access_token['oauth_token_secret'] | ||||
| print | ||||
| print "You may now access protected resources using the access tokens above."  | ||||
| print "You may now access protected resources using the access tokens above." | ||||
| print | ||||
|  | ||||
| d = dict( | ||||
|   consumer_key = 'anonymous', | ||||
|   consumer_secret = 'anonymous' | ||||
|   consumer_key='anonymous', | ||||
|   consumer_secret='anonymous' | ||||
|     ) | ||||
|  | ||||
| d.update(access_token) | ||||
|  | ||||
| f = open("oauth_token.dat", "w") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Joe Gregorio
					Joe Gregorio