
I can't think of a good way to annotate this design pattern with the current Python type system. You are dynamically creating a new class that subclasses from an existing class, in effect transforming the original class by adding new attributes and methods to it. This pattern shows up in a handful of popular libraries within the Python ecosystem, and static type checkers have troubles with this pattern. I've been thinking about ways that these types of "class transforms" could be described in a declarative manner for static type checkers. I'm thinking that it would be in a similar vein to the `typing.dataclass_transform` mechanism that I proposed in [this spec](https://github.com/microsoft/pyright/blob/main/specs/dataclass_transforms.md). This hypothetical `typing.class_transform` decorator would take a protocol class as an argument, and the type checker would then "merge" the protocol attributes and methods into the decorated class, creating a new transformed class in the process. This would properly model what the wrapping class does in this case. Another theoretical solution for your use case is an "intersection" type. Other languages like TypeScript have this concept as a companion to "union" types, and the idea has been discussed periodically in the typing-sig. The result of your `enhance` decorator could be `X & Wrapper`, an intersection between the class `X` and class `Wrapper`. The problem with intersection types is that they work fine for structural types (protocol classes), but their semantics become unclear when dealing with nominal types because intersections don't properly model the class hierarchy or MRO of the resulting class. If we were to add intersection types to the type system, we might need to restrict them to protocol classes, and that would mean they wouldn't work for your use case. Even if we were able to work out the rules for intersecting nominal types, the intersection would still be visible to users of your library. They'd see the resulting type as `X & Wrapper` rather than just `X`. That's not ideal because it exposes a detail that might be confusing to most users and is probably best to hide. Another option is to write a custom mypy plugin to handle this case in your library. This is what other libraries have done to work around this limitation of the type system. The downside is that you need to maintain the plugin. Also, this solution is specific to mypy. It wouldn't work with other Python type checkers or language servers. In short, I don't think there's a good solution currently. My advice for now is to avoid this pattern if you can because it will not work well with static type checking. -Eric -- Eric Traut Contributor to Pyright & Pylance Microsoft Corp.