Copyright (C) 2011 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. Subclass for the Discovery portion of GoogleCL which
manages the documentation
n charge of saving/loading the API directory, nd retrieves and stores the Discovery documents.
import httplib2
import logging
import simplejson as json
import googlecl
LOG = logging.getLogger(googlecl.LOGGER_NAME)
apis_path = googlecl.get_data_path('apis.dat', create_missing_dir=True)
SERVICE_BLACKLIST = ['latitude']
LIST_URL = '%s/discovery/v1/apis?preferred=true&pp=0'
SERVICE_URL = '%s/discovery/v1/apis/%s/%s/rest'
class DocManager():
def __init__(self, local, base_url):
self.base_url = base_url
self.load()
self.apis = {}
self.local = local
if self.local:
if isinstance(self.local, list): # local comes from the config file
for filename in self.local: # Be sure to give the correct path.
self.loadDoc(filename)
else:
self.loadDoc(self.local)
Loads the currently saved list of preferred APIs,
def load(self, force=False):
or downloads the latest version. Can be forced with the command 'refresh apis'
rgs: force: If true, the will always download a new document
try:
if force:
raise
f = open(apis_path, 'r')
self.directory = json.load(f)
except:
http = httplib2.Http()
resp, content = http.request(LIST_URL % self.base_url)
self.directory = json.loads(content)
Removes blacklisted APIs (currently just latitude)
self.directory['items'] = [a for a in self.directory['items']
if a['name'] not in SERVICE_BLACKLIST]
f = open(apis_path, 'w')
json.dump(self.directory, f, indent=2)
if hasattr(self, 'local') and self.local:
if isinstance(self.local, list): # local comes from the config file
for filename in self.local: # Be sure to give the correct path.
self.loadDoc(filename)
else:
self.loadDoc(self.local)
Loads a discovery document stored locally
def loadDoc(self, filename):
rgs: filename: The file being loaded
try:
doc = json.loads(file(filename).read())
except:
LOG.info('Failed to load ' + filename)
return
self.apis[doc['name']+'.'+doc['version']] = doc
info = {'name': doc['name'], 'version': doc['version']}
self.directory['items'].append(info)
Parses through arguments to determine service, version, and gets docs
def run(self, argv, isHelp, verbose):
lso prints help, if applicable
rgs: argv: The arguments which are passed in isHelp: If help should be displayed verbose: If isHelp, then whether it should be verbose eturns: If it doesn't display help, then a tuple of the service name, version, documentation, and remaining args
http = httplib2.Http()
Parses the service name and version If no version is defined, finds the currently preferred one
servicename = argv[0]
if len(argv) > 1:
version = argv[1]
else:
version = None
args = argv[2:]
if not version or not version[0] == 'v' or not version[1].isdigit():
version = None
for api in self.directory['items']:
if api['name'] == servicename:
version = api['version']
args = argv[1:]
break
if not version:
LOG.error('Did not recognize service.')
return
Fetches documentation for service
if servicename + '.' + version in self.apis:
doc = self.apis[servicename + '.' + version]
else:
resp, content = http.request(SERVICE_URL % (self.base_url, servicename, version))
doc = json.loads(content)
self.apis[servicename + '.' + version] = doc
if 'error' in doc:
LOG.error('Did not recognize version.')
return
Displays help, if requested
if isHelp:
help(doc, verbose, *args)
return
return servicename, version, doc, args
Prints the help for an arbitrary service
def help(doc, verbose, *path):
rgs: doc: Discovery document for the service verbose: Whether or not all information should be displayed path: The path to the desired method, parameter, or other attribute
Locates the desired object Will try to follow path implicitly (for resources, methods, parameters) otherwise the path must be fully defined (most likely useful for schemas)
base = doc
for p in path:
if p[:2] == '--':
p = p[2:]
if p in base:
base = base[p]
elif 'resources' in base and p in base['resources']:
base = base['resources'][p]
elif 'methods' in base and p in base['methods']:
base = base['methods'][p]
elif 'parameters' in base and p in base['parameters']:
base = base['parameters'][p]
else:
n = ('resources' in base) + ('methods' in base) + ('parameters' in base
and not base == doc)
while (n == 1 or len(base) == 1) and not p in base:
i = 0
if 'resources' in base: i = base.keys().index('resources')
elif 'methods' in base: i = base.keys().index('methods')
elif 'parameters' in base: i = base.keys().index('parameters')
base = base[base.keys()[i]]
n = ('resources' in base) + ('methods' in base) + ('parameters' in base)
if p in base:
base = base[p]
else:
LOG.error('Error in path: "' + p + '" not found')
return
Displays the attributes of the requested object Formatted if object is base API, method, or resource and not verbose.
if not verbose:
if isinstance(base, dict):
if 'version' in base: #Base API
print ' ' + base['description']
print ' Resources: ' + ', '.join(base['resources'])
elif 'httpMethod' in base: #Method
print ' ' + base['description']
if 'parameterOrder' in base:
print ' Requires: ' + ' AND '.join(base['parameterOrder']) \
+ ' Optional: ' + ', '.join([i for i in base['parameters'] if \
i not in base['parameterOrder']])
elif 'parameters' in base:
print ' Optional: ' + ', '.join(base['parameters'])
if 'request' in base:
print ' Request schema: ' + base['request']['$ref']
elif 'methods' in base or 'resources' in base: #Resource
if 'methods' in base:
print ' Methods: ' + ', '.join(base['methods'])
if 'resources' in base:
print ' Resources: ' + ', '.join(base['resources'])
else: #Everything else
for obj in base:
if isinstance(base[obj], dict) or isinstance(base[obj], list):
print ' ' + obj + ": " + ', '.join(base[obj])
else:
print ' ' + obj + ": " + str(base[obj])
else:
print base
else:
if isinstance(base, dict):
for obj in base:
if isinstance(base[obj], dict) or isinstance(base[obj], list):
print ' ' + obj + ": " + ', '.join(base[obj])
else:
print ' ' + obj + ": " + str(base[obj])
else:
print base