def register_pretty(type=None, predicate=None):
    """Returns a decorator that registers the decorated function
    as the pretty printer for instances of ``type``.

    :param type: the type to register the pretty printer for, or a ``str``
                 to indicate the module and name, e.g.: ``'collections.Counter'``.
    :param predicate: a predicate function that takes one argument
                      and returns a boolean indicating if the value
                      should be handled by the registered pretty printer.

    Only one of ``type`` and ``predicate`` may be supplied. That means
    that ``predicate`` will be run on unregistered types only.

    The decorated function must accept exactly two positional arguments:

    - ``value`` to pretty print, and
    - ``ctx``, a context value.

    Here's an example of the pretty printer for OrderedDict:

    .. code:: python

        from collections import OrderedDict
        from prettyprinter import register_pretty, pretty_call

        @register_pretty(OrderedDict)
        def pretty_orderreddict(value, ctx):
            return pretty_call(ctx, OrderedDict, list(value.items()))
    """

    if type is None and predicate is None:
        raise ValueError(
            "You must provide either the 'type' or 'predicate' argument."
        )

    if type is not None and predicate is not None:
        raise ValueError(
            "You must provide either the 'type' or 'predicate' argument,"
            "but not both"
        )

    if predicate is not None:
        if not callable(predicate):
            raise ValueError(
                "Expected a callable for 'predicate', got {}".format(
                    repr(predicate)
                )
            )

    def decorator(fn):
        sig = inspect.signature(fn)

        value = None
        ctx = None

        try:
            sig.bind(value, ctx)
        except TypeError:
            fnname = '{}.{}'.format(
                fn.__module__,
                fn.__qualname__
            )
            raise ValueError(
                "Functions decorated with register_pretty must accept "
                "exactly two positional parameters: 'value' and 'ctx'. "
                "The function signature for {} was not compatible.".format(
                    fnname
                )
            )

        if type:
            if isinstance(type, str):
                # We don't wrap this with _run_pretty,
                # so that when we register this printer with an actual
                # class, we can call register_pretty(cls)(fn)
                _DEFERRED_DISPATCH_BY_NAME[type] = fn
            else:
                pretty_dispatch.register(type, partial(_run_pretty, fn))
        else:
            assert callable(predicate)
            _PREDICATE_REGISTRY.append((predicate, fn))
        return fn
    return decorator