Merge in better json error handling from Ali Afshar
diff --git a/apiclient/ext/authtools.py b/apiclient/ext/authtools.py
new file mode 100644
index 0000000..5398bd8
--- /dev/null
+++ b/apiclient/ext/authtools.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Command-line tools for authenticating via OAuth 1.0
+
+Do the OAuth 1.0 Three Legged Dance for
+a command line application. Stores the generated
+credentials in a common file that is used by
+other example apps in the same directory.
+"""
+
+__author__ = 'jcgregorio@google.com (Joe Gregorio)'
+__all__ = ["run"]
+
+import BaseHTTPServer
+import logging
+import pickle
+import socket
+import sys
+
+from optparse import OptionParser
+from apiclient.oauth import RequestError
+
+try:
+ from urlparse import parse_qsl
+except ImportError:
+ from cgi import parse_qsl
+
+
+class ClientRedirectServer(BaseHTTPServer.HTTPServer):
+ """A server to handle OAuth 1.0 redirects back to localhost.
+
+ Waits for a single request and parses the query parameters
+ into query_params and then stops serving.
+ """
+ query_params = {}
+
+
+class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ """A handler for OAuth 2.0 redirects back to localhost.
+
+ Waits for a single request and parses the query parameters
+ into the servers query_params and then stops serving.
+ """
+
+ def do_GET(s):
+ """Handle a GET request
+
+ Parses the query parameters and prints a message
+ if the flow has completed. Note that we can't detect
+ if an error occurred.
+ """
+ s.send_response(200)
+ s.send_header("Content-type", "text/html")
+ s.end_headers()
+ query = s.path.split('?', 1)[-1]
+ query = dict(parse_qsl(query))
+ s.server.query_params = query
+ s.wfile.write("<html><head><title>Authentication Status</title></head>")
+ s.wfile.write("<body><p>The authentication flow has completed.</p>")
+ s.wfile.write("</body></html>")
+
+ def log_message(self, format, *args):
+ """Do not log messages to stdout while running as command line program."""
+ pass
+
+
+def run(flow, filename):
+ """Core code for a command-line application.
+ """
+ parser = OptionParser()
+ parser.add_option("-f", "--file", dest="filename",
+ default=filename, help="write credentials to FILE", metavar="FILE")
+ parser.add_option("-p", "--no_local_web_server", dest="localhost",
+ action="store_false",
+ default=True,
+ help="Do not run a web server on localhost to handle redirect URIs")
+ parser.add_option("-w", "--local_web_server", dest="localhost",
+ action="store_true",
+ default=True,
+ help="Run a web server on localhost to handle redirect URIs")
+
+ (options, args) = parser.parse_args()
+
+ host_name = 'localhost'
+ port_numbers = [8080, 8090]
+ if options.localhost:
+ server_class = BaseHTTPServer.HTTPServer
+ try:
+ port_number = port_numbers[0]
+ httpd = server_class((host_name, port_number), ClientRedirectHandler)
+ except socket.error:
+ port_number = port_numbers[1]
+ try:
+ httpd = server_class((host_name, port_number), ClientRedirectHandler)
+ except socket.error:
+ options.localhost = False
+
+ if options.localhost:
+ oauth_callback = 'http://%s:%s/' % (host_name, port_number)
+ else:
+ oauth_callback = 'oob'
+ authorize_url = flow.step1_get_authorize_url(oauth_callback)
+
+ print 'Go to the following link in your browser:'
+ print authorize_url
+ print
+
+ if options.localhost:
+ httpd.handle_request()
+ if 'error' in httpd.query_params:
+ sys.exit('Authentication request was rejected.')
+ if 'oauth_verifier' in httpd.query_params:
+ code = httpd.query_params['oauth_verifier']
+ else:
+ accepted = 'n'
+ while accepted.lower() == 'n':
+ accepted = raw_input('Have you authorized me? (y/n) ')
+ code = raw_input('What is the verification code? ').strip()
+
+ try:
+ credentials = flow.step2_exchange(code)
+ except RequestError:
+ sys.exit('The authentication has failed.')
+
+ f = open(filename, 'w')
+ f.write(pickle.dumps(credentials))
+ f.close()
+ print "You have successfully authenticated."
diff --git a/apiclient/http.py b/apiclient/http.py
index d616c07..31a8fe8 100644
--- a/apiclient/http.py
+++ b/apiclient/http.py
@@ -12,8 +12,8 @@
'HttpRequest', 'RequestMockBuilder'
]
-from httplib2 import Response
-from apiclient.model import JsonModel
+import httplib2
+from model import JsonModel
class HttpRequest(object):
@@ -86,7 +86,7 @@
self.content = content
self.postproc = postproc
if resp is None:
- self.resp = Response({'status': 200, 'reason': 'OK'})
+ self.resp = httplib2.Response({'status': 200, 'reason': 'OK'})
if 'reason' in self.resp:
self.resp.reason = self.resp['reason']
diff --git a/docs/apiclient.json.html b/docs/apiclient.anyjson.html
similarity index 89%
rename from docs/apiclient.json.html
rename to docs/apiclient.anyjson.html
index 00c56ab..df64fcd 100644
--- a/docs/apiclient.json.html
+++ b/docs/apiclient.anyjson.html
@@ -1,14 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html><head><title>Python: module apiclient.json</title>
+<html><head><title>Python: module apiclient.anyjson</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom> <br>
-<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.json</strong></big></big></font></td
+<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.anyjson</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/json.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/json.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py</a></font></td></tr></table>
<p><tt>Utility module to import a JSON module<br>
<br>
Hides all the messy details of exactly where<br>
diff --git a/docs/apiclient.contrib.html b/docs/apiclient.contrib.html
index 513802a..488fdaa 100644
--- a/docs/apiclient.contrib.html
+++ b/docs/apiclient.contrib.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.contrib</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.discovery.html b/docs/apiclient.discovery.html
index 7936c9f..c7d0c54 100644
--- a/docs/apiclient.discovery.html
+++ b/docs/apiclient.discovery.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.discovery</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/discovery.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/discovery.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py</a></font></td></tr></table>
<p><tt>Client for discovery based APIs<br>
<br>
A client library for Google's discovery<br>
diff --git a/docs/apiclient.errors.html b/docs/apiclient.errors.html
index af69a51..73d3765 100644
--- a/docs/apiclient.errors.html
+++ b/docs/apiclient.errors.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.errors</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/errors.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/errors.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py</a></font></td></tr></table>
<p><tt>Errors for the library.<br>
<br>
All exceptions defined by the library<br>
diff --git a/docs/apiclient.ext.appengine.html b/docs/apiclient.ext.appengine.html
index 90cd6ca..a55ec26 100644
--- a/docs/apiclient.ext.appengine.html
+++ b/docs/apiclient.ext.appengine.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.appengine</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py</a></font></td></tr></table>
<p><tt>Utilities for Google App Engine<br>
<br>
Utilities for making it easier to use the<br>
diff --git a/docs/apiclient.ext.django_orm.html b/docs/apiclient.ext.django_orm.html
index 7832fcf..163f80e 100644
--- a/docs/apiclient.ext.django_orm.html
+++ b/docs/apiclient.ext.django_orm.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.django_orm</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.ext.html b/docs/apiclient.ext.html
index f9b24a0..3a77941 100644
--- a/docs/apiclient.ext.html
+++ b/docs/apiclient.ext.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.ext</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
diff --git a/docs/apiclient.html b/docs/apiclient.html
index 6b8dfbb..bf91ae5 100644
--- a/docs/apiclient.html
+++ b/docs/apiclient.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>apiclient</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/__init__.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/__init__.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
@@ -17,13 +17,14 @@
<font color="#ffffff" face="helvetica, arial"><big><strong>Package Contents</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt> </tt></td><td> </td>
-<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.contrib.html"><strong>contrib</strong> (package)</a><br>
+<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.anyjson.html">anyjson</a><br>
+<a href="apiclient.contrib.html"><strong>contrib</strong> (package)</a><br>
<a href="apiclient.discovery.html">discovery</a><br>
</td><td width="25%" valign=top><a href="apiclient.errors.html">errors</a><br>
<a href="apiclient.ext.html"><strong>ext</strong> (package)</a><br>
-</td><td width="25%" valign=top><a href="apiclient.http.html">http</a><br>
-<a href="apiclient.json.html">json</a><br>
-</td><td width="25%" valign=top><a href="apiclient.model.html">model</a><br>
+<a href="apiclient.http.html">http</a><br>
+</td><td width="25%" valign=top><a href="apiclient.json.html">json</a><br>
+<a href="apiclient.model.html">model</a><br>
<a href="apiclient.oauth.html">oauth</a><br>
-</td></tr></table></td></tr></table>
+</td><td width="25%" valign=top></td></tr></table></td></tr></table>
</body></html>
\ No newline at end of file
diff --git a/docs/apiclient.http.html b/docs/apiclient.http.html
index 9810823..19883b6 100644
--- a/docs/apiclient.http.html
+++ b/docs/apiclient.http.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.http</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/http.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/http.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py</a></font></td></tr></table>
<p><tt>Classes to encapsulate a single HTTP request.<br>
<br>
The classes implement a command pattern, with every<br>
diff --git a/docs/apiclient.model.html b/docs/apiclient.model.html
index 32ea8b9..585e348 100644
--- a/docs/apiclient.model.html
+++ b/docs/apiclient.model.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.model</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/model.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/model.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py</a></font></td></tr></table>
<p><tt>Model objects for requests and responses<br>
<br>
Each API may support one or more serializations, such<br>
diff --git a/docs/apiclient.oauth.html b/docs/apiclient.oauth.html
index e55af8c..e5efa2d 100644
--- a/docs/apiclient.oauth.html
+++ b/docs/apiclient.oauth.html
@@ -8,7 +8,7 @@
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.oauth</strong></big></big></font></td
><td align=right valign=bottom
-><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiary/apiclient/oauth.py">/usr/local/google/home/jcgregorio/projects/apiary/apiclient/oauth.py</a></font></td></tr></table>
+><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py</a></font></td></tr></table>
<p><tt>Utilities for OAuth.<br>
<br>
Utilities for making it easier to work with OAuth.</tt></p>
diff --git a/docs/build.sh b/docs/build.sh
index 1ea5060..0a08b71 100755
--- a/docs/build.sh
+++ b/docs/build.sh
@@ -9,8 +9,8 @@
# Notes: You may have to update the location of the
# App Engine library for your local system.
-set GOOGLE_APPENGINE=$HOME/projects/google_appengine/
-set DJANGO_SETTINGS_MODULE=fakesettings
-set PYTHONPATH=`pwd`/..:$GOOGLE_APPENGINE
+export GOOGLE_APPENGINE=$HOME/projects/google_appengine/
+export DJANGO_SETTINGS_MODULE=fakesettings
+export PYTHONPATH=`pwd`/..:$GOOGLE_APPENGINE
find ../apiclient/ -name "*.py" | sed "s/\/__init__.py//" | sed "s/\.py//" | sed "s/^\.\.\///" | sed "s#/#.#g" | xargs pydoc -w
diff --git a/functional_tests/test_services.py b/functional_tests/test_services.py
index 17ee601..37a005e 100644
--- a/functional_tests/test_services.py
+++ b/functional_tests/test_services.py
@@ -131,11 +131,11 @@
follower_count = following['totalResults']
self.assertTrue(follower_count > 10000, follower_count)
- def test_follower_count_is_zero_for_user_with_hidden_follower_count(self):
+ def test_follower_count_is_missing_for_user_with_hidden_follower_count(self):
buzz = build('buzz', 'v1')
following = buzz.people().list(userId='adewale', groupId='@followers').execute()
- self.assertEquals(0, following['totalResults'])
+ self.assertFalse('totalResults' in following)
class BuzzAuthenticatedFunctionalTest(unittest.TestCase):
diff --git a/oacurl.py b/oacurl.py
index 68b4ca9..64493b5 100644
--- a/oacurl.py
+++ b/oacurl.py
@@ -11,13 +11,18 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-import optparse
+from apiclient.discovery import build
+from apiclient.oauth import FlowThreeLegged
+
+import datetime
import httplib2
import logging
import oauth_wrap
+import optparse
import os
import sys
+
def load_properties_file(path):
properties = {}
for line in open(path):
@@ -29,6 +34,20 @@
properties[key.strip()] = value.strip()
return properties
+
+def save_properties(consumer_key, consumer_secret, token_key, token_secret, path):
+ file = open(path, 'w')
+
+ # File format and order is based on oacurl.java's defaults
+ now = datetime.datetime.today()
+ now_string = now.strftime('%a %b %d %H:%m:%S %Z %Y')
+ file.write('#%s\n' % now_string)
+ file.write('consumerSecret=%s\n' % consumer_secret)
+ file.write('accessToken=%s\n' % token_key)
+ file.write('consumerKey=%s\n' % consumer_key)
+ file.write('accessTokenSecret=%s\n' % token_secret)
+ file.close()
+
def fetch(url):
logging.debug('Now fetching: %s' % url)
@@ -38,6 +57,7 @@
print 'You are not logged in'
sys.exit(1)
+
properties = load_properties_file(path)
oauth_parameters = {
'consumer_key': properties['consumerKey'],
@@ -52,7 +72,48 @@
return response,content
+
+def buzz_login():
+ buzz_discovery = build("buzz", "v1").auth_discovery()
+
+ flow = FlowThreeLegged(buzz_discovery,
+ consumer_key='anonymous',
+ consumer_secret='anonymous',
+ user_agent='google-api-client-python-buzz-cmdline/1.0',
+ domain='anonymous',
+ scope='https://www.googleapis.com/auth/buzz',
+ xoauth_displayname='oacurl.py')
+
+ authorize_url = flow.step1_get_authorize_url()
+
+ print 'Go to the following link in your browser:'
+ print authorize_url
+ print
+
+ accepted = 'n'
+ while accepted.lower() == 'n':
+ accepted = raw_input('Have you authorized me? (y/n) ')
+ verification = raw_input('What is the verification code? ').strip()
+
+ credentials = flow.step2_exchange(verification)
+ path = os.path.expanduser('~/.oacurl.properties')
+ save_properties('anonymous', 'anonymous', credentials.token.key, credentials.token.secret,path)
+
+
+def generic_login():
+ #TODO(ade) Implement support for other services
+ print 'Support for services other than Buzz is not implemented yet. Sorry.'
+
+def login(options):
+ if options.buzz:
+ buzz_login()
+ else:
+ generic_login()
+
+
def get_command(args):
+ if args[0] == 'login':
+ return 'login'
if args[0] == 'fetch':
return 'fetch'
return None
@@ -69,6 +130,7 @@
parser.set_defaults(verbose=False)
parser.add_option('-v', '--verbose', action='store_true', dest='verbose')
parser.add_option('-q', '--quiet', action='store_false', dest='verbose')
+ parser.add_option('--buzz', action='store_true', dest='buzz')
(options, args) = parser.parse_args()
@@ -85,6 +147,10 @@
response, content = fetch(args[1])
print response
print content
+ return
+
+ if command == 'login':
+ login(options)
if __name__ == '__main__':
main()
\ No newline at end of file
diff --git a/runtests.py b/runtests.py
index ecd53b1..6fd426d 100644
--- a/runtests.py
+++ b/runtests.py
@@ -42,8 +42,11 @@
cleanup()
def main():
+ if '--help' in sys.argv:
+ print 'Usage: python runtests.py [--q|-quiet|--v|-verbose] [tests|functional_tests|contrib_tests]'
+ return
verbosity = 1
- if "-q" in sys.argv or '--quiet' in sys.argv:
+ if '-q' in sys.argv or '--quiet' in sys.argv:
verbosity = 0
if "-v" in sys.argv or '--verbose' in sys.argv:
verbosity = 2
diff --git a/samples/api-python-client-doc/main.py b/samples/api-python-client-doc/main.py
index d5ae558..14f222e 100755
--- a/samples/api-python-client-doc/main.py
+++ b/samples/api-python-client-doc/main.py
@@ -73,6 +73,7 @@
<li><a href='/diacritize/v1'>diacritize</a>
<li><a href='/translate/v2'>translate</a>
<li><a href='/prediction/v1.1'>prediction</a>
+ <li><a href='/shopping/v1'>shopping</a>
</ul>
""")
diff --git a/samples/buzz/three_legged_dance.py b/samples/buzz/three_legged_dance.py
index 9972455..2dc26e5 100644
--- a/samples/buzz/three_legged_dance.py
+++ b/samples/buzz/three_legged_dance.py
@@ -24,8 +24,8 @@
from apiclient.discovery import build
from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
-import pickle
buzz_discovery = build("buzz", "v1").auth_discovery()
@@ -37,19 +37,4 @@
scope='https://www.googleapis.com/auth/buzz',
xoauth_displayname='Google API Client Example App')
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
- accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('buzz.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'buzz.dat')
diff --git a/samples/latitude/three_legged_dance.py b/samples/latitude/three_legged_dance.py
index 56f4f59..45595bc 100644
--- a/samples/latitude/three_legged_dance.py
+++ b/samples/latitude/three_legged_dance.py
@@ -24,8 +24,7 @@
from apiclient.discovery import build
from apiclient.oauth import FlowThreeLegged
-
-import pickle
+from apiclient.ext.authtools import run
moderator_discovery = build("latitude", "v1").auth_discovery()
@@ -44,19 +43,4 @@
granularity='city'
)
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
- accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('latitude.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'latitude.dat')
diff --git a/samples/moderator/three_legged_dance.py b/samples/moderator/three_legged_dance.py
index fbc90ec..32e624d 100644
--- a/samples/moderator/three_legged_dance.py
+++ b/samples/moderator/three_legged_dance.py
@@ -24,8 +24,8 @@
from apiclient.discovery import build
from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
-import pickle
moderator_discovery = build("moderator", "v1").auth_discovery()
@@ -38,19 +38,4 @@
#scope='tag:google.com,2010:auth/moderator',
xoauth_displayname='Google API Client Example App')
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
- accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('moderator.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'moderator.dat')
diff --git a/samples/shopping/main.py b/samples/shopping/main.py
new file mode 100644
index 0000000..ce9057b
--- /dev/null
+++ b/samples/shopping/main.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python2.4
+# -*- coding: utf-8 -*-
+#
+# Copyright 2010 Google Inc. All Rights Reserved.
+
+"""Simple command-line example for The Google Search
+API for Shopping.
+
+Command-line application that does a search for products.
+"""
+
+__author__ = 'jcgregorio@google.com (Joe Gregorio)'
+
+from apiclient.discovery import build
+
+import pprint
+
+# Uncomment the next line to get very detailed logging
+# httplib2.debuglevel = 4
+
+
+def main():
+ p = build("shopping", "v1",
+ developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
+ res = p.products().list(
+ country='US',
+ source='public',
+ q='logitech revue'
+ ).execute()
+ pprint.pprint(res)
+
+if __name__ == '__main__':
+ main()
diff --git a/samples/threadqueue/three_legged_dance.py b/samples/threadqueue/three_legged_dance.py
index b833e3a..12c495b 100644
--- a/samples/threadqueue/three_legged_dance.py
+++ b/samples/threadqueue/three_legged_dance.py
@@ -24,8 +24,8 @@
from apiclient.discovery import build
from apiclient.oauth import FlowThreeLegged
+from apiclient.ext.authtools import run
-import pickle
moderator_discovery = build("moderator", "v1").auth_discovery()
@@ -38,19 +38,4 @@
#scope='tag:google.com,2010:auth/moderator',
xoauth_displayname='Google API Client Example App')
-authorize_url = flow.step1_get_authorize_url()
-
-print 'Go to the following link in your browser:'
-print authorize_url
-print
-
-accepted = 'n'
-while accepted.lower() == 'n':
- accepted = raw_input('Have you authorized me? (y/n) ')
-verification = raw_input('What is the verification code? ').strip()
-
-credentials = flow.step2_exchange(verification)
-
-f = open('moderator.dat', 'w')
-f.write(pickle.dumps(credentials))
-f.close()
+run(flow, 'moderator.dat')