def __discovery_doc_descriptor(self, services, hostname=None):
    """Builds a discovery doc for an API.

    Args:
      services: List of protorpc.remote.Service instances implementing an
        api/version.
      hostname: string, Hostname of the API, to override the value set on the
        current service. Defaults to None.

    Returns:
      A dictionary that can be deserialized into JSON in discovery doc format.

    Raises:
      ApiConfigurationError: If there's something wrong with the API
        configuration, such as a multiclass API decorated with different API
        descriptors (see the docstring for api()), or a repeated method
        signature.
    """
    merged_api_info = self.__get_merged_api_info(services)
    descriptor = self.get_descriptor_defaults(merged_api_info,
                                              hostname=hostname)

    description = merged_api_info.description
    if not description and len(services) == 1:
      description = services[0].__doc__
    if description:
      descriptor['description'] = description

    descriptor['parameters'] = self.__standard_parameters_descriptor()
    descriptor['auth'] = self.__standard_auth_descriptor(services)

    # Add namespace information, if provided
    if merged_api_info.namespace:
      descriptor['ownerDomain'] = merged_api_info.namespace.owner_domain
      descriptor['ownerName'] = merged_api_info.namespace.owner_name
      descriptor['packagePath'] = merged_api_info.namespace.package_path or ''
    else:
      if merged_api_info.owner_domain is not None:
        descriptor['ownerDomain'] = merged_api_info.owner_domain
      if merged_api_info.owner_name is not None:
        descriptor['ownerName'] = merged_api_info.owner_name
      if merged_api_info.package_path is not None:
        descriptor['packagePath'] = merged_api_info.package_path

    method_map = {}
    method_collision_tracker = {}
    rest_collision_tracker = {}

    resource_index = collections.defaultdict(list)
    resource_map = {}

    # For the first pass, only process top-level methods (that is, those methods
    # that are unattached to a resource).
    for service in services:
      remote_methods = service.all_remote_methods()

      for protorpc_meth_name, protorpc_meth_info in remote_methods.iteritems():
        method_info = getattr(protorpc_meth_info, 'method_info', None)
        # Skip methods that are not decorated with @method
        if method_info is None:
          continue
        path = method_info.get_path(service.api_info)
        method_id = method_info.method_id(service.api_info)
        canonical_method_id = self._get_canonical_method_id(method_id)
        resource_path = self._get_resource_path(method_id)

        # Make sure the same method name isn't repeated.
        if method_id in method_collision_tracker:
          raise api_exceptions.ApiConfigurationError(
              'Method %s used multiple times, in classes %s and %s' %
              (method_id, method_collision_tracker[method_id],
               service.__name__))
        else:
          method_collision_tracker[method_id] = service.__name__

        # Make sure the same HTTP method & path aren't repeated.
        rest_identifier = (method_info.http_method, path)
        if rest_identifier in rest_collision_tracker:
          raise api_exceptions.ApiConfigurationError(
              '%s path "%s" used multiple times, in classes %s and %s' %
              (method_info.http_method, path,
               rest_collision_tracker[rest_identifier],
               service.__name__))
        else:
          rest_collision_tracker[rest_identifier] = service.__name__

        # If this method is part of a resource, note it and skip it for now
        if resource_path:
          resource_index[resource_path[0]].append((service, protorpc_meth_info))
        else:
          method_map[canonical_method_id] = self.__method_descriptor(
              service, method_info, protorpc_meth_info)

    # Do another pass for methods attached to resources
    for resource, resource_methods in resource_index.items():
      resource_map[resource] = self.__resource_descriptor(resource,
          resource_methods)

    if method_map:
      descriptor['methods'] = method_map

    if resource_map:
      descriptor['resources'] = resource_map

    # Add schemas, if any
    schemas = self.__schemas_descriptor()
    if schemas:
      descriptor['schemas'] = schemas

    return descriptor
Builds a discovery doc for an API.

    Args:
      services: List of protorpc.remote.Service instances implementing an
        api/version.
      hostname: string, Hostname of the API, to override the value set on the
        current service. Defaults to None.

    Returns:
      A dictionary that can be deserialized into JSON in discovery doc format.

    Raises:
      ApiConfigurationError: If there's something wrong with the API
        configuration, such as a multiclass API decorated with different API
        descriptors (see the docstring for api()), or a repeated method
        signature.