First pass at adding in pagination
This commit is contained in:
3
Makefile
3
Makefile
@@ -3,3 +3,6 @@ pep8:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
python runtests.py
|
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 httplib2
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import simplejson
|
import simplejson
|
||||||
import urlparse
|
|
||||||
import uritemplate
|
import uritemplate
|
||||||
|
import urlparse
|
||||||
|
|
||||||
|
|
||||||
class HttpError(Exception):
|
class HttpError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
DISCOVERY_URI = 'http://www.googleapis.com/discovery/0.1/describe\
|
class UnknownLinkType(Exception):
|
||||||
{?api,apiVersion}'
|
pass
|
||||||
|
|
||||||
|
DISCOVERY_URI = ('http://www.googleapis.com/discovery/0.1/describe'
|
||||||
|
'{?api,apiVersion}')
|
||||||
|
|
||||||
|
|
||||||
def key2method(key):
|
def key2method(key):
|
||||||
@@ -107,10 +111,10 @@ class JsonModel(object):
|
|||||||
raise HttpError(simplejson.loads(content)['error'])
|
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()):
|
discoveryServiceUrl=DISCOVERY_URI, auth=None, model=JsonModel()):
|
||||||
params = {
|
params = {
|
||||||
'api': service,
|
'api': serviceName,
|
||||||
'apiVersion': version
|
'apiVersion': version
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +122,14 @@ def build(service, version, http=httplib2.Http(),
|
|||||||
logging.info('URL being requested: %s' % requested_url)
|
logging.info('URL being requested: %s' % requested_url)
|
||||||
resp, content = http.request(requested_url)
|
resp, content = http.request(requested_url)
|
||||||
d = simplejson.loads(content)
|
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']
|
base = service['baseUrl']
|
||||||
resources = service['resources']
|
resources = service['resources']
|
||||||
|
|
||||||
@@ -130,21 +141,21 @@ def build(service, version, http=httplib2.Http(),
|
|||||||
self._baseUrl = base
|
self._baseUrl = base
|
||||||
self._model = model
|
self._model = model
|
||||||
|
|
||||||
def createMethod(theclass, methodName, methodDesc):
|
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||||
|
|
||||||
def method(self, **kwargs):
|
def method(self, **kwargs):
|
||||||
return createResource(self._http, self._baseUrl, self._model,
|
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(method, '__doc__', 'A description of how to use this function')
|
||||||
setattr(theclass, methodName, method)
|
setattr(theclass, methodName, method)
|
||||||
|
|
||||||
for methodName, methodDesc in resources.iteritems():
|
for methodName, methodDesc in resources.iteritems():
|
||||||
createMethod(Service, methodName, methodDesc)
|
createMethod(Service, methodName, methodDesc, future[methodName])
|
||||||
return Service()
|
return Service()
|
||||||
|
|
||||||
|
|
||||||
def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
def createResource(http, baseUrl, model, resourceName, resourceDesc, futureDesc):
|
||||||
|
|
||||||
class Resource(object):
|
class Resource(object):
|
||||||
"""A class for interacting with a resource."""
|
"""A class for interacting with a resource."""
|
||||||
@@ -154,7 +165,7 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
|||||||
self._baseUrl = baseUrl
|
self._baseUrl = baseUrl
|
||||||
self._model = model
|
self._model = model
|
||||||
|
|
||||||
def createMethod(theclass, methodName, methodDesc):
|
def createMethod(theclass, methodName, methodDesc, futureDesc):
|
||||||
pathUrl = methodDesc['pathUrl']
|
pathUrl = methodDesc['pathUrl']
|
||||||
pathUrl = re.sub(r'\{', r'{+', pathUrl)
|
pathUrl = re.sub(r'\{', r'{+', pathUrl)
|
||||||
httpMethod = methodDesc['httpMethod']
|
httpMethod = methodDesc['httpMethod']
|
||||||
@@ -207,7 +218,7 @@ def createResource(http, baseUrl, model, resourceName, resourceDesc):
|
|||||||
headers = {}
|
headers = {}
|
||||||
headers, params, query, body = self._model.request(headers, actual_path_params, actual_query_params, body_value)
|
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)
|
url = urlparse.urljoin(self._baseUrl, expanded_url + query)
|
||||||
|
|
||||||
logging.info('URL being requested: %s' % url)
|
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']
|
docs = ['A description of how to use this function\n\n']
|
||||||
for arg in argmap.iterkeys():
|
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(method, '__doc__', ''.join(docs))
|
||||||
setattr(theclass, methodName, method)
|
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():
|
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()
|
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_key = 'anonymous'
|
||||||
consumer_secret = 'anonymous'
|
consumer_secret = 'anonymous'
|
||||||
|
|
||||||
request_token_url = 'https://www.google.com/accounts/OAuthGetRequestToken\
|
request_token_url = ('https://www.google.com/accounts/OAuthGetRequestToken'
|
||||||
?domain=anonymous&scope=https://www.googleapis.com/auth/buzz'
|
'?domain=anonymous&scope=https://www.googleapis.com/auth/buzz')
|
||||||
|
|
||||||
access_token_url = 'https://www.google.com/accounts/OAuthGetAccessToken\
|
access_token_url = ('https://www.google.com/accounts/OAuthGetAccessToken'
|
||||||
?domain=anonymous&scope=https://www.googleapis.com/auth/buzz'
|
'?domain=anonymous&scope=https://www.googleapis.com/auth/buzz')
|
||||||
|
|
||||||
authorize_url = 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken\
|
authorize_url = ('https://www.google.com/buzz/api/auth/OAuthAuthorizeToken'
|
||||||
?domain=anonymous&scope=https://www.googleapis.com/auth/buzz'
|
'?domain=anonymous&scope=https://www.googleapis.com/auth/buzz')
|
||||||
|
|
||||||
consumer = oauth.Consumer(consumer_key, consumer_secret)
|
consumer = oauth.Consumer(consumer_key, consumer_secret)
|
||||||
client = oauth.Client(consumer)
|
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": {
|
"reshared": {
|
||||||
"pathUrl": "buzz/v1/activities/{userId}/{scope}/{postId}/{groupId}",
|
"pathUrl": "buzz/v1/activities/{userId}/{scope}/{postId}/{groupId}",
|
||||||
"rpcName": "buzz.people.reshared",
|
"rpcName": "buzz.people.reshared",
|
||||||
@@ -722,15 +742,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"insert": {
|
"update": {
|
||||||
"pathUrl": "buzz/v1/people/{userId}/@groups",
|
"pathUrl": "buzz/v1/people/{userId}/@groups/{groupId}/@self",
|
||||||
"rpcName": "buzz.groups.insert",
|
"rpcName": "buzz.groups.update",
|
||||||
"httpMethod": "POST",
|
"httpMethod": "PUT",
|
||||||
"methodType": "rest",
|
"methodType": "rest",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"alt": {
|
"groupId": {
|
||||||
"parameterType": "query",
|
"parameterType": "path",
|
||||||
"required": false
|
"pattern": "[^/]+",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
"userId": {
|
"userId": {
|
||||||
"parameterType": "path",
|
"parameterType": "path",
|
||||||
@@ -743,16 +764,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"update": {
|
"insert": {
|
||||||
"pathUrl": "buzz/v1/people/{userId}/@groups/{groupId}/@self",
|
"pathUrl": "buzz/v1/people/{userId}/@groups",
|
||||||
"rpcName": "buzz.groups.update",
|
"rpcName": "buzz.groups.insert",
|
||||||
"httpMethod": "PUT",
|
"httpMethod": "POST",
|
||||||
"methodType": "rest",
|
"methodType": "rest",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"groupId": {
|
"alt": {
|
||||||
"parameterType": "path",
|
"parameterType": "query",
|
||||||
"pattern": "[^/]+",
|
"required": false
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
"userId": {
|
"userId": {
|
||||||
"parameterType": "path",
|
"parameterType": "path",
|
||||||
|
@@ -1,6 +1,19 @@
|
|||||||
#!/usr/bin/python2.4
|
#!/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
|
"""Discovery document tests
|
||||||
|
|
||||||
|
@@ -1,10 +1,22 @@
|
|||||||
#!/usr/bin/python2.4
|
#!/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)'
|
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||||
|
Reference in New Issue
Block a user