I'm trying to get Pycharm's linter to stop complaining when I use a dynamically created class via the Python type( )
function. A simplified version of the actual code looks like the following.
Yes, it's weird to be working with the class object like that, but in the real code, it makes sense (SQLAlchemy ORM classes, if you're curious). Note the final line which points out the Pycharm warning.
class MyClass(object):
ID_NUM: int = 0
def __init__(self, id_num: int, first_name: str, last_name: str):
self.ID_NUM = id_num
self.first_name = first_name
self.last_name = last_name
def make_augmented_class(cls):
def augmented__eq__(self, other):
try:
return self.id_num == other.id_num
except AttributeError:
return False
new_cls = type('{}Augmented'.format(cls.__name__), tuple([cls]), {})
new_cls.__eq__ = augmented__eq__
return new_cls
def do_stuff(my_class):
print(my_class.ID_NUM)
if __name__ == '__main__':
do_stuff(MyClass)
augmented_class = make_augmented_class(MyClass)
do_stuff(augmented_class) # <=== PYCHARM CODE LINTER COMPLAINS THAT "Type 'type' doesn't have expected attribute 'ID_NUM'"
I've tried a couple of type hints for the do_stuff( )
function, such as def do_stuff(my_class: type):
and def do_stuff(my_class: MyClass):
, but that just causes different linter warnings.
The code works, but I'd like to eliminate the linter warnings somehow...
There is no good reason to use the type
function to create a class for your use case. Instead, simply create the new class in the closure of the function and return the class object so that the linter can more easily infer that the new class is a subclass of the given class. That said, I found that you would still need to type hint the argument and the returning value of the function in order for PyCharm not to complain:
from typing import TypeVar
T = TypeVar('T')
def make_augmented_class(cls: type[T]) -> type[T]:
class _AugmentingWrapper(cls):
def __eq__(self, other):
try:
return self.ID_NUM == other.ID_NUM
except AttributeError:
return False
return _AugmentingWrapper