First pass at adding in pagination
This commit is contained in:
3
Makefile
3
Makefile
@@ -3,3 +3,6 @@ pep8:
|
||||
|
||||
test:
|
||||
python runtests.py
|
||||
|
||||
skeletons:
|
||||
python discovery_extras.py tests/data/buzz.json tests/data/latitude.json tests/data/moderator.json
|
||||
|
89
apiclient/contrib/buzz/future.json
Normal file
89
apiclient/contrib/buzz/future.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"data": {
|
||||
"buzz": {
|
||||
"v1": {
|
||||
"baseUrl": "https://www.googleapis.com/",
|
||||
"resources": {
|
||||
"activities": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {
|
||||
"next": {
|
||||
"type": "uri",
|
||||
"location": ["links", "next", 0, "href"]
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"next": {
|
||||
"type": "uri",
|
||||
"location": ["links", "next", 0, "href"]
|
||||
}
|
||||
},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"comments": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"feeds": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"insert": {},
|
||||
"list": {},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"groups": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {
|
||||
"next": {
|
||||
"type": "uri",
|
||||
"location": ["links", "next", 0, "href"]
|
||||
}
|
||||
},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"people": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"liked": {},
|
||||
"list": {},
|
||||
"relatedToUri": {},
|
||||
"reshared": {},
|
||||
"search": {},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"photos": {
|
||||
"methods": {
|
||||
"insert": {}
|
||||
}
|
||||
},
|
||||
"related": {
|
||||
"methods": {
|
||||
"list": {}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"methods": {
|
||||
"extractPeople": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
apiclient/contrib/latitude/future.json
Normal file
26
apiclient/contrib/latitude/future.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": {
|
||||
"latitude": {
|
||||
"v1": {
|
||||
"baseUrl": "https://www.googleapis.com/",
|
||||
"resources": {
|
||||
"currentLocation": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"insert": {}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
apiclient/contrib/moderator/future.json
Normal file
60
apiclient/contrib/moderator/future.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"data": {
|
||||
"moderator": {
|
||||
"v1": {
|
||||
"baseUrl": "https://www.googleapis.com/",
|
||||
"resources": {
|
||||
"profiles": {
|
||||
"methods": {
|
||||
"get": {},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"methods": {
|
||||
"insert": {},
|
||||
"list": {}
|
||||
}
|
||||
},
|
||||
"series": {
|
||||
"methods": {
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {},
|
||||
"update": {}
|
||||
}
|
||||
},
|
||||
"submissions": {
|
||||
"methods": {
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"methods": {
|
||||
"delete": {},
|
||||
"insert": {},
|
||||
"list": {}
|
||||
}
|
||||
},
|
||||
"topics": {
|
||||
"methods": {
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {}
|
||||
}
|
||||
},
|
||||
"votes": {
|
||||
"methods": {
|
||||
"get": {},
|
||||
"insert": {},
|
||||
"list": {},
|
||||
"update": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,17 +23,21 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
|
||||
import httplib2
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import simplejson
|
||||
import urlparse
|
||||
import uritemplate
|
||||
import urlparse
|
||||
|
||||
|
||||
class HttpError(Exception):
|
||||
pass
|
||||
|
||||
DISCOVERY_URI = 'http://www.googleapis.com/discovery/0.1/describe\
|
||||
{?api,apiVersion}'
|
||||
class UnknownLinkType(Exception):
|
||||
pass
|
||||
|
||||
DISCOVERY_URI = ('http://www.googleapis.com/discovery/0.1/describe'
|
||||
'{?api,apiVersion}')
|
||||
|
||||
|
||||
def key2method(key):
|
||||
@@ -107,10 +111,10 @@ class JsonModel(object):
|
||||
raise HttpError(simplejson.loads(content)['error'])
|
||||
|
||||
|
||||
def build(service, version, http=httplib2.Http(),
|
||||
def build(serviceName, version, http=httplib2.Http(),
|
||||
discoveryServiceUrl=DISCOVERY_URI, auth=None, model=JsonModel()):
|
||||
params = {
|
||||
'api': service,
|
||||
'api': serviceName,
|
||||
'apiVersion': version
|
||||
}
|
||||
|
||||
@@ -118,7 +122,14 @@ def build(service, version, http=httplib2.Http(),
|
||||
logging.info('URL being requested: %s' % requested_url)
|
||||
resp, content = http.request(requested_url)
|
||||
d = simplejson.loads(content)
|
||||
service = d['data'][service][version]
|
||||
service = d['data'][serviceName][version]
|
||||
|
||||
fn = os.path.join(os.path.dirname(__file__), "contrib", serviceName, "future.json")
|
||||
f = file(fn, "r")
|
||||
d = simplejson.load(f)
|
||||
f.close()
|
||||
future = d['data'][serviceName][version]['resources']
|
||||
|
||||
base = service['baseUrl']
|
||||
resources = service['resources']
|
||||
|
||||
@@ -130,21 +141,21 @@ def build(service, version, http=httplib2.Http(),
|
||||
self._baseUrl = base
|
||||
self._model = model
|
||||
|
||||
def createMethod(theclass, methodName, methodDesc):
|
||||
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||
|
||||
def method(self, **kwargs):
|
||||
return createResource(self._http, self._baseUrl, self._model,
|
||||
methodName, methodDesc)
|
||||
methodName, methodDesc, futureDesc)
|
||||
|
||||
setattr(method, '__doc__', 'A description of how to use this function')
|
||||
setattr(theclass, methodName, method)
|
||||
|
||||
for methodName, methodDesc in resources.iteritems():
|
||||
createMethod(Service, methodName, methodDesc)
|
||||
createMethod(Service, methodName, methodDesc, future[methodName])
|
||||
return Service()
|
||||
|
||||
|
||||
def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
||||
def createResource(http, baseUrl, model, resourceName, resourceDesc, futureDesc):
|
||||
|
||||
class Resource(object):
|
||||
"""A class for interacting with a resource."""
|
||||
@@ -154,7 +165,7 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
||||
self._baseUrl = baseUrl
|
||||
self._model = model
|
||||
|
||||
def createMethod(theclass, methodName, methodDesc):
|
||||
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||
pathUrl = methodDesc['pathUrl']
|
||||
pathUrl = re.sub(r'\{', r'{+', pathUrl)
|
||||
httpMethod = methodDesc['httpMethod']
|
||||
@@ -207,7 +218,7 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
||||
headers = {}
|
||||
headers, params, query, body = self._model.request(headers, actual_path_params, actual_query_params, body_value)
|
||||
|
||||
expanded_url = uritemplate.expand(pathUrl, params)
|
||||
expanded_url = uritemplate.expand(pathUrl, params)
|
||||
url = urlparse.urljoin(self._baseUrl, expanded_url + query)
|
||||
|
||||
logging.info('URL being requested: %s' % url)
|
||||
@@ -218,12 +229,53 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
||||
|
||||
docs = ['A description of how to use this function\n\n']
|
||||
for arg in argmap.iterkeys():
|
||||
docs.append('%s - A parameter\n' % arg)
|
||||
required = ""
|
||||
if arg in required_params:
|
||||
required = " (required)"
|
||||
docs.append('%s - A parameter%s\n' % (arg, required))
|
||||
|
||||
setattr(method, '__doc__', ''.join(docs))
|
||||
setattr(theclass, methodName, method)
|
||||
|
||||
def createNextMethod(theclass, methodName, methodDesc):
|
||||
|
||||
def method(self, previous):
|
||||
"""
|
||||
Takes a single argument, 'body', which is the results
|
||||
from the last call, and returns the next set of items
|
||||
in the collection.
|
||||
|
||||
Returns None if there are no more items in
|
||||
the collection.
|
||||
"""
|
||||
if methodDesc['type'] != 'uri':
|
||||
raise UnknownLinkType(methodDesc['type'])
|
||||
|
||||
try:
|
||||
p = previous
|
||||
for key in methodDesc['location']:
|
||||
p = p[key]
|
||||
url = p
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
headers = {}
|
||||
headers, params, query, body = self._model.request(headers, {}, {}, None)
|
||||
|
||||
logging.info('URL being requested: %s' % url)
|
||||
resp, content = self._http.request(url, method='GET', headers=headers)
|
||||
|
||||
return self._model.response(resp, content)
|
||||
|
||||
setattr(theclass, methodName, method)
|
||||
|
||||
# Add basic methods to Resource
|
||||
for methodName, methodDesc in resourceDesc['methods'].iteritems():
|
||||
createMethod(Resource, methodName, methodDesc)
|
||||
createMethod(Resource, methodName, methodDesc, futureDesc['methods'].get(methodName, {}))
|
||||
|
||||
# Add <m>_next() methods to Resource
|
||||
for methodName, methodDesc in futureDesc['methods'].iteritems():
|
||||
if 'next' in methodDesc and methodName in resourceDesc['methods']:
|
||||
createNextMethod(Resource, methodName + "_next", methodDesc['next'])
|
||||
|
||||
return Resource()
|
||||
|
52
discovery_extras.py
Normal file
52
discovery_extras.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
|
||||
"""Generate a skeleton discovery extras document.
|
||||
|
||||
For the given API, retrieve the discovery document,
|
||||
strip out the guts of each method description
|
||||
and put :
|
||||
"""
|
||||
|
||||
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import simplejson
|
||||
import sys
|
||||
|
||||
def main():
|
||||
for filename in sys.argv[1:]:
|
||||
f = file(filename, "r")
|
||||
dis = simplejson.load(f)
|
||||
f.close()
|
||||
|
||||
data = dis['data']
|
||||
api = data[data.keys()[0]]
|
||||
version = api[api.keys()[0]]
|
||||
resources = version['resources']
|
||||
for res_name, res_desc in resources.iteritems():
|
||||
methods = res_desc['methods']
|
||||
for method_name, method_desc in methods.iteritems():
|
||||
methods[method_name] = {}
|
||||
path, basename = os.path.split(filename)
|
||||
newfilename = os.path.join(path, "skel-" + basename)
|
||||
f = file(newfilename, "w")
|
||||
simplejson.dump(dis, f, sort_keys=True, indent=2 * ' ')
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@@ -17,14 +17,14 @@ headers = {'user-agent': 'google-api-client-python-buzz-cmdline/1.0',
|
||||
consumer_key = 'anonymous'
|
||||
consumer_secret = 'anonymous'
|
||||
|
||||
request_token_url = 'https://www.google.com/accounts/OAuthGetRequestToken\
|
||||
?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'
|
||||
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'
|
||||
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)
|
||||
|
@@ -497,6 +497,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"relatedToUri": {
|
||||
"pathUrl": "buzz/v1/people/{userId}/@related",
|
||||
"rpcName": "buzz.people.relatedToUri",
|
||||
"httpMethod": "POST",
|
||||
"methodType": "rest",
|
||||
"parameters": {
|
||||
"alt": {
|
||||
"parameterType": "query",
|
||||
"required": false
|
||||
},
|
||||
"uri": {
|
||||
"parameterType": "query",
|
||||
"required": false
|
||||
},
|
||||
"hl": {
|
||||
"parameterType": "query",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"reshared": {
|
||||
"pathUrl": "buzz/v1/activities/{userId}/{scope}/{postId}/{groupId}",
|
||||
"rpcName": "buzz.people.reshared",
|
||||
@@ -722,15 +742,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"insert": {
|
||||
"pathUrl": "buzz/v1/people/{userId}/@groups",
|
||||
"rpcName": "buzz.groups.insert",
|
||||
"httpMethod": "POST",
|
||||
"update": {
|
||||
"pathUrl": "buzz/v1/people/{userId}/@groups/{groupId}/@self",
|
||||
"rpcName": "buzz.groups.update",
|
||||
"httpMethod": "PUT",
|
||||
"methodType": "rest",
|
||||
"parameters": {
|
||||
"alt": {
|
||||
"parameterType": "query",
|
||||
"required": false
|
||||
"groupId": {
|
||||
"parameterType": "path",
|
||||
"pattern": "[^/]+",
|
||||
"required": true
|
||||
},
|
||||
"userId": {
|
||||
"parameterType": "path",
|
||||
@@ -743,16 +764,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"update": {
|
||||
"pathUrl": "buzz/v1/people/{userId}/@groups/{groupId}/@self",
|
||||
"rpcName": "buzz.groups.update",
|
||||
"httpMethod": "PUT",
|
||||
"insert": {
|
||||
"pathUrl": "buzz/v1/people/{userId}/@groups",
|
||||
"rpcName": "buzz.groups.insert",
|
||||
"httpMethod": "POST",
|
||||
"methodType": "rest",
|
||||
"parameters": {
|
||||
"groupId": {
|
||||
"parameterType": "path",
|
||||
"pattern": "[^/]+",
|
||||
"required": true
|
||||
"alt": {
|
||||
"parameterType": "query",
|
||||
"required": false
|
||||
},
|
||||
"userId": {
|
||||
"parameterType": "path",
|
||||
|
@@ -1,6 +1,19 @@
|
||||
#!/usr/bin/python2.4
|
||||
#
|
||||
# Copyright 2010 Google Inc. All Rights Reserved.
|
||||
# Copyright 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.
|
||||
|
||||
|
||||
"""Discovery document tests
|
||||
|
||||
|
@@ -1,10 +1,22 @@
|
||||
#!/usr/bin/python2.4
|
||||
#
|
||||
# Copyright 2010 Google Inc. All Rights Reserved.
|
||||
# Copyright 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.
|
||||
|
||||
"""Discovery document tests
|
||||
"""JSON Model tests
|
||||
|
||||
Unit tests for objects created from discovery documents.
|
||||
Unit tests for the JSON model.
|
||||
"""
|
||||
|
||||
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
|
Reference in New Issue
Block a user