curved-manchester-66006
04/03/2024, 5:47 PM@abc.abstractmethod
on a class that doesn't derive from abc.ABC
?wide-midnight-78598
04/03/2024, 6:57 PMwide-midnight-78598
04/03/2024, 6:58 PMclass MissingABCVisitor(ast.NodeVisitor):
def __init__(self) -> None:
super().__init__()
self.has_abc = False
def visit_ClassDef(self, node: ast.ClassDef):
"""Check if the class has a base class of ABC or a metaclass of ABCMeta"""
for base in node.bases:
if isinstance(base, ast.Name):
if "abc" in base.id.lower():
self.has_abc = True
if isinstance(base, ast.Attribute):
if "abc" in base.attr.lower():
self.has_abc = True
for kw in node.keywords:
if kw.arg != "metaclass":
continue
if isinstance(kw.value, ast.Name):
if "abcmeta" in kw.value.id.lower():
self.has_abc = True
if isinstance(kw.value, ast.Attribute):
if "abcmeta" in kw.value.attr.lower():
self.has_abc = True
super().generic_visit(node)
def visit_FunctionDef(self, node: ast.FunctionDef):
"""Check if the function has a decorator of abc.abstractmethod"""
if self.has_abc:
return
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if "abstractmethod" in decorator.attr.lower():
print(f"{node.name} has abc.abstractmethod decorator but no ABC base class or ABCMeta metaclass")
if isinstance(decorator, ast.Name):
if "abstractmethod" in decorator.id.lower():
print(f"{node.name} has abc.abstractmethod decorator but no ABC base class or ABCMeta metaclass")
wide-midnight-78598
04/03/2024, 7:00 PMa = """
class A(metaclass=abc.ABCMeta):
@abc.abstractmethod
def func_a(self):
...
"""
b = """
class B:
@abc.abstractmethod
def func_b(self):
...
"""
c = """
class C(abc.ABC):
@abc.abstractmethod
def func_c(self):
...
"""
d = """
class D(ABC):
@abc.abstractmethod
def func_d(self):
...
"""
e = """
class E(metaclass=ABCMeta):
@abc.abstractmethod
def func_e(self):
...
"""
f = """
class F(metaclass=ABCMeta):
@abstractmethod
def hello(self):
...
"""
for code in [a, b, c, d, e, f]:
visitor = MissingABCVisitor()
tree = ast.parse(code)
visitor.visit(tree)