def get_object_members( subject: Any, objpath: List[str], attrgetter: Callable, analyzer: ModuleAnalyzer = None) -> Dict[str, Attribute]: """Get members and attributes of target object.""" from sphinx.ext.autodoc import INSTANCEATTR # the members directly defined in the class obj_dict = attrgetter(subject, '__dict__', {}) members = {} # type: Dict[str, Attribute] # enum members if isenumclass(subject): for name, value in subject.__members__.items(): if name not in members: members[name] = Attribute(name, True, value) superclass = subject.__mro__[1] for name in obj_dict: if name not in superclass.__dict__: value = safe_getattr(subject, name) members[name] = Attribute(name, True, value) # members in __slots__ if isclass(subject) and getattr(subject, '__slots__', None) is not None: from sphinx.ext.autodoc import SLOTSATTR for name in subject.__slots__: members[name] = Attribute(name, True, SLOTSATTR) # other members for name in dir(subject): try: value = attrgetter(subject, name) directly_defined = name in obj_dict name = unmangle(subject, name) if name and name not in members: members[name] = Attribute(name, directly_defined, value) except AttributeError: continue # annotation only member (ex. attr: int) if hasattr(subject, '__annotations__') and isinstance( subject.__annotations__, Mapping): for name in subject.__annotations__: name = unmangle(subject, name) if name and name not in members: members[name] = Attribute(name, True, INSTANCEATTR) if analyzer: # append instance attributes (cf. self.attr1) if analyzer knows namespace = '.'.join(objpath) for (ns, name) in analyzer.find_attr_docs(): if namespace == ns and name not in members: members[name] = Attribute(name, True, INSTANCEATTR) return members
def mangle(subject: Any, name: str) -> str: """mangle the given name.""" try: if isclass(subject) and name.startswith('__') and not name.endswith('__'): return "_%s%s" % (subject.__name__, name) except AttributeError: pass return name
def get_object_members(subject, objpath, attrgetter, analyzer=None): # type: (Any, List[str], Callable, Any) -> Dict[str, Attribute] # NOQA """Get members and attributes of target object.""" # the members directly defined in the class obj_dict = attrgetter(subject, '__dict__', {}) members = {} # type: Dict[str, Attribute] # enum members if isenumclass(subject): for name, value in subject.__members__.items(): if name not in members: members[name] = Attribute(name, True, value) superclass = subject.__mro__[1] for name, value in obj_dict.items(): if name not in superclass.__dict__: members[name] = Attribute(name, True, value) # members in __slots__ if isclass(subject) and hasattr(subject, '__slots__'): from sphinx.ext.autodoc import SLOTSATTR for name in subject.__slots__: members[name] = Attribute(name, True, SLOTSATTR) # other members for name in dir(subject): try: value = attrgetter(subject, name) directly_defined = name in obj_dict if name not in members: members[name] = Attribute(name, directly_defined, value) except AttributeError: continue if analyzer: # append instance attributes (cf. self.attr1) if analyzer knows from sphinx.ext.autodoc import INSTANCEATTR namespace = '.'.join(objpath) for (ns, name) in analyzer.find_attr_docs(): if namespace == ns and name not in members: members[name] = Attribute(name, True, INSTANCEATTR) return members
def unmangle(subject: Any, name: str) -> Optional[str]: """unmangle the given name.""" try: if isclass(subject) and not name.endswith('__'): prefix = "_%s__" % subject.__name__ if name.startswith(prefix): return name.replace(prefix, "__", 1) else: for cls in subject.__mro__: prefix = "_%s__" % cls.__name__ if name.startswith(prefix): # mangled attribute defined in parent class return None except AttributeError: pass return name
def _process_docstring(app: Sphinx, what: str, name: str, obj: Any, options: Any, lines: List[str]) -> None: """Removes already documented (by XPM) attributes from docstring Comes after napoleon (lesser priority) so benefit from a standardized output """ if obj is not None and inspect.isclass(obj) and issubclass(obj, Config): xpminfo = getxpminfo(obj) names = set(xpminfo.arguments.keys()) newlines = [] skip = False for line in lines: if m := RE_ATTRIBUTE.match(line): if m.group(1) in names: skip = True elif skip: if line.startswith(".."): skip = False if not skip: newlines.append(line)