| Index: third_party/google_api_python_client/describe.py
|
| diff --git a/third_party/google_api_python_client/describe.py b/third_party/google_api_python_client/describe.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..5dcac904c61a559b6e78003d63576bfdb1759b15
|
| --- /dev/null
|
| +++ b/third_party/google_api_python_client/describe.py
|
| @@ -0,0 +1,390 @@
|
| +#!/usr/bin/python
|
| +#
|
| +# Copyright 2014 Google Inc. All Rights Reserved.
|
| +#
|
| +# 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.
|
| +
|
| +"""Create documentation for generate API surfaces.
|
| +
|
| +Command-line tool that creates documentation for all APIs listed in discovery.
|
| +The documentation is generated from a combination of the discovery document and
|
| +the generated API surface itself.
|
| +"""
|
| +
|
| +__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
| +
|
| +import argparse
|
| +import json
|
| +import os
|
| +import re
|
| +import string
|
| +import sys
|
| +
|
| +from googleapiclient.discovery import DISCOVERY_URI
|
| +from googleapiclient.discovery import build
|
| +from googleapiclient.discovery import build_from_document
|
| +import httplib2
|
| +import uritemplate
|
| +
|
| +CSS = """<style>
|
| +
|
| +body, h1, h2, h3, div, span, p, pre, a {
|
| + margin: 0;
|
| + padding: 0;
|
| + border: 0;
|
| + font-weight: inherit;
|
| + font-style: inherit;
|
| + font-size: 100%;
|
| + font-family: inherit;
|
| + vertical-align: baseline;
|
| +}
|
| +
|
| +body {
|
| + font-size: 13px;
|
| + padding: 1em;
|
| +}
|
| +
|
| +h1 {
|
| + font-size: 26px;
|
| + margin-bottom: 1em;
|
| +}
|
| +
|
| +h2 {
|
| + font-size: 24px;
|
| + margin-bottom: 1em;
|
| +}
|
| +
|
| +h3 {
|
| + font-size: 20px;
|
| + margin-bottom: 1em;
|
| + margin-top: 1em;
|
| +}
|
| +
|
| +pre, code {
|
| + line-height: 1.5;
|
| + font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace;
|
| +}
|
| +
|
| +pre {
|
| + margin-top: 0.5em;
|
| +}
|
| +
|
| +h1, h2, h3, p {
|
| + font-family: Arial, sans serif;
|
| +}
|
| +
|
| +h1, h2, h3 {
|
| + border-bottom: solid #CCC 1px;
|
| +}
|
| +
|
| +.toc_element {
|
| + margin-top: 0.5em;
|
| +}
|
| +
|
| +.firstline {
|
| + margin-left: 2 em;
|
| +}
|
| +
|
| +.method {
|
| + margin-top: 1em;
|
| + border: solid 1px #CCC;
|
| + padding: 1em;
|
| + background: #EEE;
|
| +}
|
| +
|
| +.details {
|
| + font-weight: bold;
|
| + font-size: 14px;
|
| +}
|
| +
|
| +</style>
|
| +"""
|
| +
|
| +METHOD_TEMPLATE = """<div class="method">
|
| + <code class="details" id="$name">$name($params)</code>
|
| + <pre>$doc</pre>
|
| +</div>
|
| +"""
|
| +
|
| +COLLECTION_LINK = """<p class="toc_element">
|
| + <code><a href="$href">$name()</a></code>
|
| +</p>
|
| +<p class="firstline">Returns the $name Resource.</p>
|
| +"""
|
| +
|
| +METHOD_LINK = """<p class="toc_element">
|
| + <code><a href="#$name">$name($params)</a></code></p>
|
| +<p class="firstline">$firstline</p>"""
|
| +
|
| +BASE = 'docs/dyn'
|
| +
|
| +DIRECTORY_URI = 'https://www.googleapis.com/discovery/v1/apis?preferred=true'
|
| +
|
| +parser = argparse.ArgumentParser(description=__doc__)
|
| +
|
| +parser.add_argument('--discovery_uri_template', default=DISCOVERY_URI,
|
| + help='URI Template for discovery.')
|
| +
|
| +parser.add_argument('--discovery_uri', default='',
|
| + help=('URI of discovery document. If supplied then only '
|
| + 'this API will be documented.'))
|
| +
|
| +parser.add_argument('--directory_uri', default=DIRECTORY_URI,
|
| + help=('URI of directory document. Unused if --discovery_uri'
|
| + ' is supplied.'))
|
| +
|
| +parser.add_argument('--dest', default=BASE,
|
| + help='Directory name to write documents into.')
|
| +
|
| +
|
| +
|
| +def safe_version(version):
|
| + """Create a safe version of the verion string.
|
| +
|
| + Needed so that we can distinguish between versions
|
| + and sub-collections in URIs. I.e. we don't want
|
| + adsense_v1.1 to refer to the '1' collection in the v1
|
| + version of the adsense api.
|
| +
|
| + Args:
|
| + version: string, The version string.
|
| + Returns:
|
| + The string with '.' replaced with '_'.
|
| + """
|
| +
|
| + return version.replace('.', '_')
|
| +
|
| +
|
| +def unsafe_version(version):
|
| + """Undoes what safe_version() does.
|
| +
|
| + See safe_version() for the details.
|
| +
|
| +
|
| + Args:
|
| + version: string, The safe version string.
|
| + Returns:
|
| + The string with '_' replaced with '.'.
|
| + """
|
| +
|
| + return version.replace('_', '.')
|
| +
|
| +
|
| +def method_params(doc):
|
| + """Document the parameters of a method.
|
| +
|
| + Args:
|
| + doc: string, The method's docstring.
|
| +
|
| + Returns:
|
| + The method signature as a string.
|
| + """
|
| + doclines = doc.splitlines()
|
| + if 'Args:' in doclines:
|
| + begin = doclines.index('Args:')
|
| + if 'Returns:' in doclines[begin+1:]:
|
| + end = doclines.index('Returns:', begin)
|
| + args = doclines[begin+1: end]
|
| + else:
|
| + args = doclines[begin+1:]
|
| +
|
| + parameters = []
|
| + for line in args:
|
| + m = re.search('^\s+([a-zA-Z0-9_]+): (.*)', line)
|
| + if m is None:
|
| + continue
|
| + pname = m.group(1)
|
| + desc = m.group(2)
|
| + if '(required)' not in desc:
|
| + pname = pname + '=None'
|
| + parameters.append(pname)
|
| + parameters = ', '.join(parameters)
|
| + else:
|
| + parameters = ''
|
| + return parameters
|
| +
|
| +
|
| +def method(name, doc):
|
| + """Documents an individual method.
|
| +
|
| + Args:
|
| + name: string, Name of the method.
|
| + doc: string, The methods docstring.
|
| + """
|
| +
|
| + params = method_params(doc)
|
| + return string.Template(METHOD_TEMPLATE).substitute(
|
| + name=name, params=params, doc=doc)
|
| +
|
| +
|
| +def breadcrumbs(path, root_discovery):
|
| + """Create the breadcrumb trail to this page of documentation.
|
| +
|
| + Args:
|
| + path: string, Dot separated name of the resource.
|
| + root_discovery: Deserialized discovery document.
|
| +
|
| + Returns:
|
| + HTML with links to each of the parent resources of this resource.
|
| + """
|
| + parts = path.split('.')
|
| +
|
| + crumbs = []
|
| + accumulated = []
|
| +
|
| + for i, p in enumerate(parts):
|
| + prefix = '.'.join(accumulated)
|
| + # The first time through prefix will be [], so we avoid adding in a
|
| + # superfluous '.' to prefix.
|
| + if prefix:
|
| + prefix += '.'
|
| + display = p
|
| + if i == 0:
|
| + display = root_discovery.get('title', display)
|
| + crumbs.append('<a href="%s.html">%s</a>' % (prefix + p, display))
|
| + accumulated.append(p)
|
| +
|
| + return ' . '.join(crumbs)
|
| +
|
| +
|
| +def document_collection(resource, path, root_discovery, discovery, css=CSS):
|
| + """Document a single collection in an API.
|
| +
|
| + Args:
|
| + resource: Collection or service being documented.
|
| + path: string, Dot separated name of the resource.
|
| + root_discovery: Deserialized discovery document.
|
| + discovery: Deserialized discovery document, but just the portion that
|
| + describes the resource.
|
| + css: string, The CSS to include in the generated file.
|
| + """
|
| + collections = []
|
| + methods = []
|
| + resource_name = path.split('.')[-2]
|
| + html = [
|
| + '<html><body>',
|
| + css,
|
| + '<h1>%s</h1>' % breadcrumbs(path[:-1], root_discovery),
|
| + '<h2>Instance Methods</h2>'
|
| + ]
|
| +
|
| + # Which methods are for collections.
|
| + for name in dir(resource):
|
| + if not name.startswith('_') and callable(getattr(resource, name)):
|
| + if hasattr(getattr(resource, name), '__is_resource__'):
|
| + collections.append(name)
|
| + else:
|
| + methods.append(name)
|
| +
|
| +
|
| + # TOC
|
| + if collections:
|
| + for name in collections:
|
| + if not name.startswith('_') and callable(getattr(resource, name)):
|
| + href = path + name + '.html'
|
| + html.append(string.Template(COLLECTION_LINK).substitute(
|
| + href=href, name=name))
|
| +
|
| + if methods:
|
| + for name in methods:
|
| + if not name.startswith('_') and callable(getattr(resource, name)):
|
| + doc = getattr(resource, name).__doc__
|
| + params = method_params(doc)
|
| + firstline = doc.splitlines()[0]
|
| + html.append(string.Template(METHOD_LINK).substitute(
|
| + name=name, params=params, firstline=firstline))
|
| +
|
| + if methods:
|
| + html.append('<h3>Method Details</h3>')
|
| + for name in methods:
|
| + dname = name.rsplit('_')[0]
|
| + html.append(method(name, getattr(resource, name).__doc__))
|
| +
|
| + html.append('</body></html>')
|
| +
|
| + return '\n'.join(html)
|
| +
|
| +
|
| +def document_collection_recursive(resource, path, root_discovery, discovery):
|
| +
|
| + html = document_collection(resource, path, root_discovery, discovery)
|
| +
|
| + f = open(os.path.join(FLAGS.dest, path + 'html'), 'w')
|
| + f.write(html.encode('utf-8'))
|
| + f.close()
|
| +
|
| + for name in dir(resource):
|
| + if (not name.startswith('_')
|
| + and callable(getattr(resource, name))
|
| + and hasattr(getattr(resource, name), '__is_resource__')):
|
| + dname = name.rsplit('_')[0]
|
| + collection = getattr(resource, name)()
|
| + document_collection_recursive(collection, path + name + '.', root_discovery,
|
| + discovery['resources'].get(dname, {}))
|
| +
|
| +def document_api(name, version):
|
| + """Document the given API.
|
| +
|
| + Args:
|
| + name: string, Name of the API.
|
| + version: string, Version of the API.
|
| + """
|
| + service = build(name, version)
|
| + response, content = http.request(
|
| + uritemplate.expand(
|
| + FLAGS.discovery_uri_template, {
|
| + 'api': name,
|
| + 'apiVersion': version})
|
| + )
|
| + discovery = json.loads(content)
|
| +
|
| + version = safe_version(version)
|
| +
|
| + document_collection_recursive(
|
| + service, '%s_%s.' % (name, version), discovery, discovery)
|
| +
|
| +
|
| +def document_api_from_discovery_document(uri):
|
| + """Document the given API.
|
| +
|
| + Args:
|
| + uri: string, URI of discovery document.
|
| + """
|
| + http = httplib2.Http()
|
| + response, content = http.request(FLAGS.discovery_uri)
|
| + discovery = json.loads(content)
|
| +
|
| + service = build_from_document(discovery)
|
| +
|
| + name = discovery['version']
|
| + version = safe_version(discovery['version'])
|
| +
|
| + document_collection_recursive(
|
| + service, '%s_%s.' % (name, version), discovery, discovery)
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + FLAGS = parser.parse_args(sys.argv[1:])
|
| + if FLAGS.discovery_uri:
|
| + document_api_from_discovery_document(FLAGS.discovery_uri)
|
| + else:
|
| + http = httplib2.Http()
|
| + resp, content = http.request(
|
| + FLAGS.directory_uri,
|
| + headers={'X-User-IP': '0.0.0.0'})
|
| + if resp.status == 200:
|
| + directory = json.loads(content)['items']
|
| + for api in directory:
|
| + document_api(api['name'], api['version'])
|
| + else:
|
| + sys.exit("Failed to load the discovery document.")
|
|
|