def object_build_methoddescriptor( node: nodes.Module | nodes.ClassDef, member: _FunctionTypes, localname: str, ) -> None: """create astroid for a living method descriptor object""" # FIXME get arguments ? func = build_function(getattr(member, "__name__", None) or localname, doc=member.__doc__) node.add_local_node(func, localname) _add_dunder_class(func, member)
def _check_docstring( self, node_type: str, node: nodes.Module | nodes.ClassDef | nodes.FunctionDef) -> None: docstring = node.doc_node.value if node.doc_node else None if docstring and docstring[0] == "\n": self.add_message( "docstring-first-line-empty", node=node, args=(node_type, ), confidence=HIGH, ) # Use "linecache", instead of node.as_string(), because the latter # looses the original form of the docstrings. if docstring: lineno = node.fromlineno + 1 line = linecache.getline(node.root().file, lineno).lstrip() if line and line.find('"""') == 0: return if line and "'''" in line: quotes = "'''" elif line and line[0] == '"': quotes = '"' elif line and line[0] == "'": quotes = "'" else: quotes = "" if quotes: self.add_message( "bad-docstring-quotes", node=node, args=(node_type, quotes), confidence=HIGH, )
def object_build_function(node: nodes.Module | nodes.ClassDef, member: _FunctionTypes, localname: str) -> None: """create astroid for a living function object""" args, posonlyargs, defaults, kwonlyargs = _get_args_info_from_callable( member) func = build_function( getattr(member, "__name__", None) or localname, args, posonlyargs, defaults, member.__doc__, kwonlyargs=kwonlyargs, ) node.add_local_node(func, localname)
def _base_class_object_build( node: nodes.Module | nodes.ClassDef, member: type, basenames: list[str], name: str | None = None, localname: str | None = None, ) -> nodes.ClassDef: """create astroid for a living class object, with a given set of base names (e.g. ancestors) """ class_name = name or getattr(member, "__name__", None) or localname assert isinstance(class_name, str) klass = build_class( class_name, basenames, member.__doc__, ) klass._newstyle = isinstance(member, type) node.add_local_node(klass, localname) try: # limit the instantiation trick since it's too dangerous # (such as infinite test execution...) # this at least resolves common case such as Exception.args, # OSError.errno if issubclass(member, Exception): instdict = member().__dict__ else: raise TypeError except TypeError: pass else: for item_name, obj in instdict.items(): valnode = nodes.EmptyNode() valnode.object = obj valnode.parent = klass valnode.lineno = 1 klass.instance_attrs[item_name] = [valnode] return klass
def object_build(self, node: nodes.Module | nodes.ClassDef, obj: types.ModuleType | type) -> None: """recursive method which create a partial ast from real objects (only function, class, and method are handled) """ if obj in self._done: return None self._done[obj] = node for name in dir(obj): # inspect.ismethod() and inspect.isbuiltin() in PyPy return # the opposite of what they do in CPython for __class_getitem__. pypy__class_getitem__ = IS_PYPY and name == "__class_getitem__" try: with warnings.catch_warnings(): warnings.simplefilter("ignore") member = getattr(obj, name) except (AttributeError): # damned ExtensionClass.Base, I know you're there ! attach_dummy_node(node, name) continue if inspect.ismethod(member) and not pypy__class_getitem__: member = member.__func__ if inspect.isfunction(member): _build_from_function(node, name, member, self._module) elif inspect.isbuiltin(member) or pypy__class_getitem__: if self.imported_member(node, member, name): continue object_build_methoddescriptor(node, member, name) elif inspect.isclass(member): if self.imported_member(node, member, name): continue if member in self._done: class_node = self._done[member] assert isinstance(class_node, nodes.ClassDef) if class_node not in node.locals.get(name, ()): node.add_local_node(class_node, name) else: class_node = object_build_class(node, member, name) # recursion self.object_build(class_node, member) if name == "__class__" and class_node.parent is None: class_node.parent = self._done[self._module] elif inspect.ismethoddescriptor(member): object_build_methoddescriptor(node, member, name) elif inspect.isdatadescriptor(member): object_build_datadescriptor(node, member, name) elif isinstance(member, _CONSTANTS): attach_const_node(node, name, member) elif inspect.isroutine(member): # This should be called for Jython, where some builtin # methods aren't caught by isbuiltin branch. _build_from_function(node, name, member, self._module) elif _safe_has_attribute(member, "__all__"): module = build_module(name) _attach_local_node(node, module, name) # recursion self.object_build(module, member) else: # create an empty node so that the name is actually defined attach_dummy_node(node, name, member) return None