Inconsistent behavior in issubclass
$ python
Python 3.13.8 (main, Oct 7 2025, 12:01:51) [GCC 14.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
Ctrl click to launch VS Code Native REPL
>>> import wrapt
>>> import enum
>>> issubclass(wrapt.BaseObjectProxy(enum.StrEnum),enum.Enum)
True
>>> issubclass(wrapt.BaseObjectProxy(enum.StrEnum),enum.StrEnum)
False
>>> issubclass(enum.StrEnum,enum.StrEnum)
True
>>> issubclass(enum.StrEnum,wrapt.BaseObjectProxy(enum.StrEnum))
False
wrapt version: 2.0.1
Will need to investigate, wrapping type objects with a proxy can be problematic.
What should work okay are tests like:
from enum import StrEnum
class State(StrEnum):
STARTED = "started"
STOPPED = "stopped"
PAUSED = "paused"
isinstance(wrapt.BaseObjectProxy(State.STARTED), enum.Enum)
isinstance(wrapt.BaseObjectProxy(State.STARTED), enum.StrEnum)
That is, wrapping an instance of an enum.
Can you give the real world example demonstrating why you are wrapping the type object?
Wrapping types, such as applying a decorator to a type, has always had issues. Eg.,
- https://wrapt.readthedocs.io/en/master/issues.html#deriving-from-decorated-class
Okay, looks like I may have tried to deal with issubclass() checks in decorators by having in the function wrappers used for decorators:
def __subclasscheck__(self, subclass):
# This is a special method used by issubclass() to make checks
# about inheritance of classes. We need to upwrap any object
# proxy. Not wanting to add this to ObjectProxy as not sure of
# broader implications of doing that. Thus restrict to
# FunctionWrapper used by decorators.
if hasattr(subclass, "__wrapped__"):
return issubclass(subclass.__wrapped__, self.__wrapped__)
else:
return issubclass(subclass, self.__wrapped__)
As the comment says, this wasn't added to main ObjectProxy class as wasn't sure what implications of doing so would be.
So would need to investigate what implications might be of adding this to BaseObjectProxy.
Can you give the real world example demonstrating why you are wrapping the type object?
I am building a recording/replaying testing framework (similar to https://vcrpy.readthedocs.io/) to monkey patch classes that would be used in abitrary ways (including instantiations, class method calls and issubclass calls) in functions being tested.
Can you add that implementation of __subclasscheck__ above to your custom object proxy class and see if the issue is resolved? If it works, or we can work out a variation of it that does, then we can look at adding it to BaseObjectProxy.
issubclass(proxy := wrapt.BaseObjectProxy(enum.StrEnum), enum.StrEnum) -> triggers proxy.__bases__, which does not include StrEnum, thus returning False. The reason is that it actually triggers StrEnum.__subclasscheck__, not proxy.__subclasscheck__ and StrEnum.__subclasscheck__ internally accesses proxy.__bases__ property.
I think issubclass(wrapt.BaseObjectProxy(enum.StrEnum),enum.StrEnum) returning False might be an accepted behavior.
Supposing in tests, you do monkey patching:
my_lib.MyClass = MyProxy(my_lib.MyClass)
Then the original my_lib.MyClass should become inaccessible from user code, therefore the user code would never trigger issubclass(<patched my_lib.MyClass>, <original my_lib.MyClass>)
issubclass(enum.StrEnum, proxy := wrapt.BaseObjectProxy(enum.StrEnum)) triggers proxy.__subclasscheck__, the instance method, because BaseObjectProxy is now the metaclass of the proxy if you consider proxy itself as a type. However currently BaseObjectProxy does not forward __subclasscheck__ to __wrapped__.
Since for issubclass(enum.StrEnum, enum.StrEnum) you get True, I would not expect issubclass(wrapt.BaseObjectProxy(enum.StrEnum), enum.StrEnum) to return False.
FWIW, the whole issubclass() issue and why never did it on ObjectProxy may have been complicated by:
- https://github.com/python/cpython/issues/89010
I can't remember. I still need to sit down and properly work through this issue. My simple first check using __subclasscheck__ override didn't work, but I may have not added it in properly or constructed my test wrongly.