PageRenderTime 77ms CodeModel.GetById 20ms app.highlight 37ms RepoModel.GetById 16ms app.codeStats 0ms

/src/googlecl/discovery/docs.py

http://googlecl.googlecode.com/
Python | 221 lines | 183 code | 6 blank | 32 comment | 9 complexity | 0192ff44ddc0cd5adfbf6dc712275682 MD5 | raw file
  1# Copyright (C) 2011 Google Inc.
  2#
  3# Licensed under the Apache License, Version 2.0 (the "License");
  4# you may not use this file except in compliance with the License.
  5# You may obtain a copy of the License at
  6#
  7#      http://www.apache.org/licenses/LICENSE-2.0
  8#
  9# Unless required by applicable law or agreed to in writing, software
 10# distributed under the License is distributed on an "AS IS" BASIS,
 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12# See the License for the specific language governing permissions and
 13# limitations under the License.
 14
 15""" Subclass for the Discovery portion of GoogleCL which
 16    manages the documentation
 17
 18In charge of saving/loading the API directory, 
 19and retrieves and stores the Discovery documents.
 20"""
 21
 22import httplib2
 23import logging
 24
 25import simplejson as json
 26import googlecl
 27
 28LOG = logging.getLogger(googlecl.LOGGER_NAME)
 29apis_path = googlecl.get_data_path('apis.dat', create_missing_dir=True)
 30SERVICE_BLACKLIST = ['latitude']
 31LIST_URL = '%s/discovery/v1/apis?preferred=true&pp=0'
 32SERVICE_URL = '%s/discovery/v1/apis/%s/%s/rest'
 33
 34class DocManager():
 35  def __init__(self, local, base_url):
 36    self.base_url = base_url
 37    self.load()
 38    self.apis = {}
 39    self.local = local
 40    if self.local:
 41      if isinstance(self.local, list): # local comes from the config file
 42        for filename in self.local:    # Be sure to give the correct path.
 43          self.loadDoc(filename)
 44      else:
 45        self.loadDoc(self.local)
 46
 47  def load(self, force=False):
 48    """ Loads the currently saved list of preferred APIs, 
 49        or downloads the latest version.
 50        Can be forced with the command 'refresh apis'
 51
 52    Args:
 53      force: If true, the will always download a new document
 54    """
 55    try:
 56      if force:
 57        raise
 58      f = open(apis_path, 'r')
 59      self.directory = json.load(f)
 60    except:
 61      http = httplib2.Http()
 62      resp, content = http.request(LIST_URL % self.base_url)
 63      self.directory = json.loads(content)
 64      # Removes blacklisted APIs (currently just latitude)
 65      self.directory['items'] = [a for a in self.directory['items'] 
 66                                 if a['name'] not in SERVICE_BLACKLIST]
 67      f = open(apis_path, 'w')
 68      json.dump(self.directory, f, indent=2)
 69    if hasattr(self, 'local') and self.local:
 70      if isinstance(self.local, list): # local comes from the config file
 71        for filename in self.local:    # Be sure to give the correct path.
 72          self.loadDoc(filename)
 73      else:
 74        self.loadDoc(self.local)
 75
 76  def loadDoc(self, filename):
 77    """ Loads a discovery document stored locally
 78
 79    Args:
 80      filename: The file being loaded
 81    """
 82    try:
 83      doc = json.loads(file(filename).read())
 84    except:
 85      LOG.info('Failed to load ' + filename)
 86      return
 87    self.apis[doc['name']+'.'+doc['version']] = doc
 88    info = {'name': doc['name'], 'version': doc['version']}
 89    self.directory['items'].append(info)
 90
 91  def run(self, argv, isHelp, verbose):
 92    """ Parses through arguments to determine service, version, and gets docs
 93    Also prints help, if applicable
 94
 95    Args:
 96      argv: The arguments which are passed in
 97      isHelp: If help should be displayed
 98      verbose: If isHelp, then whether it should be verbose
 99    Returns:
100      If it doesn't display help, then a tuple of the service name,
101      version, documentation, and remaining args
102    """
103    http = httplib2.Http()
104
105    # Parses the service name and version
106    # If no version is defined, finds the currently preferred one
107    servicename = argv[0]
108    if len(argv) > 1:
109      version = argv[1]
110    else:
111      version = None
112    args = argv[2:]
113    if not version or not version[0] == 'v' or not version[1].isdigit():
114      version = None
115      for api in self.directory['items']:
116        if api['name'] == servicename:
117          version = api['version']
118          args = argv[1:]
119          break
120      if not version:
121        LOG.error('Did not recognize service.')
122        return
123
124    # Fetches documentation for service
125    if servicename + '.' + version in self.apis:
126      doc = self.apis[servicename + '.' + version]
127    else:
128      resp, content = http.request(SERVICE_URL % (self.base_url, servicename, version))
129      doc = json.loads(content)
130      self.apis[servicename + '.' + version] = doc
131
132    if 'error' in doc:
133      LOG.error('Did not recognize version.')
134      return
135
136    # Displays help, if requested
137    if isHelp:
138      help(doc, verbose, *args)
139      return
140
141    return servicename, version, doc, args
142
143def help(doc, verbose, *path):
144  """ Prints the help for an arbitrary service
145
146  Args:
147    doc: Discovery document for the service
148    verbose: Whether or not all information should be displayed
149    path: The path to the desired method, parameter, or other attribute
150  """
151
152  # Locates the desired object
153  # Will try to follow path implicitly (for resources, methods, parameters)
154  # otherwise the path must be fully defined (most likely useful for schemas)
155  base = doc
156  for p in path:
157    if p[:2] == '--':
158      p = p[2:]
159    if p in base:
160      base = base[p]
161    elif 'resources' in base and p in base['resources']:
162      base = base['resources'][p]
163    elif 'methods' in base and p in base['methods']:
164      base = base['methods'][p]
165    elif 'parameters' in base and p in base['parameters']:
166      base = base['parameters'][p]
167    else:
168      n = ('resources' in base) + ('methods' in base) + ('parameters' in base 
169                                                         and not base == doc)
170      while (n == 1 or len(base) == 1) and not p in base:
171        i = 0
172        if 'resources' in base: i = base.keys().index('resources')
173        elif 'methods' in base: i = base.keys().index('methods')
174        elif 'parameters' in base: i = base.keys().index('parameters')
175        base = base[base.keys()[i]]
176        n = ('resources' in base) + ('methods' in base) + ('parameters' in base)
177      if p in base:
178        base = base[p]
179      else:
180        LOG.error('Error in path: "' + p + '" not found')
181        return
182
183  # Displays the attributes of the requested object
184  # Formatted if object is base API, method, or resource and not verbose.
185  if not verbose:
186    if isinstance(base, dict):
187      if 'version' in base: #Base API
188        print ' ' + base['description']
189        print '  Resources: ' + ', '.join(base['resources'])
190      elif 'httpMethod' in base: #Method
191        print ' ' + base['description']
192        if 'parameterOrder' in base:
193          print '  Requires: ' + ' AND '.join(base['parameterOrder']) \
194          + ' Optional: ' + ', '.join([i for i in base['parameters'] if \
195          i not in base['parameterOrder']])
196        elif 'parameters' in base:
197          print '  Optional: ' + ', '.join(base['parameters'])
198        if 'request' in base:
199          print '  Request schema: ' + base['request']['$ref']
200      elif 'methods' in base or 'resources' in base: #Resource
201        if 'methods' in base:
202          print '  Methods: ' + ', '.join(base['methods'])
203        if 'resources' in base:
204          print '  Resources: ' + ', '.join(base['resources'])
205      else: #Everything else
206        for obj in base:
207          if isinstance(base[obj], dict) or isinstance(base[obj], list):
208            print '  ' + obj + ": " + ', '.join(base[obj])
209          else:
210            print '  ' + obj + ": " + str(base[obj])
211    else:
212      print base
213  else:
214    if isinstance(base, dict):
215      for obj in base:
216        if isinstance(base[obj], dict) or isinstance(base[obj], list):
217          print '  ' + obj + ": " + ', '.join(base[obj])
218        else:
219          print '  ' + obj + ": " + str(base[obj])
220    else:
221      print base