| Index: third_party/google_api_python_client/googleapiclient/schema.py | 
| diff --git a/third_party/google_api_python_client/googleapiclient/schema.py b/third_party/google_api_python_client/googleapiclient/schema.py | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..af413177f02b19d122e73102de93279c06b486c7 | 
| --- /dev/null | 
| +++ b/third_party/google_api_python_client/googleapiclient/schema.py | 
| @@ -0,0 +1,311 @@ | 
| +# 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. | 
| + | 
| +"""Schema processing for discovery based APIs | 
| + | 
| +Schemas holds an APIs discovery schemas. It can return those schema as | 
| +deserialized JSON objects, or pretty print them as prototype objects that | 
| +conform to the schema. | 
| + | 
| +For example, given the schema: | 
| + | 
| + schema = \"\"\"{ | 
| +   "Foo": { | 
| +    "type": "object", | 
| +    "properties": { | 
| +     "etag": { | 
| +      "type": "string", | 
| +      "description": "ETag of the collection." | 
| +     }, | 
| +     "kind": { | 
| +      "type": "string", | 
| +      "description": "Type of the collection ('calendar#acl').", | 
| +      "default": "calendar#acl" | 
| +     }, | 
| +     "nextPageToken": { | 
| +      "type": "string", | 
| +      "description": "Token used to access the next | 
| +         page of this result. Omitted if no further results are available." | 
| +     } | 
| +    } | 
| +   } | 
| + }\"\"\" | 
| + | 
| + s = Schemas(schema) | 
| + print s.prettyPrintByName('Foo') | 
| + | 
| + Produces the following output: | 
| + | 
| +  { | 
| +   "nextPageToken": "A String", # Token used to access the | 
| +       # next page of this result. Omitted if no further results are available. | 
| +   "kind": "A String", # Type of the collection ('calendar#acl'). | 
| +   "etag": "A String", # ETag of the collection. | 
| +  }, | 
| + | 
| +The constructor takes a discovery document in which to look up named schema. | 
| +""" | 
| + | 
| +# TODO(jcgregorio) support format, enum, minimum, maximum | 
| + | 
| +__author__ = 'jcgregorio@google.com (Joe Gregorio)' | 
| + | 
| +import copy | 
| + | 
| +from oauth2client import util | 
| + | 
| + | 
| +class Schemas(object): | 
| +  """Schemas for an API.""" | 
| + | 
| +  def __init__(self, discovery): | 
| +    """Constructor. | 
| + | 
| +    Args: | 
| +      discovery: object, Deserialized discovery document from which we pull | 
| +        out the named schema. | 
| +    """ | 
| +    self.schemas = discovery.get('schemas', {}) | 
| + | 
| +    # Cache of pretty printed schemas. | 
| +    self.pretty = {} | 
| + | 
| +  @util.positional(2) | 
| +  def _prettyPrintByName(self, name, seen=None, dent=0): | 
| +    """Get pretty printed object prototype from the schema name. | 
| + | 
| +    Args: | 
| +      name: string, Name of schema in the discovery document. | 
| +      seen: list of string, Names of schema already seen. Used to handle | 
| +        recursive definitions. | 
| + | 
| +    Returns: | 
| +      string, A string that contains a prototype object with | 
| +        comments that conforms to the given schema. | 
| +    """ | 
| +    if seen is None: | 
| +      seen = [] | 
| + | 
| +    if name in seen: | 
| +      # Do not fall into an infinite loop over recursive definitions. | 
| +      return '# Object with schema name: %s' % name | 
| +    seen.append(name) | 
| + | 
| +    if name not in self.pretty: | 
| +      self.pretty[name] = _SchemaToStruct(self.schemas[name], | 
| +          seen, dent=dent).to_str(self._prettyPrintByName) | 
| + | 
| +    seen.pop() | 
| + | 
| +    return self.pretty[name] | 
| + | 
| +  def prettyPrintByName(self, name): | 
| +    """Get pretty printed object prototype from the schema name. | 
| + | 
| +    Args: | 
| +      name: string, Name of schema in the discovery document. | 
| + | 
| +    Returns: | 
| +      string, A string that contains a prototype object with | 
| +        comments that conforms to the given schema. | 
| +    """ | 
| +    # Return with trailing comma and newline removed. | 
| +    return self._prettyPrintByName(name, seen=[], dent=1)[:-2] | 
| + | 
| +  @util.positional(2) | 
| +  def _prettyPrintSchema(self, schema, seen=None, dent=0): | 
| +    """Get pretty printed object prototype of schema. | 
| + | 
| +    Args: | 
| +      schema: object, Parsed JSON schema. | 
| +      seen: list of string, Names of schema already seen. Used to handle | 
| +        recursive definitions. | 
| + | 
| +    Returns: | 
| +      string, A string that contains a prototype object with | 
| +        comments that conforms to the given schema. | 
| +    """ | 
| +    if seen is None: | 
| +      seen = [] | 
| + | 
| +    return _SchemaToStruct(schema, seen, dent=dent).to_str(self._prettyPrintByName) | 
| + | 
| +  def prettyPrintSchema(self, schema): | 
| +    """Get pretty printed object prototype of schema. | 
| + | 
| +    Args: | 
| +      schema: object, Parsed JSON schema. | 
| + | 
| +    Returns: | 
| +      string, A string that contains a prototype object with | 
| +        comments that conforms to the given schema. | 
| +    """ | 
| +    # Return with trailing comma and newline removed. | 
| +    return self._prettyPrintSchema(schema, dent=1)[:-2] | 
| + | 
| +  def get(self, name): | 
| +    """Get deserialized JSON schema from the schema name. | 
| + | 
| +    Args: | 
| +      name: string, Schema name. | 
| +    """ | 
| +    return self.schemas[name] | 
| + | 
| + | 
| +class _SchemaToStruct(object): | 
| +  """Convert schema to a prototype object.""" | 
| + | 
| +  @util.positional(3) | 
| +  def __init__(self, schema, seen, dent=0): | 
| +    """Constructor. | 
| + | 
| +    Args: | 
| +      schema: object, Parsed JSON schema. | 
| +      seen: list, List of names of schema already seen while parsing. Used to | 
| +        handle recursive definitions. | 
| +      dent: int, Initial indentation depth. | 
| +    """ | 
| +    # The result of this parsing kept as list of strings. | 
| +    self.value = [] | 
| + | 
| +    # The final value of the parsing. | 
| +    self.string = None | 
| + | 
| +    # The parsed JSON schema. | 
| +    self.schema = schema | 
| + | 
| +    # Indentation level. | 
| +    self.dent = dent | 
| + | 
| +    # Method that when called returns a prototype object for the schema with | 
| +    # the given name. | 
| +    self.from_cache = None | 
| + | 
| +    # List of names of schema already seen while parsing. | 
| +    self.seen = seen | 
| + | 
| +  def emit(self, text): | 
| +    """Add text as a line to the output. | 
| + | 
| +    Args: | 
| +      text: string, Text to output. | 
| +    """ | 
| +    self.value.extend(["  " * self.dent, text, '\n']) | 
| + | 
| +  def emitBegin(self, text): | 
| +    """Add text to the output, but with no line terminator. | 
| + | 
| +    Args: | 
| +      text: string, Text to output. | 
| +      """ | 
| +    self.value.extend(["  " * self.dent, text]) | 
| + | 
| +  def emitEnd(self, text, comment): | 
| +    """Add text and comment to the output with line terminator. | 
| + | 
| +    Args: | 
| +      text: string, Text to output. | 
| +      comment: string, Python comment. | 
| +    """ | 
| +    if comment: | 
| +      divider = '\n' + '  ' * (self.dent + 2) + '# ' | 
| +      lines = comment.splitlines() | 
| +      lines = [x.rstrip() for x in lines] | 
| +      comment = divider.join(lines) | 
| +      self.value.extend([text, ' # ', comment, '\n']) | 
| +    else: | 
| +      self.value.extend([text, '\n']) | 
| + | 
| +  def indent(self): | 
| +    """Increase indentation level.""" | 
| +    self.dent += 1 | 
| + | 
| +  def undent(self): | 
| +    """Decrease indentation level.""" | 
| +    self.dent -= 1 | 
| + | 
| +  def _to_str_impl(self, schema): | 
| +    """Prototype object based on the schema, in Python code with comments. | 
| + | 
| +    Args: | 
| +      schema: object, Parsed JSON schema file. | 
| + | 
| +    Returns: | 
| +      Prototype object based on the schema, in Python code with comments. | 
| +    """ | 
| +    stype = schema.get('type') | 
| +    if stype == 'object': | 
| +      self.emitEnd('{', schema.get('description', '')) | 
| +      self.indent() | 
| +      if 'properties' in schema: | 
| +        for pname, pschema in schema.get('properties', {}).iteritems(): | 
| +          self.emitBegin('"%s": ' % pname) | 
| +          self._to_str_impl(pschema) | 
| +      elif 'additionalProperties' in schema: | 
| +        self.emitBegin('"a_key": ') | 
| +        self._to_str_impl(schema['additionalProperties']) | 
| +      self.undent() | 
| +      self.emit('},') | 
| +    elif '$ref' in schema: | 
| +      schemaName = schema['$ref'] | 
| +      description = schema.get('description', '') | 
| +      s = self.from_cache(schemaName, seen=self.seen) | 
| +      parts = s.splitlines() | 
| +      self.emitEnd(parts[0], description) | 
| +      for line in parts[1:]: | 
| +        self.emit(line.rstrip()) | 
| +    elif stype == 'boolean': | 
| +      value = schema.get('default', 'True or False') | 
| +      self.emitEnd('%s,' % str(value), schema.get('description', '')) | 
| +    elif stype == 'string': | 
| +      value = schema.get('default', 'A String') | 
| +      self.emitEnd('"%s",' % str(value), schema.get('description', '')) | 
| +    elif stype == 'integer': | 
| +      value = schema.get('default', '42') | 
| +      self.emitEnd('%s,' % str(value), schema.get('description', '')) | 
| +    elif stype == 'number': | 
| +      value = schema.get('default', '3.14') | 
| +      self.emitEnd('%s,' % str(value), schema.get('description', '')) | 
| +    elif stype == 'null': | 
| +      self.emitEnd('None,', schema.get('description', '')) | 
| +    elif stype == 'any': | 
| +      self.emitEnd('"",', schema.get('description', '')) | 
| +    elif stype == 'array': | 
| +      self.emitEnd('[', schema.get('description')) | 
| +      self.indent() | 
| +      self.emitBegin('') | 
| +      self._to_str_impl(schema['items']) | 
| +      self.undent() | 
| +      self.emit('],') | 
| +    else: | 
| +      self.emit('Unknown type! %s' % stype) | 
| +      self.emitEnd('', '') | 
| + | 
| +    self.string = ''.join(self.value) | 
| +    return self.string | 
| + | 
| +  def to_str(self, from_cache): | 
| +    """Prototype object based on the schema, in Python code with comments. | 
| + | 
| +    Args: | 
| +      from_cache: callable(name, seen), Callable that retrieves an object | 
| +         prototype for a schema with the given name. Seen is a list of schema | 
| +         names already seen as we recursively descend the schema definition. | 
| + | 
| +    Returns: | 
| +      Prototype object based on the schema, in Python code with comments. | 
| +      The lines of the code will all be properly indented. | 
| +    """ | 
| +    self.from_cache = from_cache | 
| +    return self._to_str_impl(self.schema) | 
|  |