from typing import Mapping


def _turn_iterable_to_mapping_from_attribute(attribute, obj, optional=False):
    """
    Given ``obj`` which is either something that is an instance of ``Mapping``
    or an iterable, return something that implements ``Mapping`` from
    ``getattr(o, attribute)`` to the value of the items in the iterable. This
    funky signature is required to be a valid field factory function.

    :param attribute: The name of the attribute that should be the key in the
        resulting Mapping.
    :param obj: Either something that is a Mapping (which is immediately
        returned), or an iterable to be converted into a Mapping. If this is an
        iterable, then all of the objects in the iterable must have an
        attribute named ``attribute``.
    :param optional bool: If True, pass None through this function. This allows
        the underlying field to be optional

    :returns: A Mapping of the items in ``obj`` from
        ``getattr(o, attribute)`` to the items in obj (``o`` in ``obj``).
    """
    if optional:
        if obj is None:
            return None
    if isinstance(obj, Mapping):
        return obj
    return {getattr(a, attribute): a for a in obj}