Fix lack of top level methods from a service.

This commit is contained in:
Joe Gregorio
2011-01-31 21:55:21 -05:00
parent 28ee089ca3
commit 7a6df3a31a
9 changed files with 67 additions and 58 deletions

View File

@@ -91,6 +91,7 @@ def build(serviceName, version,
return build_from_document(content, discoveryServiceUrl, future, return build_from_document(content, discoveryServiceUrl, future,
http, developerKey, model, requestBuilder) http, developerKey, model, requestBuilder)
def build_from_document( def build_from_document(
service, service,
base, base,
@@ -105,8 +106,8 @@ def build_from_document(
base: string, base URI for all HTTP requests, usually the discovery URI base: string, base URI for all HTTP requests, usually the discovery URI
future: string, discovery document with future capabilities future: string, discovery document with future capabilities
auth_discovery: dict, information about the authentication the API supports auth_discovery: dict, information about the authentication the API supports
http: httplib2.Http, An instance of httplib2.Http or something that acts like http: httplib2.Http, An instance of httplib2.Http or something that acts
it that HTTP requests will be made through. like it that HTTP requests will be made through.
developerKey: string, Key for controlling API usage, generated developerKey: string, Key for controlling API usage, generated
from the API Console. from the API Console.
model: Model class instance that serializes and model: Model class instance that serializes and
@@ -116,45 +117,26 @@ def build_from_document(
service = simplejson.loads(service) service = simplejson.loads(service)
base = urlparse.urljoin(base, service['restBasePath']) base = urlparse.urljoin(base, service['restBasePath'])
resources = service['resources']
if future: if future:
doc = simplejson.loads(future) future = simplejson.loads(future)
future = doc['resources'] auth_discovery = future.get('auth', {})
auth_discovery = doc.get('auth', {})
else: else:
future = {} future = {}
auth_discovery = {} auth_discovery = {}
class Service(object): resource = createResource(http, base, model, requestBuilder, developerKey,
"""Top level interface for a service""" service, future)
def __init__(self, http=http): def auth_method():
self._http = http """Discovery information about the authentication the API uses."""
self._baseUrl = base return auth_discovery
self._model = model
self._developerKey = developerKey
self._requestBuilder = requestBuilder
def auth_discovery(self): setattr(resource, 'auth_discovery', auth_method)
return auth_discovery
def createMethod(theclass, methodName, methodDesc, futureDesc): return resource
def method(self):
return createResource(self._http, self._baseUrl, self._model,
self._requestBuilder, methodName,
self._developerKey, methodDesc, futureDesc)
setattr(method, '__doc__', 'A description of how to use this function')
setattr(method, '__is_resource__', True)
setattr(theclass, methodName, method)
for methodName, methodDesc in resources.iteritems():
createMethod(Service, methodName, methodDesc, future.get(methodName, {}))
return Service()
def createResource(http, baseUrl, model, requestBuilder, resourceName, def createResource(http, baseUrl, model, requestBuilder,
developerKey, resourceDesc, futureDesc): developerKey, resourceDesc, futureDesc):
class Resource(object): class Resource(object):
@@ -322,8 +304,8 @@ def createResource(http, baseUrl, model, requestBuilder, resourceName,
def method(self): def method(self):
return createResource(self._http, self._baseUrl, self._model, return createResource(self._http, self._baseUrl, self._model,
self._requestBuilder, methodName, self._requestBuilder, self._developerKey,
self._developerKey, methodDesc, futureDesc) 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)
@@ -335,10 +317,10 @@ def createResource(http, baseUrl, model, requestBuilder, resourceName,
else: else:
future = {} future = {}
createMethod(Resource, methodName, methodDesc, createMethod(Resource, methodName, methodDesc,
future.get(methodName, {})) future)
# Add <m>_next() methods to Resource # Add <m>_next() methods to Resource
if futureDesc: if futureDesc and 'methods' in 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", createNextMethod(Resource, methodName + "_next",

View File

@@ -79,10 +79,12 @@ class Credentials(object):
""" """
_abstract() _abstract()
class Flow(object): class Flow(object):
"""Base class for all Flow objects.""" """Base class for all Flow objects."""
pass pass
class OAuthCredentials(Credentials): class OAuthCredentials(Credentials):
"""Credentials object for OAuth 1.0a """Credentials object for OAuth 1.0a
""" """
@@ -254,4 +256,3 @@ class FlowThreeLegged(Flow):
oauth_params['oauth_token_secret']) oauth_params['oauth_token_secret'])
return OAuthCredentials(consumer, token, self.user_agent) return OAuthCredentials(consumer, token, self.user_agent)

View File

@@ -15,12 +15,12 @@ DEVELOPER_KEY = 'AIzaSyACZJW4JwcWwz5taR2gjIMNQrtgDLfILPc'
def main(): def main():
"""Get and print a feed of public products in the United States mathing a text """Get and print a feed of public products in the United States mathing a
search query for 'digital camera' and grouped by the 8 top brands. text search query for 'digital camera' and grouped by the 8 top brands.
The list method of the resource should be called with the "crowdBy" parameter. The list method of the resource should be called with the "crowdBy"
Each parameter should be designed as <attribute>:<occurence>, where parameter. Each parameter should be designed as <attribute>:<occurence>,
<occurrence> is the number of that <attribute> that will be used. For where <occurrence> is the number of that <attribute> that will be used. For
example, to crowd by the 5 top brands, the parameter would be "brand:5". The example, to crowd by the 5 top brands, the parameter would be "brand:5". The
possible rules for crowding are currently: possible rules for crowding are currently:

View File

@@ -23,9 +23,10 @@ def main():
The "|" operator can be used to search for alternative search terms, for The "|" operator can be used to search for alternative search terms, for
example: q = 'banana|apple' will search for bananas or apples. example: q = 'banana|apple' will search for bananas or apples.
Search phrases such as those containing spaces can be specified by surrounding Search phrases such as those containing spaces can be specified by
them with double quotes, for example q='"mp3 player"'. This can be useful when surrounding them with double quotes, for example q='"mp3 player"'. This can
combining with the "|" operator such as q = '"mp3 player"|ipod'. be useful when combining with the "|" operator such as q = '"mp3
player"|ipod'.
""" """
client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY) client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY)
resource = client.products() resource = client.products()

View File

@@ -16,16 +16,17 @@ def main():
"""Get and print a histogram of the top 15 brand distribution for a search """Get and print a histogram of the top 15 brand distribution for a search
query. query.
Histograms are created by using the "Facets" functionality of the API. A Facet Histograms are created by using the "Facets" functionality of the API. A
is a view of a certain property of products, containing a number of buckets, Facet is a view of a certain property of products, containing a number of
one for each value of that property. Or concretely, for a parameter such as buckets, one for each value of that property. Or concretely, for a parameter
"brand" of a product, the facets would include a facet for brand, which would such as "brand" of a product, the facets would include a facet for brand,
contain a number of buckets, one for each brand returned in the result. which would contain a number of buckets, one for each brand returned in the
result.
A bucket contains either a value and a count, or a value and a range. In the A bucket contains either a value and a count, or a value and a range. In the
simple case of a value and a count for our example of the "brand" property, simple case of a value and a count for our example of the "brand" property,
the value would be the brand name, eg "sony" and the count would be the number the value would be the brand name, eg "sony" and the count would be the
of results in the search. number of results in the search.
""" """
client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY) client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY)
resource = client.products() resource = client.products()

View File

@@ -15,11 +15,12 @@ DEVELOPER_KEY = 'AIzaSyACZJW4JwcWwz5taR2gjIMNQrtgDLfILPc'
def main(): def main():
"""Get and print a feed of public products in the United States mathing a text """Get and print a feed of public products in the United States mathing a
search query for 'digital camera' ranked by ascending price. text search query for 'digital camera' ranked by ascending price.
The list method for the resource should be called with the "rankBy" parameter. The list method for the resource should be called with the "rankBy"
5 parameters to rankBy are currently supported by the API. They are: parameter. 5 parameters to rankBy are currently supported by the API. They
are:
"relevancy" "relevancy"
"modificationTime:ascending" "modificationTime:ascending"
@@ -33,8 +34,8 @@ def main():
""" """
client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY) client = build('shopping', SHOPPING_API_VERSION, developerKey=DEVELOPER_KEY)
resource = client.products() resource = client.products()
# The rankBy parameter to the list method causes results to be ranked, in this # The rankBy parameter to the list method causes results to be ranked, in
# case by ascending price. # this case by ascending price.
request = resource.list(source='public', country='US', q=u'digital camera', request = resource.list(source='public', country='US', q=u'digital camera',
rankBy='price:ascending') rankBy='price:ascending')
response = request.execute() response = request.execute()

