Added mocks for the generated service objects. Also fixed a bunch of formatting.
This commit is contained in:
@@ -32,31 +32,15 @@ try:
|
|||||||
from urlparse import parse_qsl
|
from urlparse import parse_qsl
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from cgi import parse_qsl
|
from cgi import parse_qsl
|
||||||
|
|
||||||
from apiclient.http import HttpRequest
|
from apiclient.http import HttpRequest
|
||||||
from apiclient.json import simplejson
|
from apiclient.json import simplejson
|
||||||
|
from apiclient.model import JsonModel
|
||||||
|
from apiclient.errors import HttpError
|
||||||
|
from apiclient.errors import UnknownLinkType
|
||||||
|
|
||||||
URITEMPLATE = re.compile('{[^}]*}')
|
URITEMPLATE = re.compile('{[^}]*}')
|
||||||
VARNAME = re.compile('[a-zA-Z0-9_-]+')
|
VARNAME = re.compile('[a-zA-Z0-9_-]+')
|
||||||
|
|
||||||
class Error(Exception):
|
|
||||||
"""Base error for this module."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class HttpError(Error):
|
|
||||||
"""HTTP data was invalid or unexpected."""
|
|
||||||
def __init__(self, resp, detail):
|
|
||||||
self.resp = resp
|
|
||||||
self.detail = detail
|
|
||||||
def __str__(self):
|
|
||||||
return self.detail
|
|
||||||
|
|
||||||
|
|
||||||
class UnknownLinkType(Error):
|
|
||||||
"""Link type unknown or unexpected."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
DISCOVERY_URI = ('https://www.googleapis.com/discovery/v0.2beta1/describe/'
|
DISCOVERY_URI = ('https://www.googleapis.com/discovery/v0.2beta1/describe/'
|
||||||
'{api}/{apiVersion}')
|
'{api}/{apiVersion}')
|
||||||
|
|
||||||
@@ -78,52 +62,12 @@ def key2param(key):
|
|||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
|
|
||||||
class JsonModel(object):
|
def build(serviceName, version,
|
||||||
|
http=None,
|
||||||
def request(self, headers, path_params, query_params, body_value):
|
discoveryServiceUrl=DISCOVERY_URI,
|
||||||
query = self.build_query(query_params)
|
developerKey=None,
|
||||||
headers['accept'] = 'application/json'
|
model=JsonModel(),
|
||||||
if 'user-agent' in headers:
|
requestBuilder=HttpRequest):
|
||||||
headers['user-agent'] += ' '
|
|
||||||
else:
|
|
||||||
headers['user-agent'] = ''
|
|
||||||
headers['user-agent'] += 'google-api-python-client/1.0'
|
|
||||||
if body_value is None:
|
|
||||||
return (headers, path_params, query, None)
|
|
||||||
else:
|
|
||||||
headers['content-type'] = 'application/json'
|
|
||||||
return (headers, path_params, query, simplejson.dumps(body_value))
|
|
||||||
|
|
||||||
def build_query(self, params):
|
|
||||||
params.update({'alt': 'json'})
|
|
||||||
astuples = []
|
|
||||||
for key, value in params.iteritems():
|
|
||||||
if getattr(value, 'encode', False) and callable(value.encode):
|
|
||||||
value = value.encode('utf-8')
|
|
||||||
astuples.append((key, value))
|
|
||||||
return '?' + urllib.urlencode(astuples)
|
|
||||||
|
|
||||||
def response(self, resp, content):
|
|
||||||
# Error handling is TBD, for example, do we retry
|
|
||||||
# for some operation/error combinations?
|
|
||||||
if resp.status < 300:
|
|
||||||
if resp.status == 204:
|
|
||||||
# A 204: No Content response should be treated differently to all the other success states
|
|
||||||
return simplejson.loads('{}')
|
|
||||||
body = simplejson.loads(content)
|
|
||||||
if isinstance(body, dict) and 'data' in body:
|
|
||||||
body = body['data']
|
|
||||||
return body
|
|
||||||
else:
|
|
||||||
logging.debug('Content from bad request was: %s' % content)
|
|
||||||
if resp.get('content-type', '').startswith('application/json'):
|
|
||||||
raise HttpError(resp, simplejson.loads(content)['error'])
|
|
||||||
else:
|
|
||||||
raise HttpError(resp, '%d %s' % (resp.status, resp.reason))
|
|
||||||
|
|
||||||
|
|
||||||
def build(serviceName, version, http=None,
|
|
||||||
discoveryServiceUrl=DISCOVERY_URI, developerKey=None, model=JsonModel()):
|
|
||||||
params = {
|
params = {
|
||||||
'api': serviceName,
|
'api': serviceName,
|
||||||
'apiVersion': version
|
'apiVersion': version
|
||||||
@@ -159,6 +103,7 @@ def build(serviceName, version, http=None,
|
|||||||
self._baseUrl = base
|
self._baseUrl = base
|
||||||
self._model = model
|
self._model = model
|
||||||
self._developerKey = developerKey
|
self._developerKey = developerKey
|
||||||
|
self._requestBuilder = requestBuilder
|
||||||
|
|
||||||
def auth_discovery(self):
|
def auth_discovery(self):
|
||||||
return auth_discovery
|
return auth_discovery
|
||||||
@@ -167,7 +112,8 @@ def build(serviceName, version, http=None,
|
|||||||
|
|
||||||
def method(self):
|
def method(self):
|
||||||
return createResource(self._http, self._baseUrl, self._model,
|
return createResource(self._http, self._baseUrl, self._model,
|
||||||
methodName, self._developerKey, methodDesc, futureDesc)
|
self._requestBuilder, methodName,
|
||||||
|
self._developerKey, methodDesc, futureDesc)
|
||||||
|
|
||||||
setattr(method, '__doc__', 'A description of how to use this function')
|
setattr(method, '__doc__', 'A description of how to use this function')
|
||||||
setattr(method, '__is_resource__', True)
|
setattr(method, '__is_resource__', True)
|
||||||
@@ -178,8 +124,8 @@ def build(serviceName, version, http=None,
|
|||||||
return Service()
|
return Service()
|
||||||
|
|
||||||
|
|
||||||
def createResource(http, baseUrl, model, resourceName, developerKey,
|
def createResource(http, baseUrl, model, requestBuilder, resourceName,
|
||||||
resourceDesc, futureDesc):
|
developerKey, resourceDesc, futureDesc):
|
||||||
|
|
||||||
class Resource(object):
|
class Resource(object):
|
||||||
"""A class for interacting with a resource."""
|
"""A class for interacting with a resource."""
|
||||||
@@ -189,11 +135,13 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
self._baseUrl = baseUrl
|
self._baseUrl = baseUrl
|
||||||
self._model = model
|
self._model = model
|
||||||
self._developerKey = developerKey
|
self._developerKey = developerKey
|
||||||
|
self._requestBuilder = requestBuilder
|
||||||
|
|
||||||
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||||
pathUrl = methodDesc['restPath']
|
pathUrl = methodDesc['restPath']
|
||||||
pathUrl = re.sub(r'\{', r'{+', pathUrl)
|
pathUrl = re.sub(r'\{', r'{+', pathUrl)
|
||||||
httpMethod = methodDesc['httpMethod']
|
httpMethod = methodDesc['httpMethod']
|
||||||
|
methodId = methodDesc['rpcMethod']
|
||||||
|
|
||||||
argmap = {}
|
argmap = {}
|
||||||
if httpMethod in ['PUT', 'POST']:
|
if httpMethod in ['PUT', 'POST']:
|
||||||
@@ -257,18 +205,23 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
headers, params, query, body = self._model.request(headers,
|
headers, params, query, body = self._model.request(headers,
|
||||||
actual_path_params, actual_query_params, body_value)
|
actual_path_params, actual_query_params, body_value)
|
||||||
|
|
||||||
# TODO(ade) This exists to fix a bug in V1 of the Buzz discovery document.
|
# TODO(ade) This exists to fix a bug in V1 of the Buzz discovery
|
||||||
# Base URLs should not contain any path elements. If they do then urlparse.urljoin will strip them out
|
# document. Base URLs should not contain any path elements. If they do
|
||||||
# This results in an incorrect URL which returns a 404
|
# then urlparse.urljoin will strip them out This results in an incorrect
|
||||||
|
# URL which returns a 404
|
||||||
url_result = urlparse.urlsplit(self._baseUrl)
|
url_result = urlparse.urlsplit(self._baseUrl)
|
||||||
new_base_url = url_result.scheme + '://' + url_result.netloc
|
new_base_url = url_result.scheme + '://' + url_result.netloc
|
||||||
|
|
||||||
expanded_url = uritemplate.expand(pathUrl, params)
|
expanded_url = uritemplate.expand(pathUrl, params)
|
||||||
url = urlparse.urljoin(new_base_url, url_result.path + expanded_url + query)
|
url = urlparse.urljoin(new_base_url,
|
||||||
|
url_result.path + expanded_url + query)
|
||||||
|
|
||||||
logging.info('URL being requested: %s' % url)
|
logging.info('URL being requested: %s' % url)
|
||||||
return HttpRequest(self._http, url, method=httpMethod, body=body,
|
return self._requestBuilder(self._http, url,
|
||||||
headers=headers, postproc=self._model.response)
|
method=httpMethod, body=body,
|
||||||
|
headers=headers,
|
||||||
|
postproc=self._model.response,
|
||||||
|
methodId=methodId)
|
||||||
|
|
||||||
docs = ['A description of how to use this function\n\n']
|
docs = ['A description of how to use this function\n\n']
|
||||||
for arg in argmap.iterkeys():
|
for arg in argmap.iterkeys():
|
||||||
@@ -280,7 +233,8 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
setattr(method, '__doc__', ''.join(docs))
|
setattr(method, '__doc__', ''.join(docs))
|
||||||
setattr(theclass, methodName, method)
|
setattr(theclass, methodName, method)
|
||||||
|
|
||||||
def createNextMethod(theclass, methodName, methodDesc):
|
def createNextMethod(theclass, methodName, methodDesc, futureDesc):
|
||||||
|
methodId = methodDesc['rpcMethod'] + '.next'
|
||||||
|
|
||||||
def method(self, previous):
|
def method(self, previous):
|
||||||
"""
|
"""
|
||||||
@@ -291,12 +245,12 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
Returns None if there are no more items in
|
Returns None if there are no more items in
|
||||||
the collection.
|
the collection.
|
||||||
"""
|
"""
|
||||||
if methodDesc['type'] != 'uri':
|
if futureDesc['type'] != 'uri':
|
||||||
raise UnknownLinkType(methodDesc['type'])
|
raise UnknownLinkType(futureDesc['type'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p = previous
|
p = previous
|
||||||
for key in methodDesc['location']:
|
for key in futureDesc['location']:
|
||||||
p = p[key]
|
p = p[key]
|
||||||
url = p
|
url = p
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
@@ -315,8 +269,10 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
logging.info('URL being requested: %s' % url)
|
logging.info('URL being requested: %s' % url)
|
||||||
resp, content = self._http.request(url, method='GET', headers=headers)
|
resp, content = self._http.request(url, method='GET', headers=headers)
|
||||||
|
|
||||||
return HttpRequest(self._http, url, method='GET',
|
return self._requestBuilder(self._http, url, method='GET',
|
||||||
headers=headers, postproc=self._model.response)
|
headers=headers,
|
||||||
|
postproc=self._model.response,
|
||||||
|
methodId=methodId)
|
||||||
|
|
||||||
setattr(theclass, methodName, method)
|
setattr(theclass, methodName, method)
|
||||||
|
|
||||||
@@ -331,6 +287,7 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
|
|
||||||
# Add in nested resources
|
# Add in nested resources
|
||||||
if 'resources' in resourceDesc:
|
if 'resources' in resourceDesc:
|
||||||
|
|
||||||
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||||
|
|
||||||
def method(self):
|
def method(self):
|
||||||
@@ -346,12 +303,15 @@ def createResource(http, baseUrl, model, resourceName, developerKey,
|
|||||||
future = futureDesc['resources'].get(methodName, {})
|
future = futureDesc['resources'].get(methodName, {})
|
||||||
else:
|
else:
|
||||||
future = {}
|
future = {}
|
||||||
createMethod(Resource, methodName, methodDesc, future.get(methodName, {}))
|
createMethod(Resource, methodName, methodDesc,
|
||||||
|
future.get(methodName, {}))
|
||||||
|
|
||||||
# Add <m>_next() methods to Resource
|
# Add <m>_next() methods to Resource
|
||||||
if futureDesc:
|
if futureDesc:
|
||||||
for methodName, methodDesc in futureDesc['methods'].iteritems():
|
for methodName, methodDesc in futureDesc['methods'].iteritems():
|
||||||
if 'next' in methodDesc and methodName in resourceDesc['methods']:
|
if 'next' in methodDesc and methodName in resourceDesc['methods']:
|
||||||
createNextMethod(Resource, methodName + "_next", methodDesc['next'])
|
createNextMethod(Resource, methodName + "_next",
|
||||||
|
resourceDesc['methods'][methodName],
|
||||||
|
methodDesc['next'])
|
||||||
|
|
||||||
return Resource()
|
return Resource()
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class OAuthCredentialsField(models.Field):
|
class OAuthCredentialsField(models.Field):
|
||||||
|
|
||||||
__metaclass__ = models.SubfieldBase
|
__metaclass__ = models.SubfieldBase
|
||||||
@@ -17,6 +18,7 @@ class OAuthCredentialsField(models.Field):
|
|||||||
def get_db_prep_value(self, value):
|
def get_db_prep_value(self, value):
|
||||||
return base64.b64encode(pickle.dumps(value))
|
return base64.b64encode(pickle.dumps(value))
|
||||||
|
|
||||||
|
|
||||||
class FlowThreeLeggedField(models.Field):
|
class FlowThreeLeggedField(models.Field):
|
||||||
|
|
||||||
__metaclass__ = models.SubfieldBase
|
__metaclass__ = models.SubfieldBase
|
||||||
|
@@ -1,19 +1,42 @@
|
|||||||
# Copyright 2010 Google Inc. All Rights Reserved.
|
# Copyright 2010 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
"""One-line documentation for http module.
|
"""Classes to encapsulate a single HTTP request.
|
||||||
|
|
||||||
A detailed description of http.
|
The classes implement a command pattern, with every
|
||||||
|
object supporting an execute() method that does the
|
||||||
|
actuall HTTP request.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||||
|
__all__ = [
|
||||||
|
'HttpRequest', 'RequestMockBuilder'
|
||||||
|
]
|
||||||
|
|
||||||
|
from httplib2 import Response
|
||||||
|
from apiclient.model import JsonModel
|
||||||
|
|
||||||
|
|
||||||
class HttpRequest(object):
|
class HttpRequest(object):
|
||||||
"""Encapsulate an HTTP request.
|
"""Encapsulates a single HTTP request.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, http, uri, method="GET", body=None, headers=None,
|
def __init__(self, http, uri, method="GET", body=None, headers=None,
|
||||||
postproc=None):
|
postproc=None, methodId=None):
|
||||||
|
"""Constructor for an HttpRequest.
|
||||||
|
|
||||||
|
Only http and uri are required.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
http: httplib2.Http, the transport object to use to make a request
|
||||||
|
uri: string, the absolute URI to send the request to
|
||||||
|
method: string, the HTTP method to use
|
||||||
|
body: string, the request body of the HTTP request
|
||||||
|
headers: dict, the HTTP request headers
|
||||||
|
postproc: callable, called on the HTTP response and content to transform
|
||||||
|
it into a data object before returning, or raising an exception
|
||||||
|
on an error.
|
||||||
|
methodId: string, a unique identifier for the API method being called.
|
||||||
|
"""
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
self.method = method
|
self.method = method
|
||||||
self.body = body
|
self.body = body
|
||||||
@@ -24,8 +47,17 @@ class HttpRequest(object):
|
|||||||
def execute(self, http=None):
|
def execute(self, http=None):
|
||||||
"""Execute the request.
|
"""Execute the request.
|
||||||
|
|
||||||
If an http object is passed in it is used instead of the
|
Args:
|
||||||
httplib2.Http object that the request was constructed with.
|
http: httplib2.Http, an http object to be used in place of the
|
||||||
|
one the HttpRequest request object was constructed with.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A deserialized object model of the response body as determined
|
||||||
|
by the postproc.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
apiclient.errors.HttpError if the response was not a 2xx.
|
||||||
|
httplib2.Error if a transport error has occured.
|
||||||
"""
|
"""
|
||||||
if http is None:
|
if http is None:
|
||||||
http = self.http
|
http = self.http
|
||||||
@@ -33,3 +65,87 @@ class HttpRequest(object):
|
|||||||
body=self.body,
|
body=self.body,
|
||||||
headers=self.headers)
|
headers=self.headers)
|
||||||
return self.postproc(resp, content)
|
return self.postproc(resp, content)
|
||||||
|
|
||||||
|
|
||||||
|
class HttpRequestMock(object):
|
||||||
|
"""Mock of HttpRequest.
|
||||||
|
|
||||||
|
Do not construct directly, instead use RequestMockBuilder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, resp, content, postproc):
|
||||||
|
"""Constructor for HttpRequestMock
|
||||||
|
|
||||||
|
Args:
|
||||||
|
resp: httplib2.Response, the response to emulate coming from the request
|
||||||
|
content: string, the response body
|
||||||
|
postproc: callable, the post processing function usually supplied by
|
||||||
|
the model class. See model.JsonModel.response() as an example.
|
||||||
|
"""
|
||||||
|
self.resp = resp
|
||||||
|
self.content = content
|
||||||
|
self.postproc = postproc
|
||||||
|
if resp is None:
|
||||||
|
self.resp = Response({'status': 200, 'reason': 'OK'})
|
||||||
|
if 'reason' in self.resp:
|
||||||
|
self.resp.reason = self.resp['reason']
|
||||||
|
|
||||||
|
def execute(self, http=None):
|
||||||
|
"""Execute the request.
|
||||||
|
|
||||||
|
Same behavior as HttpRequest.execute(), but the response is
|
||||||
|
mocked and not really from an HTTP request/response.
|
||||||
|
"""
|
||||||
|
return self.postproc(self.resp, self.content)
|
||||||
|
|
||||||
|
|
||||||
|
class RequestMockBuilder(object):
|
||||||
|
"""A simple mock of HttpRequest
|
||||||
|
|
||||||
|
Pass in a dictionary to the constructor that maps request methodIds to
|
||||||
|
tuples of (httplib2.Response, content) that should be returned when that
|
||||||
|
method is called. None may also be passed in for the httplib2.Response, in
|
||||||
|
which case a 200 OK response will be generated.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
response = '{"data": {"id": "tag:google.c...'
|
||||||
|
requestBuilder = RequestMockBuilder(
|
||||||
|
{
|
||||||
|
'chili.activities.get': (None, response),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
apiclient.discovery.build("buzz", "v1", requestBuilder=requestBuilder)
|
||||||
|
|
||||||
|
Methods that you do not supply a response for will return a
|
||||||
|
200 OK with an empty string as the response content. The methodId
|
||||||
|
is taken from the rpcName in the discovery document.
|
||||||
|
|
||||||
|
For more details see the project wiki.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, responses):
|
||||||
|
"""Constructor for RequestMockBuilder
|
||||||
|
|
||||||
|
The constructed object should be a callable object
|
||||||
|
that can replace the class HttpResponse.
|
||||||
|
|
||||||
|
responses - A dictionary that maps methodIds into tuples
|
||||||
|
of (httplib2.Response, content). The methodId
|
||||||
|
comes from the 'rpcName' field in the discovery
|
||||||
|
document.
|
||||||
|
"""
|
||||||
|
self.responses = responses
|
||||||
|
|
||||||
|
def __call__(self, http, uri, method="GET", body=None, headers=None,
|
||||||
|
postproc=None, methodId=None):
|
||||||
|
"""Implements the callable interface that discovery.build() expects
|
||||||
|
of requestBuilder, which is to build an object compatible with
|
||||||
|
HttpRequest.execute(). See that method for the description of the
|
||||||
|
parameters and the expected response.
|
||||||
|
"""
|
||||||
|
if methodId in self.responses:
|
||||||
|
resp, content = self.responses[methodId]
|
||||||
|
return HttpRequestMock(resp, content, postproc)
|
||||||
|
else:
|
||||||
|
model = JsonModel()
|
||||||
|
return HttpRequestMock(None, '{}', model.response)
|
||||||
|
@@ -131,9 +131,9 @@ class OAuthCredentials(Credentials):
|
|||||||
headers = {}
|
headers = {}
|
||||||
headers.update(req.to_header())
|
headers.update(req.to_header())
|
||||||
if 'user-agent' in headers:
|
if 'user-agent' in headers:
|
||||||
headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
|
headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
|
||||||
else:
|
else:
|
||||||
headers['user-agent'] = self.user_agent
|
headers['user-agent'] = self.user_agent
|
||||||
return request_orig(uri, method, body, headers,
|
return request_orig(uri, method, body, headers,
|
||||||
redirections, connection_type)
|
redirections, connection_type)
|
||||||
|
|
||||||
|
@@ -28,7 +28,11 @@ from google.appengine.ext import webapp
|
|||||||
from google.appengine.ext.webapp import util
|
from google.appengine.ext.webapp import util
|
||||||
|
|
||||||
# Replicate render_doc here from pydoc.py as it isn't available in Python 2.5
|
# Replicate render_doc here from pydoc.py as it isn't available in Python 2.5
|
||||||
class _OldStyleClass: pass
|
|
||||||
|
|
||||||
|
class _OldStyleClass:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
|
def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
|
||||||
"""Render text documentation, given an object or a path to an object."""
|
"""Render text documentation, given an object or a path to an object."""
|
||||||
@@ -77,7 +81,8 @@ class ServiceHandler(webapp.RequestHandler):
|
|||||||
|
|
||||||
def get(self, service_name, version):
|
def get(self, service_name, version):
|
||||||
service = build(service_name, version)
|
service = build(service_name, version)
|
||||||
page = "<p><a href='/'>Home</a></p><pre>%s</pre>" % pydoc.plain(render_doc(service))
|
page = "<p><a href='/'>Home</a></p><pre>%s</pre>" % (
|
||||||
|
pydoc.plain(render_doc(service)),)
|
||||||
|
|
||||||
collections = []
|
collections = []
|
||||||
for name in dir(service):
|
for name in dir(service):
|
||||||
@@ -85,7 +90,8 @@ class ServiceHandler(webapp.RequestHandler):
|
|||||||
collections.append(name)
|
collections.append(name)
|
||||||
|
|
||||||
for name in collections:
|
for name in collections:
|
||||||
page = re.sub('(%s) =' % name, r'<a href="/%s/%s/%s">\1</a> =' % (service_name, version, name), page)
|
page = re.sub('(%s) =' % name, r'<a href="/%s/%s/%s">\1</a> =' % (
|
||||||
|
service_name, version, name), page)
|
||||||
|
|
||||||
self.response.out.write(page)
|
self.response.out.write(page)
|
||||||
|
|
||||||
@@ -101,16 +107,19 @@ class CollectionHandler(webapp.RequestHandler):
|
|||||||
service = getattr(service, method)()
|
service = getattr(service, method)()
|
||||||
method = getattr(service, path[-1])
|
method = getattr(service, path[-1])
|
||||||
obj = method()
|
obj = method()
|
||||||
page = "<p><a href='/'>Home</a></p><pre>%s</pre>" % pydoc.plain(render_doc(obj))
|
page = "<p><a href='/'>Home</a></p><pre>%s</pre>" % (
|
||||||
|
pydoc.plain(render_doc(obj)),)
|
||||||
|
|
||||||
if hasattr(method, '__is_resource__'):
|
if hasattr(method, '__is_resource__'):
|
||||||
collections = []
|
collections = []
|
||||||
for name in dir(obj):
|
for name in dir(obj):
|
||||||
if not "_" in name and callable(getattr(obj, name)) and hasattr(getattr(obj, name), '__is_resource__'):
|
if not "_" in name and callable(getattr(obj, name)) and hasattr(
|
||||||
|
getattr(obj, name), '__is_resource__'):
|
||||||
collections.append(name)
|
collections.append(name)
|
||||||
|
|
||||||
for name in collections:
|
for name in collections:
|
||||||
page = re.sub('(%s) =' % name, r'<a href="/%s/%s/%s">\1</a> =' % (service_name, version, collection + "/" + name), page)
|
page = re.sub('(%s) =' % name, r'<a href="/%s/%s/%s">\1</a> =' % (
|
||||||
|
service_name, version, collection + "/" + name), page)
|
||||||
|
|
||||||
self.response.out.write(page)
|
self.response.out.write(page)
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ import pprint
|
|||||||
# Uncomment the next line to get very detailed logging
|
# Uncomment the next line to get very detailed logging
|
||||||
#httplib2.debuglevel = 4
|
#httplib2.debuglevel = 4
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
f = open("buzz.dat", "r")
|
f = open("buzz.dat", "r")
|
||||||
credentials = pickle.loads(f.read())
|
credentials = pickle.loads(f.read())
|
||||||
|
@@ -17,9 +17,10 @@ import pprint
|
|||||||
# Uncomment the next line to get very detailed logging
|
# Uncomment the next line to get very detailed logging
|
||||||
# httplib2.debuglevel = 4
|
# httplib2.debuglevel = 4
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
p = build("customsearch", "v1", developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
def main():
|
||||||
|
p = build("customsearch", "v1",
|
||||||
|
developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
||||||
res = p.cse().list(
|
res = p.cse().list(
|
||||||
q='lectures',
|
q='lectures',
|
||||||
cx='017576662512468239146:omuauf_lfve',
|
cx='017576662512468239146:omuauf_lfve',
|
||||||
|
@@ -20,9 +20,10 @@ import pprint
|
|||||||
# Uncomment the next line to get very detailed logging
|
# Uncomment the next line to get very detailed logging
|
||||||
# httplib2.debuglevel = 4
|
# httplib2.debuglevel = 4
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
p = build("diacritize", "v1", developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
def main():
|
||||||
|
p = build("diacritize", "v1",
|
||||||
|
developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
||||||
print p.diacritize().corpus().get(
|
print p.diacritize().corpus().get(
|
||||||
lang='ar',
|
lang='ar',
|
||||||
last_letter='false',
|
last_letter='false',
|
||||||
|
@@ -8,22 +8,26 @@ from django.db import models
|
|||||||
from apiclient.ext.django_orm import FlowThreeLeggedField
|
from apiclient.ext.django_orm import FlowThreeLeggedField
|
||||||
from apiclient.ext.django_orm import OAuthCredentialsField
|
from apiclient.ext.django_orm import OAuthCredentialsField
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
|
|
||||||
# The Flow could also be stored in memcache since it is short lived.
|
# The Flow could also be stored in memcache since it is short lived.
|
||||||
|
|
||||||
|
|
||||||
class Flow(models.Model):
|
class Flow(models.Model):
|
||||||
id = models.ForeignKey(User, primary_key=True)
|
id = models.ForeignKey(User, primary_key=True)
|
||||||
flow = FlowThreeLeggedField()
|
flow = FlowThreeLeggedField()
|
||||||
|
|
||||||
|
|
||||||
class Credential(models.Model):
|
class Credential(models.Model):
|
||||||
id = models.ForeignKey(User, primary_key=True)
|
id = models.ForeignKey(User, primary_key=True)
|
||||||
credential = OAuthCredentialsField()
|
credential = OAuthCredentialsField()
|
||||||
|
|
||||||
|
|
||||||
class CredentialAdmin(admin.ModelAdmin):
|
class CredentialAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FlowAdmin(admin.ModelAdmin):
|
class FlowAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Credential, CredentialAdmin)
|
admin.site.register(Credential, CredentialAdmin)
|
||||||
admin.site.register(Flow, FlowAdmin)
|
admin.site.register(Flow, FlowAdmin)
|
||||||
|
@@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
|||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
@@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
|||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
@@ -11,9 +11,9 @@ from apiclient.oauth import FlowThreeLegged
|
|||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
|
|
||||||
print os.environ
|
|
||||||
STEP2_URI = 'http://localhost:8000/auth_return'
|
STEP2_URI = 'http://localhost:8000/auth_return'
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def index(request):
|
def index(request):
|
||||||
try:
|
try:
|
||||||
@@ -45,6 +45,7 @@ def index(request):
|
|||||||
f.save()
|
f.save()
|
||||||
return HttpResponseRedirect(authorize_url)
|
return HttpResponseRedirect(authorize_url)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def auth_return(request):
|
def auth_return(request):
|
||||||
try:
|
try:
|
||||||
|
@@ -10,12 +10,12 @@ ADMINS = (
|
|||||||
|
|
||||||
MANAGERS = ADMINS
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
DATABASE_ENGINE = 'sqlite3'
|
||||||
DATABASE_NAME = 'database.sqlite3' # Or path to database file if using sqlite3.
|
DATABASE_NAME = 'database.sqlite3'
|
||||||
DATABASE_USER = '' # Not used with sqlite3.
|
DATABASE_USER = ''
|
||||||
DATABASE_PASSWORD = '' # Not used with sqlite3.
|
DATABASE_PASSWORD = ''
|
||||||
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
|
DATABASE_HOST = ''
|
||||||
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
|
DATABASE_PORT = ''
|
||||||
|
|
||||||
# Local time zone for this installation. Choices can be found here:
|
# Local time zone for this installation. Choices can be found here:
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||||
@@ -67,7 +67,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
ROOT_URLCONF = 'django_sample.urls'
|
ROOT_URLCONF = 'django_sample.urls'
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
# Put strings here, like "/home/html/django_templates"
|
||||||
# Always use forward slashes, even on Windows.
|
# Always use forward slashes, even on Windows.
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
# Don't forget to use absolute paths, not relative paths.
|
||||||
os.path.join(os.path.dirname(__file__), 'templates')
|
os.path.join(os.path.dirname(__file__), 'templates')
|
||||||
|
@@ -20,6 +20,7 @@ import pickle
|
|||||||
# Uncomment to get detailed logging
|
# Uncomment to get detailed logging
|
||||||
# httplib2.debuglevel = 4
|
# httplib2.debuglevel = 4
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
f = open("latitude.dat", "r")
|
f = open("latitude.dat", "r")
|
||||||
credentials = pickle.loads(f.read())
|
credentials = pickle.loads(f.read())
|
||||||
@@ -32,11 +33,11 @@ def main():
|
|||||||
|
|
||||||
body = {
|
body = {
|
||||||
"data": {
|
"data": {
|
||||||
"kind":"latitude#location",
|
"kind": "latitude#location",
|
||||||
"latitude":37.420352,
|
"latitude": 37.420352,
|
||||||
"longitude":-122.083389,
|
"longitude": -122.083389,
|
||||||
"accuracy":130,
|
"accuracy": 130,
|
||||||
"altitude":35
|
"altitude": 35
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print p.currentLocation().insert(body=body).execute()
|
print p.currentLocation().insert(body=body).execute()
|
||||||
|
@@ -36,10 +36,10 @@ flow = FlowThreeLegged(moderator_discovery,
|
|||||||
# https://www.google.com/accounts/ManageDomains
|
# https://www.google.com/accounts/ManageDomains
|
||||||
consumer_key='REGISTERED DOMAIN NAME',
|
consumer_key='REGISTERED DOMAIN NAME',
|
||||||
consumer_secret='KEY GIVEN DURING REGISTRATION',
|
consumer_secret='KEY GIVEN DURING REGISTRATION',
|
||||||
user_agent='google-api-client-python-latitude-cmdline/1.0',
|
user_agent='google-api-client-python-latitude/1.0',
|
||||||
domain='REGISTERED DOMAIN NAME',
|
domain='REGISTERED DOMAIN NAME',
|
||||||
scope='https://www.googleapis.com/auth/latitude',
|
scope='https://www.googleapis.com/auth/latitude',
|
||||||
xoauth_displayname='Google API Latitude Client Example App',
|
xoauth_displayname='Google API Latitude Example',
|
||||||
location='current',
|
location='current',
|
||||||
granularity='city'
|
granularity='city'
|
||||||
)
|
)
|
||||||
|
@@ -22,9 +22,10 @@ import httplib2
|
|||||||
import pickle
|
import pickle
|
||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
DISCOVERY_URI = ('http://gregorio-ub.i:3990/discovery/v0.2beta1/describe/'
|
DISCOVERY_URI = ('http://localhost:3990/discovery/v0.2beta1/describe/'
|
||||||
'{api}/{apiVersion}')
|
'{api}/{apiVersion}')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
http = httplib2.Http()
|
http = httplib2.Http()
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ import pickle
|
|||||||
# Uncomment to get detailed logging
|
# Uncomment to get detailed logging
|
||||||
# httplib2.debuglevel = 4
|
# httplib2.debuglevel = 4
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
f = open("moderator.dat", "r")
|
f = open("moderator.dat", "r")
|
||||||
credentials = pickle.loads(f.read())
|
credentials = pickle.loads(f.read())
|
||||||
@@ -32,7 +33,7 @@ def main():
|
|||||||
|
|
||||||
series_body = {
|
series_body = {
|
||||||
"data": {
|
"data": {
|
||||||
"description": "Share and rank tips for eating healthily on the cheaps!",
|
"description": "Share and rank tips for eating healthy and cheap!",
|
||||||
"name": "Eating Healthy & Cheap",
|
"name": "Eating Healthy & Cheap",
|
||||||
"videoSubmissionAllowed": False
|
"videoSubmissionAllowed": False
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,8 @@ def main():
|
|||||||
"presenter": "liz"
|
"presenter": "liz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
topic = p.topics().insert(seriesId=series['id']['seriesId'], body=topic_body).execute()
|
topic = p.topics().insert(seriesId=series['id']['seriesId'],
|
||||||
|
body=topic_body).execute()
|
||||||
print "Created a new topic"
|
print "Created a new topic"
|
||||||
|
|
||||||
submission_body = {
|
submission_body = {
|
||||||
@@ -69,7 +71,9 @@ def main():
|
|||||||
"vote": "PLUS"
|
"vote": "PLUS"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.votes().insert(seriesId=topic['id']['seriesId'], submissionId=submission['id']['submissionId'], body=vote_body)
|
p.votes().insert(seriesId=topic['id']['seriesId'],
|
||||||
|
submissionId=submission['id']['submissionId'],
|
||||||
|
body=vote_body)
|
||||||
print "Voted on the submission"
|
print "Voted on the submission"
|
||||||
|
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ class Backoff:
|
|||||||
|
|
||||||
Implements an exponential backoff algorithm.
|
Implements an exponential backoff algorithm.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, maxretries=8):
|
def __init__(self, maxretries=8):
|
||||||
self.retry = 0
|
self.retry = 0
|
||||||
self.maxretries = maxretries
|
self.maxretries = maxretries
|
||||||
@@ -36,7 +37,7 @@ class Backoff:
|
|||||||
|
|
||||||
def fail(self):
|
def fail(self):
|
||||||
self.retry += 1
|
self.retry += 1
|
||||||
delay = 2**self.retry
|
delay = 2 ** self.retry
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
|
|
||||||
|
|
||||||
@@ -67,8 +68,8 @@ def start_threads(credentials):
|
|||||||
t.daemon = True
|
t.daemon = True
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
|
def main():
|
||||||
f = open("moderator.dat", "r")
|
f = open("moderator.dat", "r")
|
||||||
credentials = pickle.loads(f.read())
|
credentials = pickle.loads(f.read())
|
||||||
f.close()
|
f.close()
|
||||||
@@ -98,7 +99,8 @@ def main():
|
|||||||
"presenter": "me"
|
"presenter": "me"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
topic_request = p.topics().insert(seriesId=series['id']['seriesId'], body=topic_body)
|
topic_request = p.topics().insert(seriesId=series['id']['seriesId'],
|
||||||
|
body=topic_body)
|
||||||
print "Adding request to queue"
|
print "Adding request to queue"
|
||||||
queue.put(topic_request)
|
queue.put(topic_request)
|
||||||
|
|
||||||
|
@@ -32,7 +32,7 @@ moderator_discovery = build("moderator", "v1").auth_discovery()
|
|||||||
flow = FlowThreeLegged(moderator_discovery,
|
flow = FlowThreeLegged(moderator_discovery,
|
||||||
consumer_key='anonymous',
|
consumer_key='anonymous',
|
||||||
consumer_secret='anonymous',
|
consumer_secret='anonymous',
|
||||||
user_agent='google-api-client-python-threadqueue-sample/1.0',
|
user_agent='google-api-client-python-thread-sample/1.0',
|
||||||
domain='anonymous',
|
domain='anonymous',
|
||||||
scope='https://www.googleapis.com/auth/moderator',
|
scope='https://www.googleapis.com/auth/moderator',
|
||||||
#scope='tag:google.com,2010:auth/moderator',
|
#scope='tag:google.com,2010:auth/moderator',
|
||||||
|
@@ -18,9 +18,11 @@ import pprint
|
|||||||
# Uncomment the next line to get very detailed logging
|
# Uncomment the next line to get very detailed logging
|
||||||
# httplib2.debuglevel = 4
|
# httplib2.debuglevel = 4
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
p = build("translate", "v2", developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
p = build("translate", "v2",
|
||||||
|
developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
||||||
print p.translations().list(
|
print p.translations().list(
|
||||||
source="en",
|
source="en",
|
||||||
target="fr",
|
target="fr",
|
||||||
|
@@ -32,20 +32,7 @@ except ImportError:
|
|||||||
from cgi import parse_qs
|
from cgi import parse_qs
|
||||||
|
|
||||||
from apiclient.discovery import build, key2param
|
from apiclient.discovery import build, key2param
|
||||||
|
from tests.util import HttpMock
|
||||||
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
|
|
||||||
|
|
||||||
|
|
||||||
class HttpMock(object):
|
|
||||||
|
|
||||||
def __init__(self, filename, headers):
|
|
||||||
f = file(os.path.join(DATA_DIR, filename), 'r')
|
|
||||||
self.data = f.read()
|
|
||||||
f.close()
|
|
||||||
self.headers = headers
|
|
||||||
|
|
||||||
def request(self, uri, method="GET", body=None, headers=None, redirections=1, connection_type=None):
|
|
||||||
return httplib2.Response(self.headers), self.data
|
|
||||||
|
|
||||||
|
|
||||||
class Utilities(unittest.TestCase):
|
class Utilities(unittest.TestCase):
|
||||||
|
Reference in New Issue
Block a user