def is_compatible_space(space, base_space):
    """Check compatibility of a (power) space with a base space.

    Compatibility here means that the spaces are equal or ``space``
    is a non-empty power space of ``base_space`` up to different
    data types.

    Parameters
    ----------
    space, base_space : `LinearSpace`
        Spaces to check for compatibility. ``base_space`` cannot be a
        `ProductSpace`.

    Returns
    -------
    is_compatible : bool
        ``True`` if

        - ``space == base_space`` or
        - ``space.astype(base_space.dtype) == base_space``, provided that
          these properties exist, or
        - ``space`` is a power space of nonzero length and one of the three
          situations applies to ``space[0]`` (recursively).

        Otherwise ``False``.

    Examples
    --------
    Scalar spaces:

    >>> base = odl.rn(2)
    >>> is_compatible_space(odl.rn(2), base)
    True
    >>> is_compatible_space(odl.rn(3), base)
    False
    >>> is_compatible_space(odl.rn(2, dtype='float32'), base)
    True

    Power spaces:

    >>> is_compatible_space(odl.rn(2) ** 2, base)
    True
    >>> is_compatible_space(odl.rn(2) * odl.rn(3), base)  # no power space
    False
    >>> is_compatible_space(odl.rn(2, dtype='float32') ** 2, base)
    True
    """
    if isinstance(base_space, ProductSpace):
        return False

    if isinstance(space, ProductSpace):
        if not space.is_power_space:
            return False
        elif len(space) == 0:
            return False
        else:
            return is_compatible_space(space[0], base_space)
    else:
        if hasattr(space, 'astype') and hasattr(base_space, 'dtype'):
            # TODO: maybe only the shape should play a role?
            comp_space = space.astype(base_space.dtype)
        else:
            comp_space = space

        return comp_space == base_space