View File

@@ -3,7 +3,8 @@
# #
# Copyright 2010 Google Inc. All Rights Reserved. # Copyright 2010 Google Inc. All Rights Reserved.
"""Query that is restricted by a parameter against the public shopping search API""" """Query that is restricted by a parameter against the public shopping search
API"""
import pprint import pprint

View File

@@ -4,6 +4,20 @@
"description": "Zoo API used for testing", "description": "Zoo API used for testing",
"restBasePath": "/zoo", "restBasePath": "/zoo",
"rpcPath": "/rpc", "rpcPath": "/rpc",
"methods": {
"query": {
"restPath": "query",
"rpcMethod": "bigquery.query",
"httpMethod": "GET",
"parameters": {
"q": {
"restParameterType": "query",
"required": false,
"repeated": false
}
}
}
},
"resources": { "resources": {
"my": { "my": {
"resources": { "resources": {

View File

@@ -113,6 +113,14 @@ class Discovery(unittest.TestCase):
q = parse_qs(parsed[4]) q = parse_qs(parsed[4])
self.assertEqual(q['max-results'], ['5']) self.assertEqual(q['max-results'], ['5'])
def test_top_level_functions(self):
self.http = HttpMock('zoo.json', {'status': '200'})
zoo = build('zoo', 'v1', self.http)
self.assertTrue(getattr(zoo, 'query'))
request = zoo.query(q="foo")
parsed = urlparse.urlparse(request.uri)
q = parse_qs(parsed[4])
self.assertEqual(q['q'], ['foo'])
class Next(unittest.TestCase): class Next(unittest.TestCase):