Repository: scipy/scipy
File: scipy/signal/_signaltools.py (Python)

Code before:
            expected_shape[axis] = b.shape[0] - 1
            expected_shape = tuple(expected_shape)
            # check the trivial case where zi is the right shape first
            if zi.shape != expected_shape:
                strides = zi.ndim * [None]
                if axis < 0:
                    axis += zi.ndim
                for k in range(zi.ndim):
                    if k == axis and zi.shape[k] == expected_shape[k]:
                        strides[k] = zi.strides[k]
                    elif k != axis and zi.shape[k] == expected_shape[k]:
                        strides[k] = zi.strides[k]
                    elif k != axis and zi.shape[k] == 1:
                        strides[k] = 0
                    else:
                        raise ValueError('Unexpected shape for parameter zi: expected '
                                         f'{expected_shape}, found {zi.shape}.')
                zi = np.lib.stride_tricks.as_strided(zi, expected_shape,
                                                     strides)
            inputs.append(zi)
        dtype = np.result_type(*inputs)

        if dtype.char not in 'fdgFDGO':
            p_types = tuple(p_.dtype.char for p_ in inputs)
            raise NotImplementedError("Parameter dtypes must be convertible to one of "
                                      f"'fdgFDGO'! Given input dtypes are {p_types}.")

        b = np.array(b, dtype=dtype)
        a = np.asarray(a, dtype=dtype)
        b /= a[0]
        x = np.asarray(x, dtype=dtype)

        out_full = np.apply_along_axis(lambda y: np.convolve(b, y), axis, x)
        ind = out_full.ndim * [slice(None)]
        if zi is not None:
            ind[axis] = slice(zi.shape[axis])
            out_full[tuple(ind)] += zi

        ind[axis] = slice(out_full.shape[axis] - len(b) + 1)
        out = out_full[tuple(ind)]

        if zi is None:
            return xp.asarray(out)
        else:
            ind[axis] = slice(out_full.shape[axis] - len(b) + 1, None)
            zf = out_full[tuple(ind)]
            return xp.asarray(out), xp.asarray(zf)
    else:
        if zi is None:
            result =_sigtools._linear_filter(b, a, x, axis)
            return xp.asarray(result)

Review comment (suggestion):
Character codes are very obscure and shouldn't be used in error messages. And object dtype is best left out. I think it's hard to improve this error message, since the "can be coerced to a real or complex floating point dtype" isn't very understandable for a user. I'd lean towards not changing the current message.

Code after:
            expected_shape[axis] = b.shape[0] - 1
            expected_shape = tuple(expected_shape)
            # check the trivial case where zi is the right shape first
            if zi.shape != expected_shape:
                strides = zi.ndim * [None]
                if axis < 0:
                    axis += zi.ndim
                for k in range(zi.ndim):
                    if k == axis and zi.shape[k] == expected_shape[k]:
                        strides[k] = zi.strides[k]
                    elif k != axis and zi.shape[k] == expected_shape[k]:
                        strides[k] = zi.strides[k]
                    elif k != axis and zi.shape[k] == 1:
                        strides[k] = 0
                    else:
                        raise ValueError('Unexpected shape for parameter zi: expected '
                                         f'{expected_shape}, found {zi.shape}.')
                zi = np.lib.stride_tricks.as_strided(zi, expected_shape,
                                                     strides)
            inputs.append(zi)
        dtype = np.result_type(*inputs)

        if dtype.char not in 'fdgFDGO':
            raise NotImplementedError("Parameter's dtypes produced result type " +
                                      f"'{dtype}', which is not supported!")

        b = np.array(b, dtype=dtype)
        a = np.asarray(a, dtype=dtype)
        b /= a[0]
        x = np.asarray(x, dtype=dtype)

        out_full = np.apply_along_axis(lambda y: np.convolve(b, y), axis, x)
        ind = out_full.ndim * [slice(None)]
        if zi is not None:
            ind[axis] = slice(zi.shape[axis])
            out_full[tuple(ind)] += zi

        ind[axis] = slice(out_full.shape[axis] - len(b) + 1)
        out = out_full[tuple(ind)]

        if zi is None:
            return xp.asarray(out)
        else:
            ind[axis] = slice(out_full.shape[axis] - len(b) + 1, None)
            zf = out_full[tuple(ind)]
            return xp.asarray(out), xp.asarray(zf)
    else:
        if zi is None:
            result =_sigtools._linear_filter(b, a, x, axis)
            return xp.asarray(result)
        else: