PageRenderTime 69ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/googlecl/discovery/docs.py

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