Remove last OAuth 1.0 vestiges. Clean up comments. Fixes issue #127. Reviewed in http://codereview.appspot.com/6299050/
diff --git a/apiclient/contrib/__init__.py b/apiclient/contrib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/apiclient/contrib/__init__.py
+++ /dev/null
diff --git a/apiclient/contrib/latitude/__init__.py b/apiclient/contrib/latitude/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/apiclient/contrib/latitude/__init__.py
+++ /dev/null
diff --git a/apiclient/contrib/latitude/future.json b/apiclient/contrib/latitude/future.json
deleted file mode 100644
index 7b2bfa0..0000000
--- a/apiclient/contrib/latitude/future.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-        "baseUrl": "https://www.googleapis.com/",
-        "auth": {
-          "request": {
-            "url": "https://www.google.com/accounts/OAuthGetRequestToken",
-            "parameters": {
-              "xoauth_displayname": {
-                "parameterType": "query",
-                "required": false
-              },
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              }
-            }
-          },
-          "authorize": {
-            "url": "https://www.google.com/latitude/apps/OAuthAuthorizeToken",
-            "parameters": {
-              "oauth_token": {
-                "parameterType": "query",
-                "required": true
-              },
-              "iconUrl": {
-                "parameterType": "query",
-                "required": false
-              },
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              },
-              "location": {
-                "parameterType": "query",
-                "required": false
-              },
-              "granularity": {
-                "parameterType": "query",
-                "required": false
-              }
-            }
-          },
-          "access": {
-            "url": "https://www.google.com/accounts/OAuthGetAccessToken",
-            "parameters": {
-              "domain": {
-                "parameterType": "query",
-                "required": true
-              },
-              "scope": {
-                "parameterType": "query",
-                "required": true
-              }
-            }
-          }
-        },
-        "resources": {
-          "currentLocation": {
-            "methods": {
-              "delete": {},
-              "get": {},
-              "insert": {}
-            }
-          },
-          "location": {
-            "methods": {
-              "delete": {},
-              "get": {},
-              "insert": {},
-              "list": {}
-            }
-          }
-        }
-}
diff --git a/apiclient/contrib/moderator/__init__.py b/apiclient/contrib/moderator/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/apiclient/contrib/moderator/__init__.py
+++ /dev/null
diff --git a/apiclient/contrib/moderator/future.json b/apiclient/contrib/moderator/future.json
deleted file mode 100644
index 106bc06..0000000
--- a/apiclient/contrib/moderator/future.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
-        "baseUrl": "https://www.googleapis.com/",
-          "auth": {
-            "request": {
-              "url": "https://www.google.com/accounts/OAuthGetRequestToken",
-              "parameters": {
-                "xoauth_displayname": {
-                  "parameterType": "query",
-                  "required": false
-                },
-                "domain": {
-                  "parameterType": "query",
-                  "required": false
-                },
-                "scope": {
-                  "parameterType": "query",
-                  "required": true
-                }
-              }
-            },
-            "authorize": {
-              "url": "https://www.google.com/accounts/OAuthAuthorizeToken",
-              "parameters": {
-                "oauth_token": {
-                  "parameterType": "query",
-                  "required": true
-                },
-                "iconUrl": {
-                  "parameterType": "query",
-                  "required": false
-                },
-                "domain": {
-                  "parameterType": "query",
-                  "required": false
-                },
-                "scope": {
-                  "parameterType": "query",
-                  "required": true
-                }
-              }
-            },
-            "access": {
-              "url": "https://www.google.com/accounts/OAuthGetAccessToken",
-              "parameters": {
-                "domain": {
-                  "parameterType": "query",
-                  "required": false
-                },
-                "scope": {
-                  "parameterType": "query",
-                  "required": true
-                }
-              }
-            }
-          },
-        "resources": {
-          "profiles": {
-            "methods": {
-              "get": {}, 
-              "update": {}
-            }
-          }, 
-          "responses": {
-            "methods": {
-              "insert": {}, 
-              "list": {}
-            }
-          }, 
-          "series": {
-            "methods": {
-              "get": {}, 
-              "insert": {}, 
-              "list": {}, 
-              "update": {}
-            }
-          }, 
-          "submissions": {
-            "methods": {
-              "get": {}, 
-              "insert": {}, 
-              "list": {}
-            }
-          }, 
-          "tags": {
-            "methods": {
-              "delete": {}, 
-              "insert": {}, 
-              "list": {}
-            }
-          }, 
-          "topics": {
-            "methods": {
-              "get": {}, 
-              "insert": {}, 
-              "list": {}
-            }
-          }, 
-          "votes": {
-            "methods": {
-              "get": {}, 
-              "insert": {}, 
-              "list": {}, 
-              "update": {}
-            }
-          }
-        }
-}
diff --git a/apiclient/discovery.py b/apiclient/discovery.py
index 0c44516..3d46758 100644
--- a/apiclient/discovery.py
+++ b/apiclient/discovery.py
@@ -63,10 +63,10 @@
   '{api}/{apiVersion}/rest')
 DEFAULT_METHOD_DOC = 'A description of how to use this function'
 
