From 9d56b5a4253f9a255cb4f8607549265148e05c2c Mon Sep 17 00:00:00 2001 From: Joe Gregorio Date: Fri, 30 Mar 2012 09:21:26 -0400 Subject: [PATCH] Automatically generate Samples wiki page from README files. Reviewed in http://codereview.appspot.com/5900069/. Index: samples-index.py =================================================================== new file mode 100644 --- Makefile | 5 + samples-index.py | 229 +++++++++++++++++++++++++++ samples/adexchangebuyer/README | 4 + samples/adsense/README | 4 + samples/analytics/README | 4 + samples/api-python-client-doc/README | 9 +- samples/appengine/README | 5 + samples/appengine_with_robots/README | 5 + samples/audit/README | 4 + samples/blogger/README | 4 + samples/customsearch/README | 4 + samples/dailymotion/README | 3 + samples/django_sample/README | 4 + samples/groupssettings/README | 4 + samples/gtaskqueue_sample/README | 3 + samples/latitude/README | 4 + samples/moderator/README | 4 + samples/plus/README | 4 + samples/prediction/README | 9 +- samples/searchforshopping/README | 4 + samples/service_account/README | 4 + samples/tasks_appengine/README | 3 + samples/threadqueue/README | 4 + samples/translate/README | 5 + samples/tz/README | 3 + samples/urlshortener/README | 4 + 26 files changed, 331 insertions(+), 8 deletions(-) create mode 100644 samples-index.py create mode 100644 samples/adexchangebuyer/README create mode 100644 samples/adsense/README create mode 100644 samples/analytics/README create mode 100644 samples/appengine/README create mode 100644 samples/appengine_with_robots/README create mode 100644 samples/audit/README create mode 100644 samples/blogger/README create mode 100644 samples/customsearch/README create mode 100644 samples/dailymotion/README create mode 100644 samples/django_sample/README create mode 100644 samples/groupssettings/README create mode 100644 samples/latitude/README create mode 100644 samples/moderator/README create mode 100644 samples/plus/README create mode 100644 samples/searchforshopping/README create mode 100644 samples/service_account/README create mode 100644 samples/threadqueue/README create mode 100644 samples/translate/README create mode 100644 samples/urlshortener/README diff --git a/Makefile b/Makefile index 8d6962b..3786b7f 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,11 @@ coverage: docs: cd docs; ./build.sh python describe.py + python samples-index.py ../google-api-python-client.wiki/SampleApps.wiki + +.PHONY: wiki +wiki: + python samples-index.py > ../google-api-python-client.wiki/SampleApps.wiki .PHONY: prerelease prerelease: diff --git a/samples-index.py b/samples-index.py new file mode 100644 index 0000000..35e1c16 --- /dev/null +++ b/samples-index.py @@ -0,0 +1,229 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 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. + +"""Build wiki page with a list of all samples. + +The information for the wiki page is built from data found in all the README +files in the samples. The format of the README file is: + + + Description is everything up to the first blank line. + + api: plus (Used to look up the long name in discovery). + keywords: appengine (such as appengine, oauth2, cmdline) + + The rest of the file is ignored when it comes to building the index. +""" + +import httplib2 +import itertools +import json +import os +import re + +http = httplib2.Http('.cache') +r, c = http.request('https://www.googleapis.com/discovery/v1/apis') +if r.status != 200: + raise ValueError('Received non-200 response when retrieving Discovery document.') + +# Dictionary mapping api names to their discovery description. +DIRECTORY = {} +for item in json.loads(c)['items']: + if item['preferred']: + DIRECTORY[item['name']] = item + +# A list of valid keywords. Should not be taken as complete, add to +# this list as needed. +KEYWORDS = { + 'appengine': 'Google App Engine', + 'oauth2': 'OAuth 2.0', + 'cmdline': 'Command-line', + 'django': 'Django', + 'threading': 'Threading', + 'pagination': 'Pagination' + } + + +def get_lines(name, lines): + """Return lines that begin with name. + + Lines are expected to look like: + + name: space separated values + + Args: + name: string, parameter name. + lines: iterable of string, lines in the file. + + Returns: + List of values in the lines that match. + """ + retval = [] + matches = itertools.ifilter(lambda x: x.startswith(name + ':'), lines) + for line in matches: + retval.extend(line[len(name)+1:].split()) + return retval + + +def wiki_escape(s): + """Detect WikiSyntax (i.e. InterCaps, a.k.a. CamelCase) and escape it.""" + ret = [] + for word in s.split(): + if re.match(r'[A-Z]+[a-z]+[A-Z]', word): + word = '!%s' % word + ret.append(word) + return ' '.join(ret) + + +def context_from_sample(api, keywords, dirname, desc): + """Return info for expanding a sample into a template. + + Args: + api: string, name of api. + keywords: list of string, list of keywords for the given api. + dirname: string, directory name of the sample. + desc: string, long description of the sample. + + Returns: + A dictionary of values useful for template expansion. + """ + if api is None: + return None + else: + entry = DIRECTORY[api] + context = { + 'api': api, + 'version': entry['version'], + 'api_name': wiki_escape(entry.get('title', entry.get('description'))), + 'api_desc': wiki_escape(entry['description']), + 'api_icon': entry['icons']['x32'], + 'keywords': keywords, + 'dir': dirname, + 'dir_escaped': dirname.replace('/', '%2F'), + 'desc': wiki_escape(desc), + } + return context + + +def keyword_context_from_sample(keywords, dirname, desc): + """Return info for expanding a sample into a template. + + Sample may not be about a specific sample. + + Args: + keywords: list of string, list of keywords for the given api. + dirname: string, directory name of the sample. + desc: string, long description of the sample. + + Returns: + A dictionary of values useful for template expansion. + """ + context = { + 'keywords': keywords, + 'dir': dirname, + 'dir_escaped': dirname.replace('/', '%2F'), + 'desc': wiki_escape(desc), + } + return context + + +def scan_readme_files(dirname): + """Scans all subdirs of dirname for README files. + + Args: + dirname: string, name of directory to walk. + + Returns: + (samples, keyword_set): list of information about all samples, the union + of all keywords found. + """ + samples = [] + keyword_set = set() + + for root, dirs, files in os.walk(dirname): + if 'README' in files: + filename = os.path.join(root, 'README') + with open(filename, 'r') as f: + content = f.read() + lines = content.splitlines() + desc = ' '.join(itertools.takewhile(lambda x: x, lines)) + api = get_lines('api', lines) + keywords = get_lines('keywords', lines) + + for k in keywords: + if k not in KEYWORDS: + raise ValueError( + '%s is not a valid keyword in file %s' % (k, filename)) + keyword_set.update(keywords) + if not api: + api = [None] + samples.append((api[0], keywords, root[1:], desc)) + + samples.sort() + + return samples, keyword_set + + +def main(): + # Get all the information we need out of the README files in the samples. + samples, keyword_set = scan_readme_files('./samples') + + # Now build a wiki page with all that information. Accumulate all the + # information as string to be concatenated when were done. + page = ['\n= Samples By API =\n'] + + # All the samples, grouped by API. + current_api = None + for api, keywords, dirname, desc in samples: + context = context_from_sample(api, keywords, dirname, desc) + if context is None: + continue + if current_api != api: + page.append(""" +=== %(api_icon)s %(api_name)s === + +%(api_desc)s + +Documentation for the %(api_name)s in [http://api-python-client-doc.appspot.com/%(api)s/%(version)s PyDoc] + +""" % context) + current_api = api + + page.append('|| [http://code.google.com/p/google-api-python-client/source/browse/#hg%(dir_escaped)s %(dir)s] || %(desc)s ||\n' % context) + + # Now group the samples by keywords. + for keyword, keyword_name in KEYWORDS.iteritems(): + if keyword not in keyword_set: + continue + page.append('\n= %s Samples =\n\n' % keyword_name) + page.append('\n') + for _, keywords, dirname, desc in samples: + context = keyword_context_from_sample(keywords, dirname, desc) + if keyword not in keywords: + continue + page.append(""" + + + +""" % context) + page.append('
[http://code.google.com/p/google-api-python-client/source/browse/#hg%(dir_escaped)s %(dir)s] %(desc)s
\n') + + print ''.join(page) + + +if __name__ == '__main__': + main() diff --git a/samples/adexchangebuyer/README b/samples/adexchangebuyer/README new file mode 100644 index 0000000..87ad8c4 --- /dev/null +++ b/samples/adexchangebuyer/README @@ -0,0 +1,4 @@ +Samples for working with the Ad Exchange Buyer API. + +api: adexchangebuyer +keywords: cmdline diff --git a/samples/adsense/README b/samples/adsense/README new file mode 100644 index 0000000..b2f88ac --- /dev/null +++ b/samples/adsense/README @@ -0,0 +1,4 @@ +A collection of command-line samples for the AdSense Management API. + +api: adsense +keywords: cmdline diff --git a/samples/analytics/README b/samples/analytics/README new file mode 100644 index 0000000..8b3860a --- /dev/null +++ b/samples/analytics/README @@ -0,0 +1,4 @@ +Command-line samples for producting reports with the Analytics API. + +api: analytics +keywords: cmdline diff --git a/samples/api-python-client-doc/README b/samples/api-python-client-doc/README index 835a60c..bcbf475 100644 --- a/samples/api-python-client-doc/README +++ b/samples/api-python-client-doc/README @@ -1,6 +1,5 @@ -This sample is the code that drives +This sample is the code that drives http://api-python-client-doc.appspot.com/ +It is an application that serves up the Python help documentation for each API. - http://api-python-client-doc.appspot.com/ - -It is an application that serves up the Python help documentation -for each API. +api: discovery +keywords: appengine diff --git a/samples/appengine/README b/samples/appengine/README new file mode 100644 index 0000000..68befe7 --- /dev/null +++ b/samples/appengine/README @@ -0,0 +1,5 @@ +Simple Google+ sample that demonstrates the people API. Demontrates +using the OAuth 2.0 Decorator for Google App Engine applications. + +api: plus +keywords: appengine oauth2 diff --git a/samples/appengine_with_robots/README b/samples/appengine_with_robots/README new file mode 100644 index 0000000..277df01 --- /dev/null +++ b/samples/appengine_with_robots/README @@ -0,0 +1,5 @@ +Sample application that demonstrates how to use AppAssertionCredentials +to access an API. + +api: urlshortener +keywords: appengine oauth2 diff --git a/samples/audit/README b/samples/audit/README new file mode 100644 index 0000000..5fcb803 --- /dev/null +++ b/samples/audit/README @@ -0,0 +1,4 @@ +Prints the activities for a domain using the Audit API. + +api: audit +keywords: cmdline diff --git a/samples/blogger/README b/samples/blogger/README new file mode 100644 index 0000000..3c6dda5 --- /dev/null +++ b/samples/blogger/README @@ -0,0 +1,4 @@ +Retrieve the list of blogs and their posts for a user. + +api: blogger +keywords: cmdline diff --git a/samples/customsearch/README b/samples/customsearch/README new file mode 100644 index 0000000..144f598 --- /dev/null +++ b/samples/customsearch/README @@ -0,0 +1,4 @@ +Search from the command-line. + +api: customsearch +keywords: cmdline diff --git a/samples/dailymotion/README b/samples/dailymotion/README new file mode 100644 index 0000000..7139bde --- /dev/null +++ b/samples/dailymotion/README @@ -0,0 +1,3 @@ +Demonstrates using oauth2client against the DailyMotion API. + +keywords: oauth2 appengine diff --git a/samples/django_sample/README b/samples/django_sample/README new file mode 100644 index 0000000..3aaeda8 --- /dev/null +++ b/samples/django_sample/README @@ -0,0 +1,4 @@ +Sample app demonstrating using oauth2client and the Google+ API from Django. + +api: plus +keywords: oauth2 django diff --git a/samples/groupssettings/README b/samples/groupssettings/README new file mode 100644 index 0000000..432997a --- /dev/null +++ b/samples/groupssettings/README @@ -0,0 +1,4 @@ +Sample for the Groups Settings API. + +api: groupssettings +keywords: cmdline diff --git a/samples/gtaskqueue_sample/README b/samples/gtaskqueue_sample/README index 6535127..f823db0 100644 --- a/samples/gtaskqueue_sample/README +++ b/samples/gtaskqueue_sample/README @@ -1,6 +1,9 @@ This acts as a sample as well as commandline tool for accessing Google TaskQueue APIs. +api: taskqueue +keywords: cmdline + Installation ============ diff --git a/samples/latitude/README b/samples/latitude/README new file mode 100644 index 0000000..2737a03 --- /dev/null +++ b/samples/latitude/README @@ -0,0 +1,4 @@ +Add a new location via the Latitude API. + +api: latitude +keywords: cmdline diff --git a/samples/moderator/README b/samples/moderator/README new file mode 100644 index 0000000..d135bfe --- /dev/null +++ b/samples/moderator/README @@ -0,0 +1,4 @@ +Create new Moderator series and topics via the Moderator API. + +api: moderator +keywords: cmdline diff --git a/samples/plus/README b/samples/plus/README new file mode 100644 index 0000000..f9d59de --- /dev/null +++ b/samples/plus/README @@ -0,0 +1,4 @@ +Loop over all a user's activities and print a short snippet. + +api: plus +keywords: cmdline pagination diff --git a/samples/prediction/README b/samples/prediction/README index b8c3b42..b0a37b8 100644 --- a/samples/prediction/README +++ b/samples/prediction/README @@ -1,5 +1,8 @@ Before you can run the prediction sample prediction.py, you must load some csv -formatted data into Google Storage. You can do this by running setup.sh with a -bucket/object name of your choice. You must first create the bucket you want to -use. This can be done with the gsutil function or via the web UI (Storage +formatted data into Google Storage. You can do this by running setup.sh with a +bucket/object name of your choice. You must first create the bucket you want +to use. This can be done with the gsutil function or via the web UI (Storage Access) in the Google APIs Console. + +api: prediction +keywords: cmdline diff --git a/samples/searchforshopping/README b/samples/searchforshopping/README new file mode 100644 index 0000000..aaa1dd0 --- /dev/null +++ b/samples/searchforshopping/README @@ -0,0 +1,4 @@ +Samples demonstrating the query capabilities for the Search API for Shopping. + +api: shopping +keywords: cmdline diff --git a/samples/service_account/README b/samples/service_account/README new file mode 100644 index 0000000..7662df5 --- /dev/null +++ b/samples/service_account/README @@ -0,0 +1,4 @@ +Sample that demonstrates working with Service Accounts. + +api: tasks +keywords: oauth2 diff --git a/samples/tasks_appengine/README b/samples/tasks_appengine/README index 56da2e8..6888c35 100644 --- a/samples/tasks_appengine/README +++ b/samples/tasks_appengine/README @@ -1,2 +1,5 @@ Sample code for Getting Started with Tasks API on App Engine article. http://code.google.com/appengine/articles/python/getting_started_with_tasks_api.html + +api: tasks +keywords: appengine diff --git a/samples/threadqueue/README b/samples/threadqueue/README new file mode 100644 index 0000000..4baa99a --- /dev/null +++ b/samples/threadqueue/README @@ -0,0 +1,4 @@ +Demonstrates using threading and thread queues for handling a high volume of requests. + +api: moderator +keywords: cmdline threading diff --git a/samples/translate/README b/samples/translate/README new file mode 100644 index 0000000..6bde24c --- /dev/null +++ b/samples/translate/README @@ -0,0 +1,5 @@ +Simple sample for the translate API. + +api: translate +keywords: cmdline + diff --git a/samples/tz/README b/samples/tz/README index ecee023..1afa540 100644 --- a/samples/tz/README +++ b/samples/tz/README @@ -4,6 +4,9 @@ based on the user's location, as determined by Google Latitude. To use this application you will need Google Latitude running on a mobile device. +api: latitude +keywords: cmdline + Installation ============ The google-api-python-client library will need to diff --git a/samples/urlshortener/README b/samples/urlshortener/README new file mode 100644 index 0000000..a33e8a8 --- /dev/null +++ b/samples/urlshortener/README @@ -0,0 +1,4 @@ +Shortens and URL with the URL Shortener API. + +api: urlshortener +keywords: cmdline