<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def construct_settings( service_name, client_config, config_override, retry_names, bundle_descriptors=None, page_descriptors=None, metrics_headers=(), kwargs=None):
 """Constructs a dictionary mapping method names to _CallSettings. The ``client_config`` parameter is parsed from a client configuration JSON file of the form: .. code-block:: json { "interfaces": { "google.fake.v1.ServiceName": { "retry_codes": { "idempotent": ["UNAVAILABLE", "DEADLINE_EXCEEDED"], "non_idempotent": [] }, "retry_params": { "default": { "initial_retry_delay_millis": 100, "retry_delay_multiplier": 1.2, "max_retry_delay_millis": 1000, "initial_rpc_timeout_millis": 2000, "rpc_timeout_multiplier": 1.5, "max_rpc_timeout_millis": 30000, "total_timeout_millis": 45000 } }, "methods": { "CreateFoo": { "retry_codes_name": "idempotent", "retry_params_name": "default", "timeout_millis": 30000 }, "Publish": { "retry_codes_name": "non_idempotent", "retry_params_name": "default", "bundling": { "element_count_threshold": 40, "element_count_limit": 200, "request_byte_threshold": 90000, "request_byte_limit": 100000, "delay_threshold_millis": 100 } } } } } } Args: service_name (str):
 The fully-qualified name of this service, used as a key into the client config file (in the example above, this value would be ``google.fake.v1.ServiceName``). client_config (dict):
 A dictionary parsed from the standard API client config file. bundle_descriptors (Mapping[str, BundleDescriptor]):
 A dictionary of method names to BundleDescriptor objects for methods that are bundling-enabled. page_descriptors (Mapping[str, PageDescriptor]):
 A dictionary of method names to PageDescriptor objects for methods that are page streaming-enabled. config_override (str):
 A dictionary in the same structure of client_config to override the settings. Usually client_config is supplied from the default config and config_override will be specified by users. retry_names (Mapping[str, object]):
 A dictionary mapping the strings referring to response status codes to the Python objects representing those codes. metrics_headers (Mapping[str, str]):
 Dictionary of headers to be passed for analytics. Sent as a dictionary; eventually becomes a space-separated string (e.g. 'foo/1.0.0 bar/3.14.1'). kwargs (dict):
 The keyword arguments to be passed to the API calls. Returns: dict: A dictionary mapping method names to _CallSettings. Raises: KeyError: If the configuration for the service in question cannot be located in the provided ``client_config``. """

    # pylint: disable=too-many-locals
    # pylint: disable=protected-access
    defaults = {}
    bundle_descriptors = bundle_descriptors or {}
    page_descriptors = page_descriptors or {}
    kwargs = kwargs or {}

    # Sanity check: It is possible that we got this far but some headers
    # were specified with an older library, which sends them as...
    #   kwargs={'metadata': [('x-goog-api-client', 'foo/1.0 bar/3.0')]}
    #
    # Note: This is the final format we will send down to GRPC shortly.
    #
    # Remove any x-goog-api-client header that may have been present
    # in the metadata list.
    if 'metadata' in kwargs:
        kwargs['metadata'] = [value for value in kwargs['metadata']
                              if value[0].lower() != 'x-goog-api-client']

    # Fill out the metrics headers with GAX and GRPC info, and convert
    # to a string in the format that the GRPC layer expects.
    kwargs.setdefault('metadata', [])
    kwargs['metadata'].append(
        ('x-goog-api-client', metrics.stringify(metrics.fill(metrics_headers)))
    )

    try:
        service_config = client_config['interfaces'][service_name]
    except KeyError:
        raise KeyError('Client configuration not found for service: {}'
                       .format(service_name))

    overrides = config_override.get('interfaces', {}).get(service_name, {})

    for method in service_config.get('methods'):
        method_config = service_config['methods'][method]
        overriding_method = overrides.get('methods', {}).get(method, {})
        snake_name = _upper_camel_to_lower_under(method)

        if overriding_method and overriding_method.get('timeout_millis'):
            timeout = overriding_method['timeout_millis']
        else:
            timeout = method_config['timeout_millis']
        timeout /= _MILLIS_PER_SECOND

        bundle_descriptor = bundle_descriptors.get(snake_name)
        bundling_config = method_config.get('bundling', None)
        if overriding_method and 'bundling' in overriding_method:
            bundling_config = overriding_method['bundling']
        bundler = _construct_bundling(bundling_config, bundle_descriptor)

        retry_options = _merge_retry_options(
            _construct_retry(method_config, service_config['retry_codes'],
                             service_config['retry_params'], retry_names),
            _construct_retry(overriding_method, overrides.get('retry_codes'),
                             overrides.get('retry_params'), retry_names))

        defaults[snake_name] = gax._CallSettings(
            timeout=timeout, retry=retry_options,
            page_descriptor=page_descriptors.get(snake_name),
            bundler=bundler, bundle_descriptor=bundle_descriptor,
            kwargs=kwargs)
    return defaults