def _is_exempt_from_public_methods(node: astroid.ClassDef) -> bool: """Check if a class is exempt from too-few-public-methods""" # If it's a typing.Namedtuple or an Enum for ancestor in node.ancestors(): if ancestor.name == "Enum" and ancestor.root().name == "enum": return True if ancestor.qname() == TYPING_NAMEDTUPLE: return True # Or if it's a dataclass if not node.decorators: return False root_locals = set(node.root().locals) for decorator in node.decorators.nodes: if isinstance(decorator, astroid.Call): decorator = decorator.func if not isinstance(decorator, (astroid.Name, astroid.Attribute)): continue if isinstance(decorator, astroid.Name): name = decorator.name else: name = decorator.attrname if name in DATACLASSES_DECORATORS and ( root_locals.intersection(DATACLASSES_DECORATORS) or DATACLASS_IMPORT in root_locals): return True return False
def _is_dataclass(node: astroid.ClassDef) -> bool: """Check if a class definition defines a Python 3.7+ dataclass :param node: The class node to check. :type node: astroid.ClassDef :returns: True if the given node represents a dataclass class. False otherwise. :rtype: bool """ if not node.decorators: return False root_locals = node.root().locals for decorator in node.decorators.nodes: if isinstance(decorator, astroid.Call): decorator = decorator.func if not isinstance(decorator, (astroid.Name, astroid.Attribute)): continue if isinstance(decorator, astroid.Name): name = decorator.name else: name = decorator.attrname if name == DATACLASS_DECORATOR and DATACLASS_DECORATOR in root_locals: return True return False
def _is_dataclass_like(node: astroid.ClassDef) -> bool: """Check if a class definition defines a Python data class A list of decorator names are introspected, such as the builtin `dataclass` decorator, as well as the popular `attrs` one from the `attrs` library. :param node: The class node to check. :type node: astroid.ClassDef :returns: `True` if the given node represents a dataclass class, `False` otherwise. :rtype: bool """ if not node.decorators: return False root_locals = set(node.root().locals) for decorator in node.decorators.nodes: if isinstance(decorator, astroid.Call): decorator = decorator.func if not isinstance(decorator, (astroid.Name, astroid.Attribute)): continue if isinstance(decorator, astroid.Name): name = decorator.name else: name = decorator.attrname if name in DATACLASSES_DECORATORS and root_locals.intersection( DATACLASSES_DECORATORS ): return True return False