docs: 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