def introspect_class(cls, class_doc, module_name=None):
    """
    Add API documentation information about the class C{cls}
    to C{class_doc}.
    """
    class_doc.specialize_to(ClassDoc)

    # Record the class's docstring.
    class_doc.docstring = get_docstring(cls)

    # Record the class's __all__ attribute (public names).
    public_names = None
    if hasattr(cls, '__all__'):
        try:
            public_names = set([str(name) for name in cls.__all__])
        except __HOLE__: raise
        except: pass

    # Record the class's metaclass
    class_doc.metaclass = introspect_docs(type(cls))

    # Start a list of subclasses.
    class_doc.subclasses = []

    # Sometimes users will define a __metaclass__ that copies all
    # class attributes from bases directly into the derived class's
    # __dict__ when the class is created.  (This saves the lookup time
    # needed to search the base tree for an attribute.)  But for the
    # docs, we only want to list these copied attributes in the
    # parent.  So only add an attribute if it is not identical to an
    # attribute of a base class.  (Unfortunately, this can sometimes
    # cause an attribute to look like it was inherited, even though it
    # wasn't, if it happens to have the exact same value as the
    # corresponding base's attribute.)  An example of a case where
    # this helps is PyQt -- subclasses of QWidget get about 300
    # methods injected into them.
    base_children = {}
    
    # Record the class's base classes; and add the class to its
    # base class's subclass lists.
    if hasattr(cls, '__bases__'):
        try: bases = list(cls.__bases__)
        except:
            bases = None
            log.warning("Class '%s' defines __bases__, but it does not "
                        "contain an iterable; ignoring base list."
                        % getattr(cls, '__name__', '??'))
        if bases is not None:
            class_doc.bases = []
            for base in bases:
                basedoc = introspect_docs(base)
                class_doc.bases.append(basedoc)
                basedoc.subclasses.append(class_doc)
            
            bases.reverse()
            for base in bases:
                if hasattr(base, '__dict__'):
                    base_children.update(base.__dict__)

    # The module name is not defined if the class is being introspected
    # as another class base.
    if module_name is None and class_doc.defining_module not in (None, UNKNOWN):
        module_name = class_doc.defining_module.canonical_name
        
    # Record the class's local variables.
    class_doc.variables = {}
    if hasattr(cls, '__dict__'):
        private_prefix = '_%s__' % getattr(cls, '__name__', '<none>')
        for child_name, child in cls.__dict__.items():
            if (child_name in base_children
                and base_children[child_name] == child):
                continue

            if child_name.startswith(private_prefix):
                child_name = child_name[len(private_prefix)-2:]
            if child_name in UNDOCUMENTED_CLASS_VARS: continue
            val_doc = introspect_docs(child, context=class_doc,
                                      module_name=module_name)
            var_doc = VariableDoc(name=child_name, value=val_doc,
                                  container=class_doc,
                                  docs_extracted_by='introspecter')
            if public_names is not None:
                var_doc.is_public = (child_name in public_names)
            class_doc.variables[child_name] = var_doc

    return class_doc

#////////////////////////////////////////////////////////////
# Routine Introspection
#////////////////////////////////////////////////////////////
dataset/ETHPy150Open CollabQ/CollabQ/vendor/epydoc/docintrospecter.py/introspect_class