blob: 23ce65e3b3b10dceb7809457e9e6fab804924462 [file] [log] [blame]
Joe Gregorioc204b642010-09-21 12:01:23 -04001#!/usr/bin/env python
2#
Joe Gregorio9c8588a2011-07-01 12:01:36 -04003# Copyright 2011 Google Inc.
Joe Gregorioc204b642010-09-21 12:01:23 -04004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Joe Gregorio9c8588a2011-07-01 12:01:36 -040017"""Sample application for Python documentation of APIs.
18
19This is running live at http://api-python-client-doc.appspot.com where it
20provides a list of APIs and PyDoc documentation for all the generated API
21surfaces as they appear in the google-api-python-client. In addition it also
22provides a Google Gadget.
23"""
Joe Gregorioc204b642010-09-21 12:01:23 -040024
25__author__ = 'jcgregorio@google.com (Joe Gregorio)'
26
Joe Gregorioc5edb3c2011-03-18 10:54:10 -040027import httplib2
Joe Gregoriod44bb002010-09-21 14:34:44 -040028import inspect
Joe Gregorio81d92cc2012-07-09 16:46:02 -040029import logging
Joe Gregorioc5edb3c2011-03-18 10:54:10 -040030import os
Joe Gregorioc204b642010-09-21 12:01:23 -040031import pydoc
32import re
33
Joe Gregorio81d92cc2012-07-09 16:46:02 -040034import describe
35import uritemplate
36
Joe Gregorio9c8588a2011-07-01 12:01:36 -040037from apiclient import discovery
Joe Gregorio985e5402011-12-08 12:21:14 -050038from apiclient.errors import HttpError
Joe Gregorioc5edb3c2011-03-18 10:54:10 -040039from google.appengine.api import memcache
Joe Gregorioc204b642010-09-21 12:01:23 -040040from google.appengine.ext import webapp
Joe Gregorioc5edb3c2011-03-18 10:54:10 -040041from google.appengine.ext.webapp import template
Joe Gregorioc204b642010-09-21 12:01:23 -040042from google.appengine.ext.webapp import util
Joe Gregoriob4169b52012-02-14 14:42:01 -050043from oauth2client.anyjson import simplejson
Joe Gregorioc204b642010-09-21 12:01:23 -040044
Joe Gregoriod44bb002010-09-21 14:34:44 -040045
Joe Gregorio583d9e42011-09-16 15:54:15 -040046DISCOVERY_URI = 'https://www.googleapis.com/discovery/v1/apis?preferred=true'
47
48
49def get_directory_doc():
50 http = httplib2.Http(memcache)
51 ip = os.environ.get('REMOTE_ADDR', None)
52 uri = DISCOVERY_URI
53 if ip:
54 uri += ('&userIp=' + ip)
55 resp, content = http.request(uri)
56 directory = simplejson.loads(content)['items']
Joe Gregorio81d92cc2012-07-09 16:46:02 -040057 for item in directory:
58 item['title'] = item.get('title', item.get('description', ''))
59 item['safe_version'] = describe.safe_version(item['version'])
Joe Gregorio583d9e42011-09-16 15:54:15 -040060 return directory
61
62
Joe Gregorioc204b642010-09-21 12:01:23 -040063class MainHandler(webapp.RequestHandler):
Joe Gregorio9c8588a2011-07-01 12:01:36 -040064 """Handles serving the main landing page.
65 """
Joe Gregorioc204b642010-09-21 12:01:23 -040066
67 def get(self):
Joe Gregorio583d9e42011-09-16 15:54:15 -040068 directory = get_directory_doc()
Joe Gregorioc5edb3c2011-03-18 10:54:10 -040069 path = os.path.join(os.path.dirname(__file__), 'index.html')
70 self.response.out.write(
71 template.render(
72 path, {'directory': directory,
73 }))
Joe Gregorioc204b642010-09-21 12:01:23 -040074
Joe Gregorio140062f2010-09-21 16:12:41 -040075
Joe Gregorio9c8588a2011-07-01 12:01:36 -040076class GadgetHandler(webapp.RequestHandler):
Joe Gregoriob4169b52012-02-14 14:42:01 -050077 """Handles serving the Google Gadget."""
Joe Gregorio9c8588a2011-07-01 12:01:36 -040078
79 def get(self):
Joe Gregorio583d9e42011-09-16 15:54:15 -040080 directory = get_directory_doc()
Joe Gregorio9c8588a2011-07-01 12:01:36 -040081 path = os.path.join(os.path.dirname(__file__), 'gadget.html')
82 self.response.out.write(
83 template.render(
84 path, {'directory': directory,
85 }))
86 self.response.headers.add_header('Content-Type', 'application/xml')
87
88
Joe Gregoriob4169b52012-02-14 14:42:01 -050089class EmbedHandler(webapp.RequestHandler):
90 """Handles serving a front page suitable for embedding."""
91
92 def get(self):
93 directory = get_directory_doc()
Joe Gregoriob4169b52012-02-14 14:42:01 -050094 path = os.path.join(os.path.dirname(__file__), 'embed.html')
95 self.response.out.write(
96 template.render(
97 path, {'directory': directory,
98 }))
99
100
Joe Gregorio0fb19e12011-02-22 07:53:24 -0500101class ResourceHandler(webapp.RequestHandler):
Joe Gregorio9c8588a2011-07-01 12:01:36 -0400102 """Handles serving the PyDoc for a given collection.
103 """
Joe Gregorioc204b642010-09-21 12:01:23 -0400104
105 def get(self, service_name, version, collection):
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400106
107 real_version = describe.unsafe_version(version)
108
109 logging.info('%s %s %s', service_name, version, collection)
Joe Gregorio583d9e42011-09-16 15:54:15 -0400110 http = httplib2.Http(memcache)
Joe Gregorio985e5402011-12-08 12:21:14 -0500111 try:
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400112 resource = discovery.build(service_name, real_version, http=http)
Joe Gregorio985e5402011-12-08 12:21:14 -0500113 except:
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400114 logging.error('Failed to build service.')
Joe Gregorio985e5402011-12-08 12:21:14 -0500115 return self.error(404)
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400116
117 DISCOVERY_URI = ('https://www.googleapis.com/discovery/v1/apis/'
118 '{api}/{apiVersion}/rest')
119 response, content = http.request(
120 uritemplate.expand(
121 DISCOVERY_URI, {
122 'api': service_name,
123 'apiVersion': real_version})
124 )
125 root_discovery = simplejson.loads(content)
126 collection_discovery = root_discovery
127
Joe Gregorio20cfcda2010-10-26 11:58:08 -0400128 # descend the object path
Joe Gregorio0fb19e12011-02-22 07:53:24 -0500129 if collection:
Joe Gregorio985e5402011-12-08 12:21:14 -0500130 try:
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400131 path = collection.split('.')
Joe Gregorio985e5402011-12-08 12:21:14 -0500132 if path:
133 for method in path:
134 resource = getattr(resource, method)()
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400135 collection_discovery = collection_discovery['resources'][method]
Joe Gregorio985e5402011-12-08 12:21:14 -0500136 except:
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400137 logging.error('Failed to parse the collections.')
Joe Gregorio985e5402011-12-08 12:21:14 -0500138 return self.error(404)
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400139 logging.info('Built everything successfully so far.')
Joe Gregorio985e5402011-12-08 12:21:14 -0500140
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400141 path = '%s_%s.' % (service_name, version)
142 if collection:
143 path += '.'.join(collection.split('/'))
144 path += '.'
Joe Gregorio20cfcda2010-10-26 11:58:08 -0400145
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400146 page = describe.document_collection(
147 resource, path, root_discovery, collection_discovery)
Joe Gregorio20cfcda2010-10-26 11:58:08 -0400148
Joe Gregorioc204b642010-09-21 12:01:23 -0400149 self.response.out.write(page)
150
Joe Gregorio140062f2010-09-21 16:12:41 -0400151
Joe Gregorioc204b642010-09-21 12:01:23 -0400152def main():
153 application = webapp.WSGIApplication(
154 [
155 (r'/', MainHandler),
Joe Gregorio9c8588a2011-07-01 12:01:36 -0400156 (r'/_gadget/', GadgetHandler),
Joe Gregoriob4169b52012-02-14 14:42:01 -0500157 (r'/_embed/', EmbedHandler),
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400158 (r'/([^_]+)_([^\.]+)(?:\.(.*))?\.html$', ResourceHandler),
Joe Gregorioc204b642010-09-21 12:01:23 -0400159 ],
Joe Gregorio81d92cc2012-07-09 16:46:02 -0400160 debug=True)
Joe Gregorioc204b642010-09-21 12:01:23 -0400161 util.run_wsgi_app(application)
162
163
164if __name__ == '__main__':
165 main()