Wraps support for classes

Currently, functools.wraps fail for classes:

class A:
    pass

@functools.wraps(A)
class B:
    pass

Fail with:

AttributeError: 'mappingproxy' object has no attribute 'update'

This is because functools.update_wrapper try to mutate the __dict__, which is not possible for class.

It would be relatively easy to fix by using setattr(cls,...) rather than mutating cls.__dict__:

def update_wrapper(wrapper, wrapped):
  """Same as `functools.update_wrapper`, but supports class."""
  for name in functools.WRAPPER_ASSIGNMENTS:
    try:
      value = getattr(wrapped, name)
    except AttributeError:
      pass
    else:
      setattr(wrapper, name, value)
  return wrapper

There is a clear need for functool.wraps to operate on functions.

What is the purpose of “wrapping a class”? Do you have any use-cases?

My use-case for example was to wrap an Exception so my custom exception behave like the original one.

@wraps(exc_cls)
class ExceptionWrapper(exc_cls):
  ...

raise ExceptionWrapper  # Made it looks like this is an `exc_cls`

What do you mean by “behaves like”? What would you like the traceback to look like? Did you have a particular exception in mind?

Just pass updated=() in wraps().

1 Like