docs: def _stub_obj(obj):
      '''
      Stub an object directly.
      '''
      # Annoying circular reference requires importing here. Would like to see
      # this cleaned up. @AW
      from .mock import Mock
  
      # Return an existing stub
      if isinstance(obj, Stub):
          return obj
  
      # If a Mock object, stub its __call__
      if isinstance(obj, Mock):
          return stub(obj.__call__)
  
      # If passed-in a type, assume that we're going to stub out the creation.
      # See StubNew for the awesome sauce.
      # if isinstance(obj, types.TypeType):
      if hasattr(types, 'TypeType') and isinstance(obj, types.TypeType):
          return StubNew(obj)
      elif hasattr(__builtins__, 'type') and \
              isinstance(obj, __builtins__.type):
          return StubNew(obj)
      elif inspect.isclass(obj):
          return StubNew(obj)
  
      # I thought that types.UnboundMethodType differentiated these cases but
      # apparently not.
      if isinstance(obj, types.MethodType):
          # Handle differently if unbound because it's an implicit "any instance"
          if getattr(obj, 'im_self', None) is None:
              # Handle the python3 case and py2 filter
              if hasattr(obj, '__self__'):
                  if obj.__self__ is not None:
                      return StubMethod(obj)
              if sys.version_info.major == 2:
                  return StubUnboundMethod(obj)
          else:
              return StubMethod(obj)
  
      # These aren't in the types library
      if type(obj).__name__ == 'method-wrapper':
          return StubMethodWrapper(obj)
  
      if type(obj).__name__ == 'wrapper_descriptor':
          raise UnsupportedStub(
              "must call stub(obj,'%s') for slot wrapper on %s",
              obj.__name__, obj.__objclass__.__name__)
  
      # (Mostly) Lastly, look for properties.
      # First look for the situation where there's a reference back to the
      # property.
      prop = obj
      if isinstance(getattr(obj, '__self__', None), property):
          obj = prop.__self__
  
      # Once we've found a property, we have to figure out how to reference
      # back to the owning class. This is a giant pain and we have to use gc
      # to find out where it comes from. This code is dense but resolves to
      # something like this:
      # >>> gc.get_referrers( foo.x )
      # [{'__dict__': <attribute '__dict__' of 'foo' objects>,
      #   'x': <property object at 0x7f68c99a16d8>,
      #   '__module__': '__main__',
      #   '__weakref__': <attribute '__weakref__' of 'foo' objects>,
      #   '__doc__': None}]
      if isinstance(obj, property):
          klass, attr = None, None
          for ref in gc.get_referrers(obj):
              if klass and attr:
                  break
              if isinstance(ref, dict) and ref.get('prop', None) is obj:
                  klass = getattr(
                      ref.get('__dict__', None), '__objclass__', None)
                  for name, val in getattr(klass, '__dict__', {}).items():
                      if val is obj:
                          attr = name
                          break
              # In the case of PyPy, we have to check all types that refer to
              # the property, and see if any of their attrs are the property
              elif isinstance(ref, type):
                  # Use dir as a means to quickly walk through the class tree
                  for name in dir(ref):
                      if getattr(ref, name) == obj:
                          klass = ref
                          attr = name
                          break
  
          if klass and attr:
              rval = stub(klass, attr)
              if prop != obj:
                  return stub(rval, prop.__name__)
              return rval
  
      # If a function and it has an associated module, we can mock directly.
      # Note that this *must* be after properties, otherwise it conflicts with
      # stubbing out the deleter methods and such
      # Sadly, builtin functions and methods have the same type, so we have to
      # use the same stub class even though it's a bit ugly
      if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType,
                    types.BuiltinMethodType)) and hasattr(obj, '__module__'):
          return StubFunction(obj)
  
      raise UnsupportedStub("can't stub %s", obj)