diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 1982f1f5..ce4dd345 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -225,8 +225,12 @@ def _pep224_docstrings(doc_obj: Union['Module', 'Class'], *, if _init_tree: tree = _init_tree else: + source = doc_obj.source + if source == "": + warn("Couldn't read PEP-224 variable docstrings from {!r}".format(doc_obj)) + return {}, {} try: - tree = ast.parse(inspect.getsource(doc_obj.obj)) + tree = ast.parse(source) except (OSError, TypeError, SyntaxError) as exc: warn("Couldn't read PEP-224 variable docstrings from {!r}: {}".format(doc_obj, exc)) return {}, {} @@ -786,6 +790,17 @@ def classes(self, sort=True): """ return self._filter_doc_objs(Class, sort) + def all_classes(self, sort=True): + """Returns all documented classes in the module even the ones defined + in other classes.""" + stack = self.classes(sort)[::-1] + results = [] + while stack: + c = stack.pop() + results.append(c) + stack.extend(c.classes(sort=sort)[::-1]) + return results + def functions(self, sort=True): """ Returns all documented module-level functions in the module, @@ -813,9 +828,9 @@ class Class(Doc): """ Representation of a class' documentation. """ - __slots__ = ('doc', '_super_members') + __slots__ = ('doc', 'cls', '_super_members') - def __init__(self, name, module, obj, *, docstring=None): + def __init__(self, name, module, obj, *, docstring=None, cls=None): assert inspect.isclass(obj) if docstring is None: @@ -826,6 +841,12 @@ def __init__(self, name, module, obj, *, docstring=None): super().__init__(name, module, obj, docstring=docstring) + self.cls = cls + """ + The `pdoc.Class` object if this class is defined in a class. If not, + this is None. + """ + self.doc = {} """A mapping from identifier name to a `pdoc.Doc` objects.""" @@ -845,6 +866,14 @@ def __init__(self, name, module, obj, *, docstring=None): self.doc[name] = Function( name, self.module, obj, cls=self, method=not self._method_type(self.obj, name)) + elif inspect.isclass(obj): + self.doc[name] = Class( + self.name + "." + name, + self.module, + obj, + cls=self, + docstring=inspect.getdoc(obj) + ) else: self.doc[name] = Variable( name, self.module, @@ -940,6 +969,14 @@ def _filter_doc_objs(self, type: Type[T], include_inherited=True, if (include_inherited or not obj.inherits) and filter_func(obj)] return sorted(result) if sort else result + def classes(self, include_inherited=False, sort=False): + """Returns the classes defined in this class.""" + return self._filter_doc_objs( + Class, + include_inherited=include_inherited, + sort=sort + ) + def class_variables(self, include_inherited=True, sort=True): """ Returns an optionally-sorted list of `pdoc.Variable` objects that diff --git a/pdoc/templates/html.mako b/pdoc/templates/html.mako index cc2418c1..7f407f77 100644 --- a/pdoc/templates/html.mako +++ b/pdoc/templates/html.mako @@ -91,7 +91,7 @@ <%def name="show_module(module)"> <% variables = module.variables(sort=sort_identifiers) - classes = module.classes(sort=sort_identifiers) + classes = module.all_classes(sort=sort_identifiers) functions = module.functions(sort=sort_identifiers) submodules = module.submodules() %> @@ -274,7 +274,7 @@ <%def name="module_index(module)"> <% variables = module.variables(sort=sort_identifiers) - classes = module.classes(sort=sort_identifiers) + classes = module.all_classes(sort=sort_identifiers) functions = module.functions(sort=sort_identifiers) submodules = module.submodules() supermodule = module.supermodule