-# Query parameters that work, but don't appear in discovery
-STACK_QUERY_PARAMETERS = ['trace', 'fields', 'pp', 'prettyPrint', 'userIp',
-  'userip', 'strict']
+# Parameters accepted by the stack, but not visible via discovery.
+STACK_QUERY_PARAMETERS = ['trace', 'pp', 'userip', 'strict']
 
+# Python reserved words.
 RESERVED_WORDS = ['and', 'assert', 'break', 'class', 'continue', 'def', 'del',
                   'elif', 'else', 'except', 'exec', 'finally', 'for', 'from',
                   'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or',
@@ -74,17 +74,20 @@
 
 
 def _fix_method_name(name):
+  """Fix method names to avoid reserved word conflicts.
+
+  Args:
+    name: string, method name.
+
+  Returns:
+    The name with a '_' prefixed if the name is a reserved word.
+  """
   if name in RESERVED_WORDS:
     return name + '_'
   else:
     return name
 
 
-def _write_headers(self):
-  # Utility no-op method for multipart media handling
-  pass
-
-
 def _add_query_parameter(url, name, value):
   """Adds a query parameter to a url.
 
@@ -112,6 +115,12 @@
   """Converts key names into parameter names.
 
   For example, converting "max-results" -> "max_results"
+
+  Args:
+    key: string, the method key name.
+
+  Returns:
+    A safe method name based on the key name.
   """
   result = []
   key = list(key)
@@ -135,29 +144,26 @@
           requestBuilder=HttpRequest):
   """Construct a Resource for interacting with an API.
 
-  Construct a Resource object for interacting with
-  an API. The serviceName and version are the
-  names from the Discovery service.
+  Construct a Resource object for interacting with an API. The serviceName and
+  version are the names from the Discovery service.
 
   Args:
-    serviceName: string, name of the service
-    version: string, the version of the service
+    serviceName: string, name of the service.
+    version: string, the version of the service.
     http: httplib2.Http, An instance of httplib2.Http or something that acts
       like it that HTTP requests will be made through.
-    discoveryServiceUrl: string, a URI Template that points to
-      the location of the discovery service. It should have two
-      parameters {api} and {apiVersion} that when filled in
-      produce an absolute URI to the discovery document for
-      that service.
-    developerKey: string, key obtained
-      from https://code.google.com/apis/console
-    model: apiclient.Model, converts to and from the wire format
-    requestBuilder: apiclient.http.HttpRequest, encapsulator for
-      an HTTP request
+    discoveryServiceUrl: string, a URI Template that points to the location of
+      the discovery service. It should have two parameters {api} and
+      {apiVersion} that when filled in produce an absolute URI to the discovery
+      document for that service.
+    developerKey: string, key obtained from
+      https://code.google.com/apis/console.
+    model: apiclient.Model, converts to and from the wire format.
+    requestBuilder: apiclient.http.HttpRequest, encapsulator for an HTTP
+      request.
 
   Returns:
-    A Resource object with methods for interacting with
-    the service.
+    A Resource object with methods for interacting with the service.
   """
   params = {
       'api': serviceName,
@@ -192,17 +198,8 @@
     logger.error('Failed to parse as JSON: ' + content)
     raise InvalidJsonError()
 
-  filename = os.path.join(os.path.dirname(__file__), 'contrib',
-      serviceName, 'future.json')
-  try:
-    f = file(filename, 'r')
-    future = f.read()
-    f.close()
-  except IOError:
-    future = None
-
-  return build_from_document(content, discoveryServiceUrl, future,
-      http, developerKey, model, requestBuilder)
+  return build_from_document(content, discoveryServiceUrl, http=http,
+      developerKey=developerKey, model=model, requestBuilder=requestBuilder)
 
 
 def build_from_document(
@@ -215,49 +212,37 @@
     requestBuilder=HttpRequest):
   """Create a Resource for interacting with an API.
 
-  Same as `build()`, but constructs the Resource object
-  from a discovery document that is it given, as opposed to
-  retrieving one over HTTP.
+  Same as `build()`, but constructs the Resource object from a discovery
+  document that is it given, as opposed to retrieving one over HTTP.
 
   Args:
-    service: string, discovery document
-    base: string, base URI for all HTTP requests, usually the discovery URI
-    future: string, discovery document with future capabilities
-    auth_discovery: dict, information about the authentication the API supports
+    service: string, discovery document.
+    base: string, base URI for all HTTP requests, usually the discovery URI.
+    future: string, discovery document with future capabilities (deprecated).
     http: httplib2.Http, An instance of httplib2.Http or something that acts
       like it that HTTP requests will be made through.
     developerKey: string, Key for controlling API usage, generated
       from the API Console.
-    model: Model class instance that serializes and
-      de-serializes requests and responses.
+    model: Model class instance that serializes and de-serializes requests and
+      responses.
     requestBuilder: Takes an http request and packages it up to be executed.
 
   Returns:
-    A Resource object with methods for interacting with
-    the service.
+    A Resource object with methods for interacting with the service.
   """
 
+  # future is no longer used.
+  future = {}
+
   service = simplejson.loads(service)
   base = urlparse.urljoin(base, service['basePath'])
-  if future:
-    future = simplejson.loads(future)
-    auth_discovery = future.get('auth', {})
-  else:
-    future = {}
-    auth_discovery = {}
   schema = Schemas(service)
 
   if model is None:
     features = service.get('features', [])
     model = JsonModel('dataWrapper' in features)
   resource = createResource(http, base, model, requestBuilder, developerKey,
-                       service, future, schema)
-
-  def auth_method():
-    """Discovery information about the authentication the API uses."""
-    return auth_discovery
-
-  setattr(resource, 'auth_discovery', auth_method)
+                       service, service, schema)
 
   return resource
 
@@ -292,6 +277,7 @@
     else:
       return str(value)
 
+
 MULTIPLIERS = {
     "KB": 2 ** 10,
     "MB": 2 ** 20,
@@ -301,7 +287,14 @@
 
 
 def _media_size_to_long(maxSize):
-  """Convert a string media size, such as 10GB or 3TB into an integer."""
+  """Convert a string media size, such as 10GB or 3TB into an integer.
+
+  Args:
+    maxSize: string, size as a string, such as 2MB or 7GB.
+
+  Returns:
+    The size as an integer value.
+  """
   if len(maxSize) < 2:
     return 0
   units = maxSize[-2:].upper()
@@ -313,7 +306,28 @@
 
 
 def createResource(http, baseUrl, model, requestBuilder,
-                   developerKey, resourceDesc, futureDesc, schema):
+                   developerKey, resourceDesc, rootDesc, schema):
+  """Build a Resource from the API description.
+
+  Args:
+    http: httplib2.Http, Object to make http requests with.
+    baseUrl: string, base URL for the API. All requests are relative to this
+      URI.
+    model: apiclient.Model, converts to and from the wire format.
+    requestBuilder: class or callable that instantiates an
+      apiclient.HttpRequest object.
+    developerKey: string, key obtained from
+      https://code.google.com/apis/console
+    resourceDesc: object, section of deserialized discovery document that
+      describes a resource. Note that the top level discovery document
+      is considered a resource.
+    rootDesc: object, the entire deserialized discovery document.
+    schema: object, mapping of schema names to schema descriptions.
+
+  Returns:
+    An instance of Resource with all the methods attached for interacting with
+    that resource.
+  """
 
   class Resource(object):
     """A class for interacting with a resource."""
@@ -325,7 +339,16 @@
       self._developerKey = developerKey
       self._requestBuilder = requestBuilder
 
-  def createMethod(theclass, methodName, methodDesc, futureDesc):
+  def createMethod(theclass, methodName, methodDesc, rootDesc):
+    """Creates a method for attaching to a Resource.
+
+    Args:
+      theclass: type, the class to attach methods to.
+      methodName: string, name of the method to use.
+      methodDesc: object, fragment of deserialized discovery document that
+        describes the method.
+      rootDesc: object, the entire deserialized discovery document.
+    """
     methodName = _fix_method_name(methodName)
     pathUrl = methodDesc['path']
     httpMethod = methodDesc['httpMethod']
@@ -345,6 +368,12 @@
 
     if 'parameters' not in methodDesc:
       methodDesc['parameters'] = {}
+
+    # Add in the parameters common to all methods.
+    for name, desc in rootDesc.get('parameters', {}).iteritems():
+      methodDesc['parameters'][name] = desc
+
+    # Add in undocumented query parameters.
     for name in STACK_QUERY_PARAMETERS:
       methodDesc['parameters'][name] = {
           'type': 'string',
@@ -407,6 +436,7 @@
           query_params.remove(name)
 
     def method(self, **kwargs):
+      # Don't bother with doc string, it will be over-written by createMethod.
       for name in kwargs.iterkeys():
         if name not in argmap:
           raise TypeError('Got an unexpected keyword argument "%s"' % name)
@@ -550,9 +580,15 @@
     docs = [methodDesc.get('description', DEFAULT_METHOD_DOC), '\n\n']
     if len(argmap) > 0:
       docs.append('Args:\n')
+
+    # Skip undocumented params and params common to all methods.
+    skip_parameters = rootDesc.get('parameters', {}).keys()
+    skip_parameters.append(STACK_QUERY_PARAMETERS)
+
     for arg in argmap.iterkeys():
-      if arg in STACK_QUERY_PARAMETERS:
+      if arg in skip_parameters:
         continue
+
       repeated = ''
       if arg in repeated_params:
         repeated = ' (repeated)'
@@ -583,56 +619,21 @@
     setattr(method, '__doc__', ''.join(docs))
     setattr(theclass, methodName, method)
 
-  def createNextMethodFromFuture(theclass, methodName, methodDesc, futureDesc):
-    """ This is a legacy method, as only Buzz and Moderator use the future.json
-    functionality for generating _next methods. It will be kept around as long
-    as those API versions are around, but no new APIs should depend upon it.
+  def createNextMethod(theclass, methodName, methodDesc, rootDesc):
+    """Creates any _next methods for attaching to a Resource.
+
+    The _next methods allow for easy iteration through list() responses.
+
+    Args:
+      theclass: type, the class to attach methods to.
+      methodName: string, name of the method to use.
+      methodDesc: object, fragment of deserialized discovery document that
+        describes the method.
+      rootDesc: object, the entire deserialized discovery document.
     """
     methodName = _fix_method_name(methodName)
     methodId = methodDesc['id'] + '.next'
 
-    def methodNext(self, previous):
-      """Retrieve the next page of results.
-
-      Takes a single argument, 'body', which is the results
-      from the last call, and returns the next set of items
-      in the collection.
-
-      Returns:
-        None if there are no more items in the collection.
-      """
-      if futureDesc['type'] != 'uri':
-        raise UnknownLinkType(futureDesc['type'])
-
-      try:
-        p = previous
-        for key in futureDesc['location']:
-          p = p[key]
-        url = p
-      except (KeyError, TypeError):
-        return None
-
-      url = _add_query_parameter(url, 'key', self._developerKey)
-
-      headers = {}
-      headers, params, query, body = self._model.request(headers, {}, {}, None)
-
-      logger.info('URL being requested: %s' % url)
-      resp, content = self._http.request(url, method='GET', headers=headers)
-
-      return self._requestBuilder(self._http,
-                                  self._model.response,
-                                  url,
-                                  method='GET',
-                                  headers=headers,
-                                  methodId=methodId)
-
-    setattr(theclass, methodName, methodNext)
-
-  def createNextMethod(theclass, methodName, methodDesc, futureDesc):
-    methodName = _fix_method_name(methodName)
-    methodId = methodDesc['id'] + '.next'
-
     def methodNext(self, previous_request, previous_response):
       """Retrieves the next page of results.
 
@@ -673,41 +674,35 @@
   # Add basic methods to Resource
   if 'methods' in resourceDesc:
     for methodName, methodDesc in resourceDesc['methods'].iteritems():
-      if futureDesc:
-        future = futureDesc['methods'].get(methodName, {})
-      else:
-        future = None
-      createMethod(Resource, methodName, methodDesc, future)
+      createMethod(Resource, methodName, methodDesc, rootDesc)
 
   # Add in nested resources
   if 'resources' in resourceDesc:
 
-    def createResourceMethod(theclass, methodName, methodDesc, futureDesc):
+    def createResourceMethod(theclass, methodName, methodDesc, rootDesc):
+      """Create a method on the Resource to access a nested Resource.
+
+      Args:
+        theclass: type, the class to attach methods to.
+        methodName: string, name of the method to use.
+        methodDesc: object, fragment of deserialized discovery document that
+          describes the method.
+        rootDesc: object, the entire deserialized discovery document.
+      """
       methodName = _fix_method_name(methodName)
 
       def methodResource(self):
         return createResource(self._http, self._baseUrl, self._model,
                               self._requestBuilder, self._developerKey,
-                              methodDesc, futureDesc, schema)
+                              methodDesc, rootDesc, schema)
 
       setattr(methodResource, '__doc__', 'A collection resource.')
       setattr(methodResource, '__is_resource__', True)
       setattr(theclass, methodName, methodResource)
 
     for methodName, methodDesc in resourceDesc['resources'].iteritems():
-      if futureDesc and 'resources' in futureDesc:
-        future = futureDesc['resources'].get(methodName, {})
-      else:
-        future = {}
-      createResourceMethod(Resource, methodName, methodDesc, future)
+      createResourceMethod(Resource, methodName, methodDesc, rootDesc)
 
-  # Add <m>_next() methods to Resource
-  if futureDesc and 'methods' in futureDesc:
-    for methodName, methodDesc in futureDesc['methods'].iteritems():
-      if 'next' in methodDesc and methodName in resourceDesc['methods']:
-        createNextMethodFromFuture(Resource, methodName + '_next',
-                         resourceDesc['methods'][methodName],
-                         methodDesc['next'])
   # Add _next() methods
   # Look for response bodies in schema that contain nextPageToken, and methods
   # that take a pageToken parameter.
diff --git a/tests/data/zoo.json b/tests/data/zoo.json
index 7ef0f24..b4d7cfe 100644
--- a/tests/data/zoo.json
+++ b/tests/data/zoo.json
@@ -5,6 +5,51 @@
  "description": "Zoo API used for Apiary testing",
  "basePath": "/zoo/",
  "rpcPath": "/rpc",
+ "parameters": {
+  "alt": {
+   "type": "string",
+   "description": "Data format for the response.",
+   "default": "json",
+   "enum": [
+    "json"
+   ],
+   "enumDescriptions": [
+    "Responses with Content-Type of application/json"
+   ],
+   "location": "query"
+  },
+  "fields": {
+   "type": "string",
+   "description": "Selector specifying which fields to include in a partial response.",
+   "location": "query"
+  },
+  "key": {
+   "type": "string",
+   "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
+   "location": "query"
+  },
+  "oauth_token": {
+   "type": "string",
+   "description": "OAuth 2.0 token for the current user.",
+   "location": "query"
+  },
+  "prettyPrint": {
+   "type": "boolean",
+   "description": "Returns response with indentations and line breaks.",
+   "default": "true",
+   "location": "query"
+  },
+  "quotaUser": {
+   "type": "string",
+   "description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
+   "location": "query"
+  },
+  "userIp": {
+   "type": "string",
+   "description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
+   "location": "query"
+  }
+ },
  "features": [
   "dataWrapper"
  ],