diff --git a/doc/pdoc/cli.html b/doc/pdoc/cli.html index c82e9adf..6c542573 100644 --- a/doc/pdoc/cli.html +++ b/doc/pdoc/cli.html @@ -3,7 +3,7 @@ - + pdoc.cli API documentation @@ -48,18 +48,226 @@

Functions

Command-line entry point

+
+ +Expand source code +Browse git + +
def main(_args=None):
+    """ Command-line entry point """
+    global args
+    args = _args or parser.parse_args()
+
+    # If warnings not externally managed, show deprecation warnings
+    if not sys.warnoptions:
+        warnings.simplefilter("once", DeprecationWarning)
+
+    if args.close_stdin:
+        sys.stdin.close()
+
+    if (args.html or args.http) and not args.output_dir:
+        args.output_dir = 'html'
+
+    if args.html_dir:
+        _warn_deprecated('--html-dir', '--output-dir')
+        args.output_dir = args.html_dir
+    if args.overwrite:
+        _warn_deprecated('--overwrite', '--force')
+        args.force = args.overwrite
+
+    template_config = {}
+    for config_str in args.config:
+        try:
+            key, value = config_str.split('=', 1)
+            value = ast.literal_eval(value)
+            template_config[key] = value
+        except Exception:
+            raise ValueError(
+                f'Error evaluating --config statement "{config_str}". '
+                'Make sure string values are quoted?'
+            )
+
+    if args.html_no_source:
+        _warn_deprecated('--html-no-source', '-c show_source_code=False', True)
+        template_config['show_source_code'] = False
+    if args.link_prefix:
+        _warn_deprecated('--link-prefix', '-c link_prefix="foo"', True)
+        template_config['link_prefix'] = args.link_prefix
+    if args.external_links:
+        _warn_deprecated('--external-links')
+        template_config['external_links'] = True
+
+    if args.template_dir is not None:
+        if not path.isdir(args.template_dir):
+            print(f'Error: Template dir {args.template_dir!r} is not a directory', file=sys.stderr)
+            sys.exit(1)
+        pdoc.tpl_lookup.directories.insert(0, args.template_dir)
+
+    # Support loading modules specified as python paths relative to cwd
+    sys.path.append(os.getcwd())
+
+    # Virtual environment handling for pdoc script run from system site
+    try:
+        os.environ['VIRTUAL_ENV']
+    except KeyError:
+        pass  # pdoc was not invoked while in a virtual environment
+    else:
+        from glob import glob
+        from sysconfig import get_path
+        libdir = get_path("platlib")
+        sys.path.append(libdir)
+        # Resolve egg-links from `setup.py develop` or `pip install -e`
+        # XXX: Welcome a more canonical approach
+        for pth in glob(path.join(libdir, '*.egg-link')):
+            try:
+                with open(pth) as f:
+                    sys.path.append(path.join(libdir, f.readline().rstrip()))
+            except IOError:
+                warn(f'Invalid egg-link in venv: {pth!r}')
+
+    if args.http:
+        template_config['link_prefix'] = "/"
+
+        # Run the HTTP server.
+        _WebDoc.args = args  # Pass params to HTTPServer xP
+        _WebDoc.template_config = template_config
+
+        host, _, port = args.http.partition(':')
+        host = host or DEFAULT_HOST
+        port = int(port or DEFAULT_PORT)
+
+        print(f'Starting pdoc server on {host}:{port}', file=sys.stderr)
+        httpd = HTTPServer((host, port), _WebDoc)
+        print(f"pdoc server ready at http://{host}:{port}", file=sys.stderr)
+
+        # Allow tests to perform `pdoc.cli._httpd.shutdown()`
+        global _httpd
+        _httpd = httpd
+
+        try:
+            httpd.serve_forever()
+        finally:
+            httpd.server_close()
+            sys.exit(0)
+
+    if args.filter and args.filter.strip():
+        def docfilter(obj, _filters=args.filter.strip().split(',')):
+            return any(f in obj.refname or
+                       isinstance(obj, pdoc.Class) and f in obj.doc
+                       for f in _filters)
+    else:
+        docfilter = None
+
+    modules = [pdoc.Module(module, docfilter=docfilter,
+                           skip_errors=args.skip_errors)
+               for module in args.modules]
+    pdoc.link_inheritance()
+
+    # Loading is done. Output stage ...
+    config = pdoc._get_config(**template_config)
+
+    # Load configured global markdown extensions
+    # XXX: This is hereby enabled only for CLI usage as for
+    #  API use I couldn't figure out where reliably to put it.
+    if config.get('md_extensions'):
+        from .html_helpers import _md
+        _kwargs = {'extensions': [], 'configs': {}}
+        _kwargs.update(config.get('md_extensions', {}))
+        _md.registerExtensions(**_kwargs)
+
+    if args.pdf:
+        _print_pdf(modules, **template_config)
+        import textwrap
+        PANDOC_CMD = textwrap.indent(_PANDOC_COMMAND, '    ')
+        print(f"""
+PDF-ready markdown written to standard output.
+                              ^^^^^^^^^^^^^^^
+Convert this file to PDF using e.g. Pandoc:
+
+{PANDOC_CMD}
+
+or using Python-Markdown and Chrome/Chromium/WkHtmlToPDF:
+
+    markdown_py --extension=meta         \\
+                --extension=abbr         \\
+                --extension=attr_list    \\
+                --extension=def_list     \\
+                --extension=fenced_code  \\
+                --extension=footnotes    \\
+                --extension=tables       \\
+                --extension=admonition   \\
+                --extension=smarty       \\
+                --extension=toc          \\
+                pdf.md > pdf.html
+
+    chromium --headless --disable-gpu --print-to-pdf=pdf.pdf pdf.html
+
+    wkhtmltopdf --encoding utf8 -s A4 --print-media-type pdf.html pdf.pdf
+
+or similar, at your own discretion.""",
+              file=sys.stderr)
+        sys.exit(0)
+
+    for module in modules:
+        if args.html:
+            _quit_if_exists(module, ext='.html')
+            recursive_write_files(module, ext='.html', **template_config)
+        elif args.output_dir:  # Generate text files
+            _quit_if_exists(module, ext='.md')
+            recursive_write_files(module, ext='.md', **template_config)
+        else:
+            sys.stdout.write(module.text(**template_config))
+            # Two blank lines between two modules' texts
+            sys.stdout.write(os.linesep * (1 + 2 * int(module != modules[-1])))
+
+    if args.html:
+        lunr_config = config.get('lunr_search')
+        if lunr_config is not None:
+            _generate_lunr_search(
+                modules, lunr_config.get("index_docstrings", True), template_config)
+
def module_path(m: Module, ext: str)
+
+ +Expand source code +Browse git + +
def module_path(m: pdoc.Module, ext: str):
+    return path.join(args.output_dir, *re.sub(r'\.html$', ext, m.url()).split('/'))
+
def recursive_write_files(m: Module,
ext: str,
**kwargs)
+
+ +Expand source code +Browse git + +
def recursive_write_files(m: pdoc.Module, ext: str, **kwargs):
+    assert ext in ('.html', '.md')
+    filepath = module_path(m, ext=ext)
+
+    dirpath = path.dirname(filepath)
+    if not os.access(dirpath, os.R_OK):
+        os.makedirs(dirpath)
+
+    with _open_write_file(filepath) as f:
+        if ext == '.html':
+            f.write(m.html(**kwargs))
+        elif ext == '.md':
+            f.write(m.text(**kwargs))
+
+    for submodule in m.submodules():
+        recursive_write_files(submodule, ext=ext, **kwargs)
+
@@ -97,7 +305,7 @@

Functions

diff --git a/doc/pdoc/html_helpers.html b/doc/pdoc/html_helpers.html index d3a59b3b..71f0995b 100644 --- a/doc/pdoc/html_helpers.html +++ b/doc/pdoc/html_helpers.html @@ -3,7 +3,7 @@ - + pdoc.html_helpers API documentation @@ -48,6 +48,23 @@

Functions

Returns HTML Table of Contents containing markdown titles in text.

+
+ +Expand source code +Browse git + +
def extract_toc(text: str):
+    """
+    Returns HTML Table of Contents containing markdown titles in `text`.
+    """
+    with _fenced_code_blocks_hidden(text) as result:
+        result[0] = _ToMarkdown.DOCTESTS_RE.sub('', result[0])
+    text = result[0]
+    toc, _ = _md.reset().convert(f'[TOC]\n\n@CUT@\n\n{text}').split('@CUT@', 1)
+    if toc.endswith('<p>'):  # CUT was put into its own paragraph
+        toc = toc[:-3].rstrip()
+    return toc
+

Interpolate template as a formatted string literal using values extracted from dobj and the working environment.

+
+ +Expand source code +Browse git + +
def format_git_link(template: str, dobj: pdoc.Doc):
+    """
+    Interpolate `template` as a formatted string literal using values extracted
+    from `dobj` and the working environment.
+    """
+    if not template:
+        return None
+    try:
+        if 'commit' in _str_template_fields(template):
+            commit = _git_head_commit()
+        obj = pdoc._unwrap_descriptor(dobj)
+        abs_path = inspect.getfile(inspect.unwrap(obj))
+        path = _project_relative_path(abs_path)
+
+        # Urls should always use / instead of \\
+        if os.name == 'nt':
+            path = path.replace('\\', '/')
+
+        lines, start_line = inspect.getsourcelines(obj)
+        start_line = start_line or 1  # GH-296
+        end_line = start_line + len(lines) - 1
+        url = template.format(**locals())
+        return url
+    except Exception:
+        warn(f'format_git_link for {obj} failed:\n{traceback.format_exc()}')
+        return None
+
def glimpse(text: str, max_length=153, *, paragraph=True) @@ -63,12 +112,55 @@

Functions

Returns a short excerpt (e.g. first paragraph) of text. If paragraph is True, the first paragraph will be returned, but never longer than max_length characters.

+
+ +Expand source code +Browse git + +
def glimpse(text: str, max_length=153, *, paragraph=True,
+            _split_paragraph=partial(re.compile(r'\s*\n\s*\n\s*').split, maxsplit=1),
+            _trim_last_word=partial(re.compile(r'\S+$').sub, ''),
+            _remove_titles=partial(re.compile(r'^(#+|-{4,}|={4,})', re.MULTILINE).sub, ' ')):
+    """
+    Returns a short excerpt (e.g. first paragraph) of text.
+    If `paragraph` is True, the first paragraph will be returned,
+    but never longer than `max_length` characters.
+    """
+    text = text.lstrip()
+    if paragraph:
+        text, *rest = _split_paragraph(text)
+        if rest:
+            text = text.rstrip('.')
+            text += ' …'
+        text = _remove_titles(text).strip()
+
+    if len(text) > max_length:
+        text = _trim_last_word(text[:max_length - 2])
+        if not text.endswith('.') or not paragraph:
+            text = text.rstrip('. ') + ' …'
+    return text
+
def minify_css(css: str)

Minify CSS by removing extraneous whitespace, comments, and trailing semicolons.

+
+ +Expand source code +Browse git + +
@lru_cache()
+def minify_css(css: str,
+               _whitespace=partial(re.compile(r'\s*([,{:;}])\s*').sub, r'\1'),
+               _comments=partial(re.compile(r'/\*.*?\*/', flags=re.DOTALL).sub, ''),
+               _trailing_semicolon=partial(re.compile(r';\s*}').sub, '}')):
+    """
+    Minify CSS by removing extraneous whitespace, comments, and trailing semicolons.
+    """
+    return _trailing_semicolon(_whitespace(_comments(css))).strip()
+
def minify_html(html: str) @@ -76,6 +168,24 @@

Functions

Minify HTML by replacing all consecutive whitespace with a single space (or newline) character, except inside <pre> tags.

+
+ +Expand source code +Browse git + +
def minify_html(html: str,
+                _minify=partial(
+                    re.compile(r'(.*?)(<pre\b.*?</pre\b\s*>)|(.*)', re.IGNORECASE | re.DOTALL).sub,
+                    lambda m, _norm_space=partial(re.compile(r'\s\s+').sub, '\n'): (
+                        _norm_space(m.group(1) or '') +
+                        (m.group(2) or '') +
+                        _norm_space(m.group(3) or '')))):
+    """
+    Minify HTML by replacing all consecutive whitespace with a single space
+    (or newline) character, except inside `<pre>` tags.
+    """
+    return _minify(html)
+
def to_html(text: str,
*,
docformat: str | None = None,
module: Module | None = None,
link: Callable[..., str] | None = None,
latex_math: bool = False)
@@ -87,6 +197,36 @@

Functions

module should be the documented module (so the references can be resolved) and link is the hyperlinking function like the one in the example template.

+
+ +Expand source code +Browse git + +
def to_html(text: str, *,
+            docformat: Optional[str] = None,
+            module: Optional[pdoc.Module] = None,
+            link: Optional[Callable[..., str]] = None,
+            latex_math: bool = False):
+    """
+    Returns HTML of `text` interpreted as `docformat`. `__docformat__` is respected
+    if present, otherwise Numpydoc and Google-style docstrings are assumed,
+    as well as pure Markdown.
+
+    `module` should be the documented module (so the references can be
+    resolved) and `link` is the hyperlinking function like the one in the
+    example template.
+    """
+    # Optionally register our math syntax processor
+    if not latex_math and _MathPattern.NAME in _md.inlinePatterns:
+        _md.inlinePatterns.deregister(_MathPattern.NAME)
+    elif latex_math and _MathPattern.NAME not in _md.inlinePatterns:
+        _md.inlinePatterns.register(_MathPattern(_MathPattern.PATTERN),
+                                    _MathPattern.NAME,
+                                    _MathPattern.PRIORITY)
+
+    md = to_markdown(text, docformat=docformat, module=module, link=link)
+    return _md.reset().convert(md)
+
def to_markdown(text: str,
*,
docformat: str | None = None,
module: Module | None = None,
link: Callable[..., str] | None = None)
@@ -99,6 +239,67 @@

Functions

module should be the documented module (so the references can be resolved) and link is the hyperlinking function like the one in the example template.

+
+ +Expand source code +Browse git + +
def to_markdown(text: str, *,
+                docformat: Optional[str] = None,
+                module: Optional[pdoc.Module] = None,
+                link: Optional[Callable[..., str]] = None):
+    """
+    Returns `text`, assumed to be a docstring in `docformat`, converted to markdown.
+    `__docformat__` is respected
+    if present, otherwise Numpydoc and Google-style docstrings are assumed,
+    as well as pure Markdown.
+
+    `module` should be the documented module (so the references can be
+    resolved) and `link` is the hyperlinking function like the one in the
+    example template.
+    """
+    if not docformat:
+        docformat = str(getattr(getattr(module, 'obj', None), '__docformat__', 'numpy,google '))
+        docformat, *_ = docformat.lower().split()
+    if not (set(docformat.split(',')) & {'', 'numpy', 'google'}):
+        warn(f'__docformat__ value {docformat!r} in module {module!r} not supported. '
+             'Supported values are: numpy, google.')
+        docformat = 'numpy,google'
+
+    with _fenced_code_blocks_hidden(text) as result:
+        text = result[0]
+
+        text = _ToMarkdown.admonitions(text, module)
+
+        if 'google' in docformat:
+            text = _ToMarkdown.google(text)
+
+        text = _ToMarkdown.doctests(text)
+        text = _ToMarkdown.raw_urls(text)
+
+        # If doing both, do numpy after google, otherwise google-style's
+        # headings are incorrectly interpreted as numpy params
+        if 'numpy' in docformat:
+            text = _ToMarkdown.numpy(text)
+
+        if module and link:
+            # Hyperlink markdown code spans not within markdown hyperlinks.
+            # E.g. `code` yes, but not [`code`](...). RE adapted from:
+            # https://github.com/Python-Markdown/markdown/blob/ada40c66/markdown/inlinepatterns.py#L106
+            # Also avoid linking triple-backticked arg names in deflists.
+            linkify = partial(_linkify, link=link, module=module, wrap_code=True)
+            text = re.sub(r'(?P<inside_link>\[[^\]]*?)?'
+                          r'(?:(?<!\\)(?:\\{2})+(?=`)|(?<!\\)(?P<fence>`+)'
+                          r'(?P<code>.+?)(?<!`)'
+                          r'(?P=fence)(?!`))',
+                          lambda m: (m.group()
+                                     if m.group('inside_link') or len(m.group('fence')) > 2
+                                     else linkify(m)), text)
+        result[0] = text
+    text = result[0]
+
+    return text
+
@@ -116,7 +317,7 @@

Classes

Expand source code -Browse git +Browse git
class ReferenceWarning(UserWarning):
     """
@@ -179,7 +380,7 @@ 

-

Generated by pdoc 0.11.3.

+

Generated by pdoc 0.11.4.

diff --git a/doc/pdoc/index.html b/doc/pdoc/index.html index a477a263..8d09ffaa 100644 --- a/doc/pdoc/index.html +++ b/doc/pdoc/index.html @@ -3,7 +3,7 @@ - + pdoc API documentation Functions

documentation objects are shown in the output. It is a function that takes a single argument (a documentation object) and returns True or False. If False, that object will not be documented.

+
+ +Expand source code +Browse git + +
def html(module_name, docfilter=None, reload=False, skip_errors=False, **kwargs) -> str:
+    """
+    Returns the documentation for the module `module_name` in HTML
+    format. The module must be a module or an importable string.
+
+    `docfilter` is an optional predicate that controls which
+    documentation objects are shown in the output. It is a function
+    that takes a single argument (a documentation object) and returns
+    `True` or `False`. If `False`, that object will not be documented.
+    """
+    mod = Module(import_module(module_name, reload=reload, skip_errors=False),
+                 docfilter=docfilter, skip_errors=skip_errors)
+    link_inheritance()
+    return mod.html(**kwargs)
+
def import_module(module: str | module, *, reload: bool = False, skip_errors: bool = False) ‑> module @@ -361,6 +381,60 @@

Functions

Return module object matching module specification (either a python module path or a filesystem path to file/directory).

+
+ +Expand source code +Browse git + +
def import_module(
+        module: Union[str, ModuleType],
+        *,
+        reload: bool = False,
+        skip_errors: bool = False,
+) -> ModuleType:
+    """
+    Return module object matching `module` specification (either a python
+    module path or a filesystem path to file/directory).
+    """
+    @contextmanager
+    def _module_path(module):
+        from os.path import abspath, dirname, isfile, isdir, split
+        path = '_pdoc_dummy_nonexistent'
+        module_name = inspect.getmodulename(module)
+        if isdir(module):
+            path, module = split(abspath(module))
+        elif isfile(module) and module_name:
+            path, module = dirname(abspath(module)), module_name
+        try:
+            sys.path.insert(0, path)
+            yield module
+        finally:
+            sys.path.remove(path)
+
+    if isinstance(module, Module):
+        module = module.obj
+    if isinstance(module, str):
+        with _module_path(module) as module_path:
+            try:
+                module = importlib.import_module(module_path)
+            except Exception as e:
+                msg = f'Error importing {module!r}: {e.__class__.__name__}: {e}'
+                if not skip_errors:
+                    raise ImportError(msg)
+                warn(msg, category=Module.ImportWarning, stacklevel=2)
+                module = ModuleType(module_path)
+
+    assert inspect.ismodule(module)
+    # If this is pdoc itself, return without reloading. Otherwise later
+    # `isinstance(..., pdoc.Doc)` calls won't work correctly.
+    if reload and not module.__name__.startswith(__name__):
+        module = importlib.reload(module)
+        # We recursively reload all submodules, in case __all_ is used - cf. issue #264
+        for mod_key, mod in list(sys.modules.items()):
+            if mod_key.startswith(module.__name__):
+                importlib.reload(mod)
+    return module
+
def maybe_lru_cache(func)
+
+ +Expand source code +Browse git + +
def maybe_lru_cache(func):
+    cached_func = lru_cache()(func)
+
+    @wraps(func)
+    def wrapper(*args):
+        try:
+            return cached_func(*args)
+        except TypeError:
+            return func(*args)
+
+    return wrapper
+
def reset()

Resets the global Context to the initial (empty) state.

+
+ +Expand source code +Browse git + +
def reset():
+    """Resets the global `pdoc.Context` to the initial (empty) state."""
+    global _global_context
+    _global_context.clear()
+
+    # Clear LRU caches
+    for func in (_get_type_hints,
+                 _is_blacklisted,
+                 _is_whitelisted):
+        func.cache_clear()
+    for cls in (Doc, Module, Class, Function, Variable, External):
+        for _, method in inspect.getmembers(cls):
+            if isinstance(method, property):
+                method = method.fget
+            if hasattr(method, 'cache_clear'):
+                method.cache_clear()
+
def text(module_name, docfilter=None, reload=False, skip_errors=False, **kwargs) ‑> str @@ -395,6 +534,27 @@

Functions

documentation objects are shown in the output. It is a function that takes a single argument (a documentation object) and returns True or False. If False, that object will not be documented.

+
+ +Expand source code +Browse git + +
def text(module_name, docfilter=None, reload=False, skip_errors=False, **kwargs) -> str:
+    """
+    Returns the documentation for the module `module_name` in plain
+    text format suitable for viewing on a terminal.
+    The module must be a module or an importable string.
+
+    `docfilter` is an optional predicate that controls which
+    documentation objects are shown in the output. It is a function
+    that takes a single argument (a documentation object) and returns
+    `True` or `False`. If `False`, that object will not be documented.
+    """
+    mod = Module(import_module(module_name, reload=reload, skip_errors=False),
+                 docfilter=docfilter, skip_errors=skip_errors)
+    link_inheritance()
+    return mod.text(**kwargs)
+
@@ -415,7 +575,7 @@

Classes

Expand source code -Browse git +Browse git
class Class(Doc):
     """
@@ -677,471 +837,464 @@ 

Instance variables

var doc

A mapping from identifier name to a Doc objects.

-
- -

Methods

-
-
-def class_variables(self, include_inherited=True, sort=True) ‑> List[Variable] -
-
-

Returns an optionally-sorted list of Variable objects that -represent this class' class variables.

-
-
-def functions(self, include_inherited=True, sort=True) ‑> List[Function] -
-
-

Returns an optionally-sorted list of Function objects that -represent this class' static functions.

-
-
-def inherited_members(self) ‑> List[Tuple[Class, List[Doc]]] -
-
-

Returns all inherited members as a list of tuples -(ancestor class, list of ancestor class' members sorted by name), -sorted by MRO.

-
-
-def instance_variables(self, include_inherited=True, sort=True) ‑> List[Variable] -
-
-

Returns an optionally-sorted list of Variable objects that -represent this class' instance variables. Instance variables -are those defined in a class's __init__ as self.variable = ....

-
-
-def methods(self, include_inherited=True, sort=True) ‑> List[Function] -
-
-

Returns an optionally-sorted list of Function objects that -represent this class' methods.

-
-
-def mro(self, only_documented=False) ‑> List[Class] -
-
-

Returns a list of ancestor (superclass) documentation objects -in method resolution order.

-

The list will contain objects of type Class -if the types are documented, and External otherwise.

-
-
-def params(self, *, annotate=False, link=None) ‑> List[str] -
-
-

Return a list of formatted parameters accepted by the -class constructor (method __init__). See Function.params().

-
-
-def subclasses(self) ‑> List[Class] -
-
-

Returns a list of subclasses of this class that are visible to the -Python interpreter (obtained from type.__subclasses__()).

-

The objects in the list are of type Class if available, -and External otherwise.

-
-
-

Inherited members

- - -
-class Context -
-
-

The context object that maps all documented identifiers -(Doc.refname) to their respective Doc objects.

-

You can pass an instance of Context to Module constructor. -All Module objects that share the same Context will see -(and be able to link in HTML to) each other's identifiers.

-

If you don't pass your own Context instance to Module constructor, -a global context object will be used.

Expand source code -Browse git +Browse git -
class Context(dict):
+
class Class(Doc):
     """
-    The context object that maps all documented identifiers
-    (`pdoc.Doc.refname`) to their respective `pdoc.Doc` objects.
+    Representation of a class' documentation.
+    """
+    __slots__ = ('doc', '_super_members')
 
-    You can pass an instance of `pdoc.Context` to `pdoc.Module` constructor.
-    All `pdoc.Module` objects that share the same `pdoc.Context` will see
-    (and be able to link in HTML to) each other's identifiers.
+    def __init__(self, name: str, module: Module, obj, *, docstring: Optional[str] = None):
+        assert inspect.isclass(obj)
 
-    If you don't pass your own `Context` instance to `Module` constructor,
-    a global context object will be used.
-    """
-    __pdoc__['Context.__init__'] = False
+        if docstring is None:
+            init_doc = inspect.getdoc(obj.__init__) or ''
+            if init_doc == object.__init__.__doc__:
+                init_doc = ''
+            docstring = f'{inspect.getdoc(obj) or ""}\n\n{init_doc}'.strip()
 
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        # A surrogate so that the check in Module._link_inheritance()
-        # "__pdoc__-overriden key {!r} does not exist" can see the object
-        # (and not warn).
-        self.blacklisted = getattr(args[0], 'blacklisted', set()) if args else set()
-
-

Ancestors

-
    -
  • builtins.dict
  • -
-
-
-class Doc -(name: str, module, obj, docstring: str = '') -
-
-

A base class for all documentation objects.

-

A documentation object corresponds to something in a Python module -that has a docstring associated with it. Typically, this includes -modules, classes, functions, and methods. However, pdoc adds support -for extracting some docstrings from abstract syntax trees, making -(module, class or instance) variables supported too.

-

A special type of documentation object External is used to -represent identifiers that are not part of the public interface of -a module. (The name "External" is a bit of a misnomer, since it can -also correspond to unexported members of the module, particularly in -a class's ancestor list.)

-

Initializes a documentation object, where name is the public -identifier name, module is a Module object where raw -Python object obj is defined, and docstring is its -documentation string. If docstring is left empty, it will be -read with inspect.getdoc().

-
- -Expand source code -Browse git - -
class Doc:
-    """
-    A base class for all documentation objects.
+        super().__init__(name, module, obj, docstring=docstring)
 
-    A documentation object corresponds to *something* in a Python module
-    that has a docstring associated with it. Typically, this includes
-    modules, classes, functions, and methods. However, `pdoc` adds support
-    for extracting some docstrings from abstract syntax trees, making
-    (module, class or instance) variables supported too.
+        self.doc: Dict[str, Union[Function, Variable]] = {}
+        """A mapping from identifier name to a `pdoc.Doc` objects."""
 
-    A special type of documentation object `pdoc.External` is used to
-    represent identifiers that are not part of the public interface of
-    a module. (The name "External" is a bit of a misnomer, since it can
-    also correspond to unexported members of the module, particularly in
-    a class's ancestor list.)
-    """
-    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
+        # Annotations for filtering.
+        # Use only own, non-inherited annotations (the rest will be inherited)
+        annotations = getattr(self.obj, '__annotations__', {})
 
-    def __init__(self, name: str, module, obj, docstring: str = ''):
-        """
-        Initializes a documentation object, where `name` is the public
-        identifier name, `module` is a `pdoc.Module` object where raw
-        Python object `obj` is defined, and `docstring` is its
-        documentation string. If `docstring` is left empty, it will be
-        read with `inspect.getdoc()`.
-        """
-        self.module = module
-        """
-        The module documentation object that this object is defined in.
-        """
+        public_objs = []
+        for _name, obj in _getmembers_all(self.obj):
+            # Filter only *own* members. The rest are inherited
+            # in Class._fill_inheritance()
+            if ((_name in self.obj.__dict__ or
+                 _name in annotations) and
+                    (_is_public(_name) or
+                     _is_whitelisted(_name, self))):
 
-        self.name = name
-        """
-        The identifier name for this object.
-        """
+                if _is_blacklisted(_name, self):
+                    self.module._context.blacklisted.add(f'{self.refname}.{_name}')
+                    continue
 
-        self.obj = obj
-        """
-        The raw python object.
-        """
+                obj = inspect.unwrap(obj)
+                public_objs.append((_name, obj))
 
-        docstring = (docstring or inspect.getdoc(obj) or '').strip()
-        if '.. include::' in docstring:
-            from pdoc.html_helpers import _ToMarkdown
-            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
-        self.docstring = docstring
-        """
-        The cleaned docstring for this object with any `.. include::`
-        directives resolved (i.e. content included).
-        """
+        def definition_order_index(
+                name,
+                _annot_index=list(annotations).index,
+                _dict_index=list(self.obj.__dict__).index):
+            try:
+                return _dict_index(name)
+            except ValueError:
+                pass
+            try:
+                return _annot_index(name) - len(annotations)  # sort annotated first
+            except ValueError:
+                return 9e9
 
-        self.inherits: Optional[Union[Class, Function, Variable]] = None
-        """
-        The Doc object (Class, Function, or Variable) this object inherits from,
-        if any.
-        """
+        public_objs.sort(key=lambda i: definition_order_index(i[0]))
 
-    def __repr__(self):
-        return f'<{self.__class__.__name__} {self.refname!r}>'
+        var_docstrings, instance_var_docstrings = _pep224_docstrings(self)
 
-    @property
-    @lru_cache()
-    def source(self) -> str:
+        # Convert the public Python objects to documentation objects.
+        for name, obj in public_objs:
+            if _is_function(obj):
+                self.doc[name] = Function(
+                    name, self.module, obj, cls=self)
+            else:
+                self.doc[name] = Variable(
+                    name, self.module,
+                    docstring=(
+                        var_docstrings.get(name) or
+                        (inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)),
+                    cls=self,
+                    kind="prop" if isinstance(obj, property) else "var",
+                    obj=_is_descriptor(obj) and obj or None,
+                    instance_var=(_is_descriptor(obj) or
+                                  name in getattr(self.obj, '__slots__', ())))
+
+        for name, docstring in instance_var_docstrings.items():
+            self.doc[name] = Variable(
+                name, self.module, docstring, cls=self,
+                obj=getattr(self.obj, name, None),
+                instance_var=True)
+
+    @staticmethod
+    def _method_type(cls: type, name: str):
         """
-        Cleaned (dedented) source code of the Python object. If not
-        available, an empty string.
+        Returns `None` if the method `name` of class `cls`
+        is a regular method. Otherwise, it returns
+        `classmethod` or `staticmethod`, as appropriate.
         """
-        try:
-            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj))
-        except (ValueError, TypeError, OSError):
-            return ''
-        return inspect.cleandoc(''.join(['\n'] + lines))
+        func = getattr(cls, name, None)
+        if inspect.ismethod(func):
+            # If the function is already bound, it's a classmethod.
+            # Regular methods are not bound before initialization.
+            return classmethod
+        for c in inspect.getmro(cls):
+            if name in c.__dict__:
+                if isinstance(c.__dict__[name], staticmethod):
+                    return staticmethod
+                return None
+        raise RuntimeError(f"{cls}.{name} not found")
 
     @property
     def refname(self) -> str:
+        return f'{self.module.name}.{self.qualname}'
+
+    def mro(self, only_documented=False) -> List['Class']:
         """
-        Reference name of this documentation
-        object, usually its fully qualified path
-        (e.g. <code>pdoc.Doc.refname</code>). Every
-        documentation object provides this property.
+        Returns a list of ancestor (superclass) documentation objects
+        in method resolution order.
+
+        The list will contain objects of type `pdoc.Class`
+        if the types are documented, and `pdoc.External` otherwise.
         """
-        # Ok for Module and External, the rest need it overriden
-        return self.name
+        classes = [cast(Class, self.module.find_class(c))
+                   for c in inspect.getmro(self.obj)
+                   if c not in (self.obj, object)]
+        if self in classes:
+            # This can contain self in case of a class inheriting from
+            # a class with (previously) the same name. E.g.
+            #
+            #     class Loc(namedtuple('Loc', 'lat lon')): ...
+            #
+            # We remove it from ancestors so that toposort doesn't break.
+            classes.remove(self)
+        if only_documented:
+            classes = _filter_type(Class, classes)
+        return classes
 
-    @property
-    def qualname(self) -> str:
+    def subclasses(self) -> List['Class']:
         """
-        Module-relative "qualified" name of this documentation
-        object, used for show (e.g. <code>Doc.qualname</code>).
+        Returns a list of subclasses of this class that are visible to the
+        Python interpreter (obtained from `type.__subclasses__()`).
+
+        The objects in the list are of type `pdoc.Class` if available,
+        and `pdoc.External` otherwise.
         """
-        return getattr(self.obj, '__qualname__', self.name)
+        return sorted(cast(Class, self.module.find_class(c))
+                      for c in type.__subclasses__(self.obj))
 
-    @lru_cache()
-    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
-            top_ancestor: bool = False) -> str:
+    def params(self, *, annotate=False, link=None) -> List[str]:
         """
-        Canonical relative URL (including page fragment) for this
-        documentation object.
+        Return a list of formatted parameters accepted by the
+        class constructor (method `__init__`). See `pdoc.Function.params`.
+        """
+        name = self.name + '.__init__'
+        qualname = self.qualname + '.__init__'
+        refname = self.refname + '.__init__'
+        exclusions = self.module.__pdoc__
+        if name in exclusions or qualname in exclusions or refname in exclusions:
+            return []
 
-        Specify `relative_to` (a `pdoc.Module` object) to obtain a
-        relative URL.
+        return Function._params(self, annotate=annotate, link=link, module=self.module)
 
-        For usage of `link_prefix` see `pdoc.html()`.
+    def _filter_doc_objs(self, type: Type[T], include_inherited=True,
+                         filter_func: Callable[[T], bool] = lambda x: True,
+                         sort=True) -> List[T]:
+        result = [obj for obj in _filter_type(type, self.doc)
+                  if (include_inherited or not obj.inherits) and filter_func(obj)]
+        return sorted(result) if sort else result
 
-        If `top_ancestor` is `True`, the returned URL instead points to
-        the top ancestor in the object's `pdoc.Doc.inherits` chain.
+    def class_variables(self, include_inherited=True, sort=True) -> List['Variable']:
         """
-        if top_ancestor:
-            self = self._inherits_top()
+        Returns an optionally-sorted list of `pdoc.Variable` objects that
+        represent this class' class variables.
+        """
+        return self._filter_doc_objs(
+            Variable, include_inherited, lambda dobj: not dobj.instance_var,
+            sort)
 
-        if relative_to is None or link_prefix:
-            return link_prefix + self._url()
+    def instance_variables(self, include_inherited=True, sort=True) -> List['Variable']:
+        """
+        Returns an optionally-sorted list of `pdoc.Variable` objects that
+        represent this class' instance variables. Instance variables
+        are those defined in a class's `__init__` as `self.variable = ...`.
+        """
+        return self._filter_doc_objs(
+            Variable, include_inherited, lambda dobj: dobj.instance_var,
+            sort)
 
-        if self.module.name == relative_to.name:
-            return f'#{self.refname}'
+    def methods(self, include_inherited=True, sort=True) -> List['Function']:
+        """
+        Returns an optionally-sorted list of `pdoc.Function` objects that
+        represent this class' methods.
+        """
+        return self._filter_doc_objs(
+            Function, include_inherited, lambda dobj: dobj.is_method,
+            sort)
 
-        # Otherwise, compute relative path from current module to link target
-        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
-        # We have one set of '..' too many
-        if url.startswith('../'):
-            url = url[3:]
-        return url
+    def functions(self, include_inherited=True, sort=True) -> List['Function']:
+        """
+        Returns an optionally-sorted list of `pdoc.Function` objects that
+        represent this class' static functions.
+        """
+        return self._filter_doc_objs(
+            Function, include_inherited, lambda dobj: not dobj.is_method,
+            sort)
 
-    def _url(self):
-        return f'{self.module._url()}#{self.refname}'
+    def inherited_members(self) -> List[Tuple['Class', List[Doc]]]:
+        """
+        Returns all inherited members as a list of tuples
+        (ancestor class, list of ancestor class' members sorted by name),
+        sorted by MRO.
+        """
+        return sorted(((cast(Class, k), sorted(g))
+                       for k, g in groupby((i.inherits
+                                            for i in self.doc.values() if i.inherits),
+                                           key=lambda i: i.cls)),                   # type: ignore
+                      key=lambda x, _mro_index=self.mro().index: _mro_index(x[0]))  # type: ignore
 
-    def _inherits_top(self):
+    def _fill_inheritance(self):
         """
-        Follow the `pdoc.Doc.inherits` chain and return the top object.
+        Traverses this class's ancestor list and attempts to fill in
+        missing documentation objects from its ancestors.
+
+        Afterwards, call to `pdoc.Class._link_inheritance()` to also
+        set `pdoc.Doc.inherits` pointers.
         """
-        top = self
-        while top.inherits:
-            top = top.inherits
-        return top
+        super_members = self._super_members = {}
+        for cls in self.mro(only_documented=True):
+            for name, dobj in cls.doc.items():
+                if name not in super_members and dobj.docstring:
+                    super_members[name] = dobj
+                    if name not in self.doc:
+                        dobj = copy(dobj)
+                        dobj.cls = self
 
-    def __lt__(self, other):
-        return self.refname < other.refname
+ self.doc[name] = dobj + self.module._context[dobj.refname] = dobj + + def _link_inheritance(self): + """ + Set `pdoc.Doc.inherits` pointers to inherited ancestors' members, + as appropriate. This must be called after + `pdoc.Class._fill_inheritance()`. + + The reason this is split in two parts is that in-between + the `__pdoc__` overrides are applied. + """ + if not hasattr(self, '_super_members'): + return + + for name, parent_dobj in self._super_members.items(): + try: + dobj = self.doc[name] + except KeyError: + # There is a key in some __pdoc__ dict blocking this member + continue + if (dobj.obj is parent_dobj.obj or + (dobj.docstring or parent_dobj.docstring) == parent_dobj.docstring): + dobj.inherits = parent_dobj + dobj.docstring = parent_dobj.docstring + del self._super_members
-

Subclasses

- -

Instance variables

-
-
var docstring
-
-

The cleaned docstring for this object with any .. include:: -directives resolved (i.e. content included).

-
var inherits
-
-

The Doc object (Class, Function, or Variable) this object inherits from, -if any.

-
-
var module
+
+

Methods

+
+
+def class_variables(self, include_inherited=True, sort=True) ‑> List[Variable] +
-

The module documentation object that this object is defined in.

+

Returns an optionally-sorted list of Variable objects that +represent this class' class variables.

+
+ +Expand source code +Browse git + +
def class_variables(self, include_inherited=True, sort=True) -> List['Variable']:
+    """
+    Returns an optionally-sorted list of `pdoc.Variable` objects that
+    represent this class' class variables.
+    """
+    return self._filter_doc_objs(
+        Variable, include_inherited, lambda dobj: not dobj.instance_var,
+        sort)
+
-
var name
+
+def functions(self, include_inherited=True, sort=True) ‑> List[Function] +
-

The identifier name for this object.

+

Returns an optionally-sorted list of Function objects that +represent this class' static functions.

+
+ +Expand source code +Browse git + +
def functions(self, include_inherited=True, sort=True) -> List['Function']:
+    """
+    Returns an optionally-sorted list of `pdoc.Function` objects that
+    represent this class' static functions.
+    """
+    return self._filter_doc_objs(
+        Function, include_inherited, lambda dobj: not dobj.is_method,
+        sort)
+
-
var obj
+
+def inherited_members(self) ‑> List[Tuple[Class, List[Doc]]] +
-

The raw python object.

+

Returns all inherited members as a list of tuples +(ancestor class, list of ancestor class' members sorted by name), +sorted by MRO.

+
+ +Expand source code +Browse git + +
def inherited_members(self) -> List[Tuple['Class', List[Doc]]]:
+    """
+    Returns all inherited members as a list of tuples
+    (ancestor class, list of ancestor class' members sorted by name),
+    sorted by MRO.
+    """
+    return sorted(((cast(Class, k), sorted(g))
+                   for k, g in groupby((i.inherits
+                                        for i in self.doc.values() if i.inherits),
+                                       key=lambda i: i.cls)),                   # type: ignore
+                  key=lambda x, _mro_index=self.mro().index: _mro_index(x[0]))  # type: ignore
+
-
prop qualname : str
+
+def instance_variables(self, include_inherited=True, sort=True) ‑> List[Variable] +
-

Module-relative "qualified" name of this documentation -object, used for show (e.g. Doc.qualname).

+

Returns an optionally-sorted list of Variable objects that +represent this class' instance variables. Instance variables +are those defined in a class's __init__ as self.variable = ....

Expand source code +Browse git -
@property
-def qualname(self) -> str:
+
def instance_variables(self, include_inherited=True, sort=True) -> List['Variable']:
     """
-    Module-relative "qualified" name of this documentation
-    object, used for show (e.g. <code>Doc.qualname</code>).
+    Returns an optionally-sorted list of `pdoc.Variable` objects that
+    represent this class' instance variables. Instance variables
+    are those defined in a class's `__init__` as `self.variable = ...`.
     """
-    return getattr(self.obj, '__qualname__', self.name)
+ return self._filter_doc_objs( + Variable, include_inherited, lambda dobj: dobj.instance_var, + sort)
-
prop refname : str
+
+def methods(self, include_inherited=True, sort=True) ‑> List[Function] +
-

Reference name of this documentation -object, usually its fully qualified path -(e.g. pdoc.Doc.refname). Every -documentation object provides this property.

+

Returns an optionally-sorted list of Function objects that +represent this class' methods.

Expand source code +Browse git -
@property
-def refname(self) -> str:
+
def methods(self, include_inherited=True, sort=True) -> List['Function']:
     """
-    Reference name of this documentation
-    object, usually its fully qualified path
-    (e.g. <code>pdoc.Doc.refname</code>). Every
-    documentation object provides this property.
+    Returns an optionally-sorted list of `pdoc.Function` objects that
+    represent this class' methods.
     """
-    # Ok for Module and External, the rest need it overriden
-    return self.name
+ return self._filter_doc_objs( + Function, include_inherited, lambda dobj: dobj.is_method, + sort)
-
prop source : str
+
+def mro(self, only_documented=False) ‑> List[Class] +
-

Cleaned (dedented) source code of the Python object. If not -available, an empty string.

+

Returns a list of ancestor (superclass) documentation objects +in method resolution order.

+

The list will contain objects of type Class +if the types are documented, and External otherwise.

Expand source code +Browse git -
@property
-@lru_cache()
-def source(self) -> str:
+
def mro(self, only_documented=False) -> List['Class']:
     """
-    Cleaned (dedented) source code of the Python object. If not
-    available, an empty string.
+    Returns a list of ancestor (superclass) documentation objects
+    in method resolution order.
+
+    The list will contain objects of type `pdoc.Class`
+    if the types are documented, and `pdoc.External` otherwise.
     """
-    try:
-        lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj))
-    except (ValueError, TypeError, OSError):
-        return ''
-    return inspect.cleandoc(''.join(['\n'] + lines))
+ classes = [cast(Class, self.module.find_class(c)) + for c in inspect.getmro(self.obj) + if c not in (self.obj, object)] + if self in classes: + # This can contain self in case of a class inheriting from + # a class with (previously) the same name. E.g. + # + # class Loc(namedtuple('Loc', 'lat lon')): ... + # + # We remove it from ancestors so that toposort doesn't break. + classes.remove(self) + if only_documented: + classes = _filter_type(Class, classes) + return classes
-
-

Methods

-
-
-def url(self,
relative_to: ForwardRef('Module') | None = None,
*,
link_prefix: str = '',
top_ancestor: bool = False) ‑> str
+
+def params(self, *, annotate=False, link=None) ‑> List[str]
-

Canonical relative URL (including page fragment) for this -documentation object.

-

Specify relative_to (a Module object) to obtain a -relative URL.

-

For usage of link_prefix see html().

-

If top_ancestor is True, the returned URL instead points to -the top ancestor in the object's Doc.inherits chain.

-
-
+

Return a list of formatted parameters accepted by the +class constructor (method __init__). See Function.params().

+
+ +Expand source code +Browse git + +
def params(self, *, annotate=False, link=None) -> List[str]:
+    """
+    Return a list of formatted parameters accepted by the
+    class constructor (method `__init__`). See `pdoc.Function.params`.
+    """
+    name = self.name + '.__init__'
+    qualname = self.qualname + '.__init__'
+    refname = self.refname + '.__init__'
+    exclusions = self.module.__pdoc__
+    if name in exclusions or qualname in exclusions or refname in exclusions:
+        return []
+
+    return Function._params(self, annotate=annotate, link=link, module=self.module)
+
-
-class External -(name: str) +
+def subclasses(self) ‑> List[Class]
-

A representation of an external identifier. The textual -representation is the same as an internal identifier.

-

External identifiers are also used to represent something that is -not documented but appears somewhere in the public interface (like -the ancestor list of a class).

-

Initializes an external identifier with name, where name -should be a fully qualified name.

+

Returns a list of subclasses of this class that are visible to the +Python interpreter (obtained from type.__subclasses__()).

+

The objects in the list are of type Class if available, +and External otherwise.

Expand source code -Browse git +Browse git -
class External(Doc):
+
def subclasses(self) -> List['Class']:
     """
-    A representation of an external identifier. The textual
-    representation is the same as an internal identifier.
+    Returns a list of subclasses of this class that are visible to the
+    Python interpreter (obtained from `type.__subclasses__()`).
 
-    External identifiers are also used to represent something that is
-    not documented but appears somewhere in the public interface (like
-    the ancestor list of a class).
+    The objects in the list are of type `pdoc.Class` if available,
+    and `pdoc.External` otherwise.
     """
-
-    __pdoc__["External.docstring"] = """
-        An empty string. External identifiers do not have
-        docstrings.
-        """
-    __pdoc__["External.module"] = """
-        Always `None`. External identifiers have no associated
-        `pdoc.Module`.
-        """
-    __pdoc__["External.name"] = """
-        Always equivalent to `pdoc.External.refname` since external
-        identifiers are always expressed in their fully qualified
-        form.
-        """
-
-    def __init__(self, name: str):
-        """
-        Initializes an external identifier with `name`, where `name`
-        should be a fully qualified name.
-        """
-        super().__init__(name, None, None)
-
-    def url(self, *args, **kwargs):
-        """
-        `External` objects return absolute urls matching `/{name}.ext`.
-        """
-        return f'/{self.name}.ext'
+ return sorted(cast(Class, self.module.find_class(c)) + for c in type.__subclasses__(self.obj))
-

Ancestors

- -

Methods

-
-
-def url(self, *args, **kwargs) -
-
-

External objects return absolute urls matching /{name}.ext.

Inherited members

@@ -1156,394 +1309,2701 @@

Inherited members

  • qualname
  • refname
  • source
  • +
  • url
  • -
    -class Function -(name: str,
    module: Module,
    obj,
    *,
    cls: Class | None = None)
    +
    +class Context
    -

    Representation of documentation for a function or method.

    -

    Same as Doc, except obj must be a -Python function object. The docstring is gathered automatically.

    -

    cls should be set when this is a method or a static function -beloing to a class. cls should be a Class object.

    -

    method should be True when the function is a method. In -all other cases, it should be False.

    +

    The context object that maps all documented identifiers +(Doc.refname) to their respective Doc objects.

    +

    You can pass an instance of Context to Module constructor. +All Module objects that share the same Context will see +(and be able to link in HTML to) each other's identifiers.

    +

    If you don't pass your own Context instance to Module constructor, +a global context object will be used.

    Expand source code -Browse git +Browse git -
    class Function(Doc):
    -    """
    -    Representation of documentation for a function or method.
    +
    class Context(dict):
         """
    -    __slots__ = ('cls',)
    -
    -    def __init__(self, name: str, module: Module, obj, *, cls: Optional[Class] = None):
    -        """
    -        Same as `pdoc.Doc`, except `obj` must be a
    -        Python function object. The docstring is gathered automatically.
    -
    -        `cls` should be set when this is a method or a static function
    -        beloing to a class. `cls` should be a `pdoc.Class` object.
    -
    -        `method` should be `True` when the function is a method. In
    -        all other cases, it should be `False`.
    -        """
    -        assert callable(obj), (name, module, obj)
    -        super().__init__(name, module, obj)
    +    The context object that maps all documented identifiers
    +    (`pdoc.Doc.refname`) to their respective `pdoc.Doc` objects.
     
    -        self.cls = cls
    -        """
    -        The `pdoc.Class` documentation object if the function is a method.
    -        If not, this is None.
    -        """
    +    You can pass an instance of `pdoc.Context` to `pdoc.Module` constructor.
    +    All `pdoc.Module` objects that share the same `pdoc.Context` will see
    +    (and be able to link in HTML to) each other's identifiers.
     
    -    @property
    -    def is_method(self) -> bool:
    -        """
    -        Whether this function is a normal bound method.
    +    If you don't pass your own `Context` instance to `Module` constructor,
    +    a global context object will be used.
    +    """
    +    __pdoc__['Context.__init__'] = False
     
    -        In particular, static and class methods have this set to False.
    -        """
    -        assert self.cls
    -        return not Class._method_type(self.cls.obj, self.name)
    +    def __init__(self, *args, **kwargs):
    +        super().__init__(*args, **kwargs)
    +        # A surrogate so that the check in Module._link_inheritance()
    +        # "__pdoc__-overriden key {!r} does not exist" can see the object
    +        # (and not warn).
    +        self.blacklisted = getattr(args[0], 'blacklisted', set()) if args else set()
    +
    +

    Ancestors

    +
      +
    • builtins.dict
    • +
    +
    +
    +class Doc +(name: str, module, obj, docstring: str = '') +
    +
    +

    A base class for all documentation objects.

    +

    A documentation object corresponds to something in a Python module +that has a docstring associated with it. Typically, this includes +modules, classes, functions, and methods. However, pdoc adds support +for extracting some docstrings from abstract syntax trees, making +(module, class or instance) variables supported too.

    +

    A special type of documentation object External is used to +represent identifiers that are not part of the public interface of +a module. (The name "External" is a bit of a misnomer, since it can +also correspond to unexported members of the module, particularly in +a class's ancestor list.)

    +

    Initializes a documentation object, where name is the public +identifier name, module is a Module object where raw +Python object obj is defined, and docstring is its +documentation string. If docstring is left empty, it will be +read with inspect.getdoc().

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
     
    -    @property
    -    def method(self):
    -        warn('`Function.method` is deprecated. Use: `Function.is_method`', DeprecationWarning,
    -             stacklevel=2)
    -        return self.is_method
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
     
    -    __pdoc__['Function.method'] = False
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
     
    -    def funcdef(self) -> str:
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
             """
    -        Generates the string of keywords used to define the function,
    -        for example `def` or `async def`.
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
             """
    -        return 'async def' if self._is_async else 'def'
    -
    -    @property
    -    def _is_async(self):
    +        self.module = module
             """
    -        Returns whether is function is asynchronous, either as a coroutine or an async
    -        generator.
    +        The module documentation object that this object is defined in.
             """
    -        try:
    -            # Both of these are required because coroutines aren't classified as async
    -            # generators and vice versa.
    -            obj = inspect.unwrap(self.obj)
    -            return (inspect.iscoroutinefunction(obj) or
    -                    inspect.isasyncgenfunction(obj))
    -        except AttributeError:
    -            return False
    -
    -    def return_annotation(self, *, link=None) -> str:
    -        """Formatted function return type annotation or empty string if none."""
    -        annot = ''
    -        for method in (
    -                lambda: _get_type_hints(self.obj)['return'],
    -                # Mainly for non-property variables
    -                lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name],
    -                # global variables
    -                lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
    -                # properties
    -                lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation,
    -                # Use raw annotation strings in unmatched forward declarations
    -                lambda: cast(Class, self.cls).obj.__annotations__[self.name],
    -                # Extract annotation from the docstring for C builtin function
    -                lambda: Function._signature_from_string(self).return_annotation,
    -        ):
    -            try:
    -                annot = method()
    -            except Exception:
    -                continue
    -            else:
    -                break
    -        else:
    -            # Don't warn on variables. The annotation just isn't available.
    -            if not isinstance(self, Variable):
    -                warn(f"Error handling return annotation for {self!r}", stacklevel=3)
     
    -        if annot is inspect.Parameter.empty or not annot:
    -            return ''
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
     
    -        if isinstance(annot, str):
    -            s = annot
    -        else:
    -            s = _formatannotation(annot)
    -            s = re.sub(r'\bForwardRef\((?P<quot>[\"\'])(?P<str>.*?)(?P=quot)\)',
    -                       r'\g<str>', s)
    -        s = s.replace(' ', '\N{NBSP}')  # Better line breaks in html signatures
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
     
    -        if link:
    -            from pdoc.html_helpers import _linkify
    -            s = re.sub(r'[\w\.]+', partial(_linkify, link=link, module=self.module), s)
    -        return s
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
     
    -    def params(self, *, annotate: bool = False,
    -               link: Optional[Callable[[Doc], str]] = None) -> List[str]:
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
             """
    -        Returns a list where each element is a nicely formatted
    -        parameter of this function. This includes argument lists,
    -        keyword arguments and default values, and it doesn't include any
    -        optional arguments whose names begin with an underscore.
     
    -        If `annotate` is True, the parameter strings include [PEP 484]
    -        type hint annotations.
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
     
    -        [PEP 484]: https://www.python.org/dev/peps/pep-0484/
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
             """
    -        return self._params(self, annotate=annotate, link=link, module=self.module)
    -
    -    @staticmethod
    -    def _params(doc_obj, annotate=False, link=None, module=None):
             try:
    -            # We want __init__ to actually be implemented somewhere in the
    -            # MRO to still satisfy https://github.com/pdoc3/pdoc/issues/124
    -            if (
    -                inspect.isclass(doc_obj.obj)
    -                and doc_obj.obj.__init__ is not object.__init__
    -            ):
    -                # Remove the first argument (self) from __init__ signature
    -                init_sig = inspect.signature(doc_obj.obj.__init__)
    -                init_params = list(init_sig.parameters.values())
    -                signature = init_sig.replace(parameters=init_params[1:])
    -            else:
    -                signature = inspect.signature(doc_obj.obj)
    -        except ValueError:
    -            signature = Function._signature_from_string(doc_obj)
    -            if not signature:
    -                return ['...']
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
     
    -        def safe_default_value(p: inspect.Parameter):
    -            value = p.default
    -            if value is inspect.Parameter.empty:
    -                return p
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
     
    -            replacement = next((i for i in ('os.environ',
    -                                            'sys.stdin',
    -                                            'sys.stdout',
    -                                            'sys.stderr',)
    -                                if value is eval(i)), None)
    -            if not replacement:
    -                if isinstance(value, enum.Enum):
    -                    replacement = str(value)
    -                elif inspect.isclass(value):
    -                    replacement = f'{value.__module__ or _UNKNOWN_MODULE}.{value.__qualname__}'
    -                elif ' at 0x' in repr(value):
    -                    replacement = re.sub(r' at 0x\w+', '', repr(value))
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
     
    -                nonlocal link
    -                if link and ('<' in repr(value) or '>' in repr(value)):
    -                    import html
    -                    replacement = html.escape(replacement or repr(value))
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
     
    -            if replacement:
    -                class mock:
    -                    def __repr__(self):
    -                        return replacement
    -                return p.replace(default=mock())
    -            return p
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
     
    -        params = []
    -        kw_only = False
    -        pos_only = False
    -        EMPTY = inspect.Parameter.empty
    +        For usage of `link_prefix` see `pdoc.html()`.
     
    -        if link:
    -            from pdoc.html_helpers import _linkify
    -            _linkify = partial(_linkify, link=link, module=module)
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
     
    -        for p in signature.parameters.values():  # type: inspect.Parameter
    -            if not _is_public(p.name) and p.default is not EMPTY:
    -                continue
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
     
    -            if p.kind == p.POSITIONAL_ONLY:
    -                pos_only = True
    -            elif pos_only:
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +

    Subclasses

    + +

    Instance variables

    +
    +
    var docstring
    +
    +

    The cleaned docstring for this object with any .. include:: +directives resolved (i.e. content included).

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
    +
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
    +
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
    +
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
    +        """
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
    +        """
    +        self.module = module
    +        """
    +        The module documentation object that this object is defined in.
    +        """
    +
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
    +
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
    +
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
    +
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
    +        """
    +
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
    +
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
    +        """
    +        try:
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
    +
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
    +
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
    +
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
    +
    +        For usage of `link_prefix` see `pdoc.html()`.
    +
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
    +
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
    +
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +
    +
    var inherits
    +
    +

    The Doc object (Class, Function, or Variable) this object inherits from, +if any.

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
    +
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
    +
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
    +
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
    +        """
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
    +        """
    +        self.module = module
    +        """
    +        The module documentation object that this object is defined in.
    +        """
    +
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
    +
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
    +
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
    +
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
    +        """
    +
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
    +
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
    +        """
    +        try:
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
    +
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
    +
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
    +
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
    +
    +        For usage of `link_prefix` see `pdoc.html()`.
    +
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
    +
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
    +
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +
    +
    var module
    +
    +

    The module documentation object that this object is defined in.

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
    +
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
    +
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
    +
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
    +        """
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
    +        """
    +        self.module = module
    +        """
    +        The module documentation object that this object is defined in.
    +        """
    +
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
    +
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
    +
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
    +
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
    +        """
    +
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
    +
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
    +        """
    +        try:
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
    +
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
    +
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
    +
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
    +
    +        For usage of `link_prefix` see `pdoc.html()`.
    +
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
    +
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
    +
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +
    +
    var name
    +
    +

    The identifier name for this object.

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
    +
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
    +
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
    +
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
    +        """
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
    +        """
    +        self.module = module
    +        """
    +        The module documentation object that this object is defined in.
    +        """
    +
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
    +
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
    +
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
    +
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
    +        """
    +
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
    +
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
    +        """
    +        try:
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
    +
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
    +
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
    +
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
    +
    +        For usage of `link_prefix` see `pdoc.html()`.
    +
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
    +
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
    +
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +
    +
    var obj
    +
    +

    The raw python object.

    +
    + +Expand source code +Browse git + +
    class Doc:
    +    """
    +    A base class for all documentation objects.
    +
    +    A documentation object corresponds to *something* in a Python module
    +    that has a docstring associated with it. Typically, this includes
    +    modules, classes, functions, and methods. However, `pdoc` adds support
    +    for extracting some docstrings from abstract syntax trees, making
    +    (module, class or instance) variables supported too.
    +
    +    A special type of documentation object `pdoc.External` is used to
    +    represent identifiers that are not part of the public interface of
    +    a module. (The name "External" is a bit of a misnomer, since it can
    +    also correspond to unexported members of the module, particularly in
    +    a class's ancestor list.)
    +    """
    +    __slots__ = ('module', 'name', 'obj', 'docstring', 'inherits')
    +
    +    def __init__(self, name: str, module, obj, docstring: str = ''):
    +        """
    +        Initializes a documentation object, where `name` is the public
    +        identifier name, `module` is a `pdoc.Module` object where raw
    +        Python object `obj` is defined, and `docstring` is its
    +        documentation string. If `docstring` is left empty, it will be
    +        read with `inspect.getdoc()`.
    +        """
    +        self.module = module
    +        """
    +        The module documentation object that this object is defined in.
    +        """
    +
    +        self.name = name
    +        """
    +        The identifier name for this object.
    +        """
    +
    +        self.obj = obj
    +        """
    +        The raw python object.
    +        """
    +
    +        docstring = (docstring or inspect.getdoc(obj) or '').strip()
    +        if '.. include::' in docstring:
    +            from pdoc.html_helpers import _ToMarkdown
    +            docstring = _ToMarkdown.admonitions(docstring, self.module, ('include',))
    +        self.docstring = docstring
    +        """
    +        The cleaned docstring for this object with any `.. include::`
    +        directives resolved (i.e. content included).
    +        """
    +
    +        self.inherits: Optional[Union[Class, Function, Variable]] = None
    +        """
    +        The Doc object (Class, Function, or Variable) this object inherits from,
    +        if any.
    +        """
    +
    +    def __repr__(self):
    +        return f'<{self.__class__.__name__} {self.refname!r}>'
    +
    +    @property
    +    @lru_cache()
    +    def source(self) -> str:
    +        """
    +        Cleaned (dedented) source code of the Python object. If not
    +        available, an empty string.
    +        """
    +        try:
    +            lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +        except (ValueError, TypeError, OSError):
    +            return ''
    +        return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +    @property
    +    def refname(self) -> str:
    +        """
    +        Reference name of this documentation
    +        object, usually its fully qualified path
    +        (e.g. <code>pdoc.Doc.refname</code>). Every
    +        documentation object provides this property.
    +        """
    +        # Ok for Module and External, the rest need it overriden
    +        return self.name
    +
    +    @property
    +    def qualname(self) -> str:
    +        """
    +        Module-relative "qualified" name of this documentation
    +        object, used for show (e.g. <code>Doc.qualname</code>).
    +        """
    +        return getattr(self.obj, '__qualname__', self.name)
    +
    +    @lru_cache()
    +    def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +            top_ancestor: bool = False) -> str:
    +        """
    +        Canonical relative URL (including page fragment) for this
    +        documentation object.
    +
    +        Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +        relative URL.
    +
    +        For usage of `link_prefix` see `pdoc.html()`.
    +
    +        If `top_ancestor` is `True`, the returned URL instead points to
    +        the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +        """
    +        if top_ancestor:
    +            self = self._inherits_top()
    +
    +        if relative_to is None or link_prefix:
    +            return link_prefix + self._url()
    +
    +        if self.module.name == relative_to.name:
    +            return f'#{self.refname}'
    +
    +        # Otherwise, compute relative path from current module to link target
    +        url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +        # We have one set of '..' too many
    +        if url.startswith('../'):
    +            url = url[3:]
    +        return url
    +
    +    def _url(self):
    +        return f'{self.module._url()}#{self.refname}'
    +
    +    def _inherits_top(self):
    +        """
    +        Follow the `pdoc.Doc.inherits` chain and return the top object.
    +        """
    +        top = self
    +        while top.inherits:
    +            top = top.inherits
    +        return top
    +
    +    def __lt__(self, other):
    +        return self.refname < other.refname
    +
    +
    +
    prop qualname : str
    +
    +

    Module-relative "qualified" name of this documentation +object, used for show (e.g. Doc.qualname).

    +
    + +Expand source code +Browse git + +
    @property
    +def qualname(self) -> str:
    +    """
    +    Module-relative "qualified" name of this documentation
    +    object, used for show (e.g. <code>Doc.qualname</code>).
    +    """
    +    return getattr(self.obj, '__qualname__', self.name)
    +
    +
    +
    prop refname : str
    +
    +

    Reference name of this documentation +object, usually its fully qualified path +(e.g. pdoc.Doc.refname). Every +documentation object provides this property.

    +
    + +Expand source code +Browse git + +
    @property
    +def refname(self) -> str:
    +    """
    +    Reference name of this documentation
    +    object, usually its fully qualified path
    +    (e.g. <code>pdoc.Doc.refname</code>). Every
    +    documentation object provides this property.
    +    """
    +    # Ok for Module and External, the rest need it overriden
    +    return self.name
    +
    +
    +
    prop source : str
    +
    +

    Cleaned (dedented) source code of the Python object. If not +available, an empty string.

    +
    + +Expand source code +Browse git + +
    @property
    +@lru_cache()
    +def source(self) -> str:
    +    """
    +    Cleaned (dedented) source code of the Python object. If not
    +    available, an empty string.
    +    """
    +    try:
    +        lines, _ = inspect.getsourcelines(_unwrap_descriptor(self))
    +    except (ValueError, TypeError, OSError):
    +        return ''
    +    return inspect.cleandoc(''.join(['\n'] + lines))
    +
    +
    +
    +

    Methods

    +
    +
    +def url(self,
    relative_to: ForwardRef('Module') | None = None,
    *,
    link_prefix: str = '',
    top_ancestor: bool = False) ‑> str
    +
    +
    +

    Canonical relative URL (including page fragment) for this +documentation object.

    +

    Specify relative_to (a Module object) to obtain a +relative URL.

    +

    For usage of link_prefix see html().

    +

    If top_ancestor is True, the returned URL instead points to +the top ancestor in the object's Doc.inherits chain.

    +
    + +Expand source code +Browse git + +
    @lru_cache()
    +def url(self, relative_to: Optional['Module'] = None, *, link_prefix: str = '',
    +        top_ancestor: bool = False) -> str:
    +    """
    +    Canonical relative URL (including page fragment) for this
    +    documentation object.
    +
    +    Specify `relative_to` (a `pdoc.Module` object) to obtain a
    +    relative URL.
    +
    +    For usage of `link_prefix` see `pdoc.html()`.
    +
    +    If `top_ancestor` is `True`, the returned URL instead points to
    +    the top ancestor in the object's `pdoc.Doc.inherits` chain.
    +    """
    +    if top_ancestor:
    +        self = self._inherits_top()
    +
    +    if relative_to is None or link_prefix:
    +        return link_prefix + self._url()
    +
    +    if self.module.name == relative_to.name:
    +        return f'#{self.refname}'
    +
    +    # Otherwise, compute relative path from current module to link target
    +    url = os.path.relpath(self._url(), relative_to.url()).replace(path.sep, '/')
    +    # We have one set of '..' too many
    +    if url.startswith('../'):
    +        url = url[3:]
    +    return url
    +
    +
    +
    +
    +
    +class External +(name: str) +
    +
    +

    A representation of an external identifier. The textual +representation is the same as an internal identifier.

    +

    External identifiers are also used to represent something that is +not documented but appears somewhere in the public interface (like +the ancestor list of a class).

    +

    Initializes an external identifier with name, where name +should be a fully qualified name.

    +
    + +Expand source code +Browse git + +
    class External(Doc):
    +    """
    +    A representation of an external identifier. The textual
    +    representation is the same as an internal identifier.
    +
    +    External identifiers are also used to represent something that is
    +    not documented but appears somewhere in the public interface (like
    +    the ancestor list of a class).
    +    """
    +
    +    __pdoc__["External.docstring"] = """
    +        An empty string. External identifiers do not have
    +        docstrings.
    +        """
    +    __pdoc__["External.module"] = """
    +        Always `None`. External identifiers have no associated
    +        `pdoc.Module`.
    +        """
    +    __pdoc__["External.name"] = """
    +        Always equivalent to `pdoc.External.refname` since external
    +        identifiers are always expressed in their fully qualified
    +        form.
    +        """
    +
    +    def __init__(self, name: str):
    +        """
    +        Initializes an external identifier with `name`, where `name`
    +        should be a fully qualified name.
    +        """
    +        super().__init__(name, None, None)
    +
    +    def url(self, *args, **kwargs):
    +        """
    +        `External` objects return absolute urls matching `/{name}.ext`.
    +        """
    +        return f'/{self.name}.ext'
    +
    +

    Ancestors

    + +

    Methods

    +
    +
    +def url(self, *args, **kwargs) +
    +
    +

    External objects return absolute urls matching /{name}.ext.

    +
    + +Expand source code +Browse git + +
    def url(self, *args, **kwargs):
    +    """
    +    `External` objects return absolute urls matching `/{name}.ext`.
    +    """
    +    return f'/{self.name}.ext'
    +
    +
    +
    +

    Inherited members

    + +
    +
    +class Function +(name: str,
    module: Module,
    obj,
    *,
    cls: Class | None = None)
    +
    +
    +

    Representation of documentation for a function or method.

    +

    Same as Doc, except obj must be a +Python function object. The docstring is gathered automatically.

    +

    cls should be set when this is a method or a static function +beloing to a class. cls should be a Class object.

    +

    method should be True when the function is a method. In +all other cases, it should be False.

    +
    + +Expand source code +Browse git + +
    class Function(Doc):
    +    """
    +    Representation of documentation for a function or method.
    +    """
    +    __slots__ = ('cls',)
    +
    +    def __init__(self, name: str, module: Module, obj, *, cls: Optional[Class] = None):
    +        """
    +        Same as `pdoc.Doc`, except `obj` must be a
    +        Python function object. The docstring is gathered automatically.
    +
    +        `cls` should be set when this is a method or a static function
    +        beloing to a class. `cls` should be a `pdoc.Class` object.
    +
    +        `method` should be `True` when the function is a method. In
    +        all other cases, it should be `False`.
    +        """
    +        assert callable(obj), (name, module, obj)
    +        super().__init__(name, module, obj)
    +
    +        self.cls = cls
    +        """
    +        The `pdoc.Class` documentation object if the function is a method.
    +        If not, this is None.
    +        """
    +
    +    @property
    +    def is_method(self) -> bool:
    +        """
    +        Whether this function is a normal bound method.
    +
    +        In particular, static and class methods have this set to False.
    +        """
    +        assert self.cls
    +        return not Class._method_type(self.cls.obj, self.name)
    +
    +    @property
    +    def method(self):
    +        warn('`Function.method` is deprecated. Use: `Function.is_method`', DeprecationWarning,
    +             stacklevel=2)
    +        return self.is_method
    +
    +    __pdoc__['Function.method'] = False
    +
    +    def funcdef(self) -> str:
    +        """
    +        Generates the string of keywords used to define the function,
    +        for example `def` or `async def`.
    +        """
    +        return 'async def' if self._is_async else 'def'
    +
    +    @property
    +    def _is_async(self):
    +        """
    +        Returns whether is function is asynchronous, either as a coroutine or an async
    +        generator.
    +        """
    +        try:
    +            # Both of these are required because coroutines aren't classified as async
    +            # generators and vice versa.
    +            obj = inspect.unwrap(self.obj)
    +            return (inspect.iscoroutinefunction(obj) or
    +                    inspect.isasyncgenfunction(obj))
    +        except AttributeError:
    +            return False
    +
    +    def return_annotation(self, *, link=None) -> str:
    +        """Formatted function return type annotation or empty string if none."""
    +        annot = ''
    +        for method in (
    +                lambda: _get_type_hints(self.obj)['return'],
    +                # Mainly for non-property variables
    +                lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name],
    +                # global variables
    +                lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
    +                # properties
    +                lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation,
    +                # Use raw annotation strings in unmatched forward declarations
    +                lambda: cast(Class, self.cls).obj.__annotations__[self.name],
    +                # Extract annotation from the docstring for C builtin function
    +                lambda: Function._signature_from_string(self).return_annotation,
    +        ):
    +            try:
    +                annot = method()
    +            except Exception:
    +                continue
    +            else:
    +                break
    +        else:
    +            # Don't warn on variables. The annotation just isn't available.
    +            if not isinstance(self, Variable):
    +                warn(f"Error handling return annotation for {self!r}", stacklevel=3)
    +
    +        if annot is inspect.Parameter.empty or not annot:
    +            return ''
    +
    +        if isinstance(annot, str):
    +            s = annot
    +        else:
    +            s = _formatannotation(annot)
    +            s = re.sub(r'\bForwardRef\((?P<quot>[\"\'])(?P<str>.*?)(?P=quot)\)',
    +                       r'\g<str>', s)
    +        s = s.replace(' ', '\N{NBSP}')  # Better line breaks in html signatures
    +
    +        if link:
    +            from pdoc.html_helpers import _linkify
    +            s = re.sub(r'[\w\.]+', partial(_linkify, link=link, module=self.module), s)
    +        return s
    +
    +    def params(self, *, annotate: bool = False,
    +               link: Optional[Callable[[Doc], str]] = None) -> List[str]:
    +        """
    +        Returns a list where each element is a nicely formatted
    +        parameter of this function. This includes argument lists,
    +        keyword arguments and default values, and it doesn't include any
    +        optional arguments whose names begin with an underscore.
    +
    +        If `annotate` is True, the parameter strings include [PEP 484]
    +        type hint annotations.
    +
    +        [PEP 484]: https://www.python.org/dev/peps/pep-0484/
    +        """
    +        return self._params(self, annotate=annotate, link=link, module=self.module)
    +
    +    @staticmethod
    +    def _params(doc_obj, annotate=False, link=None, module=None):
    +        try:
    +            # We want __init__ to actually be implemented somewhere in the
    +            # MRO to still satisfy https://github.com/pdoc3/pdoc/issues/124
    +            if (
    +                inspect.isclass(doc_obj.obj)
    +                and doc_obj.obj.__init__ is not object.__init__
    +            ):
    +                # Remove the first argument (self) from __init__ signature
    +                init_sig = inspect.signature(doc_obj.obj.__init__)
    +                init_params = list(init_sig.parameters.values())
    +                signature = init_sig.replace(parameters=init_params[1:])
    +            else:
    +                signature = inspect.signature(doc_obj.obj)
    +        except ValueError:
    +            signature = Function._signature_from_string(doc_obj)
    +            if not signature:
    +                return ['...']
    +
    +        def safe_default_value(p: inspect.Parameter):
    +            value = p.default
    +            if value is inspect.Parameter.empty:
    +                return p
    +
    +            replacement = next((i for i in ('os.environ',
    +                                            'sys.stdin',
    +                                            'sys.stdout',
    +                                            'sys.stderr',)
    +                                if value is eval(i)), None)
    +            if not replacement:
    +                if isinstance(value, enum.Enum):
    +                    replacement = str(value)
    +                elif inspect.isclass(value):
    +                    replacement = f'{value.__module__ or _UNKNOWN_MODULE}.{value.__qualname__}'
    +                elif ' at 0x' in repr(value):
    +                    replacement = re.sub(r' at 0x\w+', '', repr(value))
    +
    +                nonlocal link
    +                if link and ('<' in repr(value) or '>' in repr(value)):
    +                    import html
    +                    replacement = html.escape(replacement or repr(value))
    +
    +            if replacement:
    +                class mock:
    +                    def __repr__(self):
    +                        return replacement
    +                return p.replace(default=mock())
    +            return p
    +
    +        params = []
    +        kw_only = False
    +        pos_only = False
    +        EMPTY = inspect.Parameter.empty
    +
    +        if link:
    +            from pdoc.html_helpers import _linkify
    +            _linkify = partial(_linkify, link=link, module=module)
    +
    +        for p in signature.parameters.values():  # type: inspect.Parameter
    +            if not _is_public(p.name) and p.default is not EMPTY:
    +                continue
    +
    +            if p.kind == p.POSITIONAL_ONLY:
    +                pos_only = True
    +            elif pos_only:
    +                params.append("/")
    +                pos_only = False
    +
    +            if p.kind == p.VAR_POSITIONAL:
    +                kw_only = True
    +            if p.kind == p.KEYWORD_ONLY and not kw_only:
    +                kw_only = True
    +                params.append('*')
    +
    +            p = safe_default_value(p)
    +
    +            if not annotate:
    +                p = p.replace(annotation=EMPTY)
    +
    +            formatted = p.name
    +            if p.annotation is not EMPTY:
    +                annotation = _formatannotation(p.annotation).replace(' ', '\N{NBSP}')
    +                # "Eval" forward-declarations (typing string literals)
    +                if isinstance(p.annotation, str):
    +                    annotation = annotation.strip("'")
    +                if link:
    +                    annotation = re.sub(r'[\w\.]+', _linkify, annotation)
    +                formatted += f':\N{NBSP}{annotation}'
    +            if p.default is not EMPTY:
    +                if p.annotation is not EMPTY:
    +                    formatted += f'\N{NBSP}=\N{NBSP}{repr(p.default)}'
    +                else:
    +                    formatted += f'={repr(p.default)}'
    +            if p.kind == p.VAR_POSITIONAL:
    +                formatted = f'*{formatted}'
    +            elif p.kind == p.VAR_KEYWORD:
    +                formatted = f'**{formatted}'
    +
    +            params.append(formatted)
    +
    +        if pos_only:
    +            params.append("/")
    +
    +        return params
    +
    +    @staticmethod
    +    @lru_cache()
    +    def _signature_from_string(self):
    +        signature = None
    +        for expr, cleanup_docstring, filter in (
    +                # Full proper typed signature, such as one from pybind11
    +                (r'^{}\(.*\)(?: -> .*)?$', True, lambda s: s),
    +                # Human-readable, usage-like signature from some Python builtins
    +                # (e.g. `range` or `slice` or `itertools.repeat` or `numpy.arange`)
    +                (r'^{}\(.*\)(?= -|$)', False, lambda s: s.replace('[', '').replace(']', '')),
    +        ):
    +            strings = sorted(re.findall(expr.format(self.name),
    +                                        self.docstring, re.MULTILINE),
    +                             key=len, reverse=True)
    +            if strings:
    +                string = filter(strings[0])
    +                _locals, _globals = {}, {}
    +                _globals.update({'capsule': None})  # pybind11 capsule data type
    +                _globals.update(typing.__dict__)
    +                _globals.update(self.module.obj.__dict__)
    +                # Trim binding module basename from type annotations
    +                # See: https://github.com/pdoc3/pdoc/pull/148#discussion_r407114141
    +                module_basename = self.module.name.rsplit('.', maxsplit=1)[-1]
    +                if module_basename in string and module_basename not in _globals:
    +                    string = re.sub(fr'(?<!\.)\b{module_basename}\.\b', '', string)
    +
    +                try:
    +                    exec(f'def {string}: pass', _globals, _locals)
    +                except Exception:
    +                    continue
    +                signature = inspect.signature(_locals[self.name])
    +                if cleanup_docstring and len(strings) == 1:
    +                    # Remove signature from docstring variable
    +                    self.docstring = self.docstring.replace(strings[0], '')
    +                break
    +        return signature
    +
    +    @property
    +    def refname(self) -> str:
    +        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    +
    +

    Ancestors

    + +

    Instance variables

    +
    +
    var cls
    +
    +

    The Class documentation object if the function is a method. +If not, this is None.

    +
    + +Expand source code +Browse git + +
    class Function(Doc):
    +    """
    +    Representation of documentation for a function or method.
    +    """
    +    __slots__ = ('cls',)
    +
    +    def __init__(self, name: str, module: Module, obj, *, cls: Optional[Class] = None):
    +        """
    +        Same as `pdoc.Doc`, except `obj` must be a
    +        Python function object. The docstring is gathered automatically.
    +
    +        `cls` should be set when this is a method or a static function
    +        beloing to a class. `cls` should be a `pdoc.Class` object.
    +
    +        `method` should be `True` when the function is a method. In
    +        all other cases, it should be `False`.
    +        """
    +        assert callable(obj), (name, module, obj)
    +        super().__init__(name, module, obj)
    +
    +        self.cls = cls
    +        """
    +        The `pdoc.Class` documentation object if the function is a method.
    +        If not, this is None.
    +        """
    +
    +    @property
    +    def is_method(self) -> bool:
    +        """
    +        Whether this function is a normal bound method.
    +
    +        In particular, static and class methods have this set to False.
    +        """
    +        assert self.cls
    +        return not Class._method_type(self.cls.obj, self.name)
    +
    +    @property
    +    def method(self):
    +        warn('`Function.method` is deprecated. Use: `Function.is_method`', DeprecationWarning,
    +             stacklevel=2)
    +        return self.is_method
    +
    +    __pdoc__['Function.method'] = False
    +
    +    def funcdef(self) -> str:
    +        """
    +        Generates the string of keywords used to define the function,
    +        for example `def` or `async def`.
    +        """
    +        return 'async def' if self._is_async else 'def'
    +
    +    @property
    +    def _is_async(self):
    +        """
    +        Returns whether is function is asynchronous, either as a coroutine or an async
    +        generator.
    +        """
    +        try:
    +            # Both of these are required because coroutines aren't classified as async
    +            # generators and vice versa.
    +            obj = inspect.unwrap(self.obj)
    +            return (inspect.iscoroutinefunction(obj) or
    +                    inspect.isasyncgenfunction(obj))
    +        except AttributeError:
    +            return False
    +
    +    def return_annotation(self, *, link=None) -> str:
    +        """Formatted function return type annotation or empty string if none."""
    +        annot = ''
    +        for method in (
    +                lambda: _get_type_hints(self.obj)['return'],
    +                # Mainly for non-property variables
    +                lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name],
    +                # global variables
    +                lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
    +                # properties
    +                lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation,
    +                # Use raw annotation strings in unmatched forward declarations
    +                lambda: cast(Class, self.cls).obj.__annotations__[self.name],
    +                # Extract annotation from the docstring for C builtin function
    +                lambda: Function._signature_from_string(self).return_annotation,
    +        ):
    +            try:
    +                annot = method()
    +            except Exception:
    +                continue
    +            else:
    +                break
    +        else:
    +            # Don't warn on variables. The annotation just isn't available.
    +            if not isinstance(self, Variable):
    +                warn(f"Error handling return annotation for {self!r}", stacklevel=3)
    +
    +        if annot is inspect.Parameter.empty or not annot:
    +            return ''
    +
    +        if isinstance(annot, str):
    +            s = annot
    +        else:
    +            s = _formatannotation(annot)
    +            s = re.sub(r'\bForwardRef\((?P<quot>[\"\'])(?P<str>.*?)(?P=quot)\)',
    +                       r'\g<str>', s)
    +        s = s.replace(' ', '\N{NBSP}')  # Better line breaks in html signatures
    +
    +        if link:
    +            from pdoc.html_helpers import _linkify
    +            s = re.sub(r'[\w\.]+', partial(_linkify, link=link, module=self.module), s)
    +        return s
    +
    +    def params(self, *, annotate: bool = False,
    +               link: Optional[Callable[[Doc], str]] = None) -> List[str]:
    +        """
    +        Returns a list where each element is a nicely formatted
    +        parameter of this function. This includes argument lists,
    +        keyword arguments and default values, and it doesn't include any
    +        optional arguments whose names begin with an underscore.
    +
    +        If `annotate` is True, the parameter strings include [PEP 484]
    +        type hint annotations.
    +
    +        [PEP 484]: https://www.python.org/dev/peps/pep-0484/
    +        """
    +        return self._params(self, annotate=annotate, link=link, module=self.module)
    +
    +    @staticmethod
    +    def _params(doc_obj, annotate=False, link=None, module=None):
    +        try:
    +            # We want __init__ to actually be implemented somewhere in the
    +            # MRO to still satisfy https://github.com/pdoc3/pdoc/issues/124
    +            if (
    +                inspect.isclass(doc_obj.obj)
    +                and doc_obj.obj.__init__ is not object.__init__
    +            ):
    +                # Remove the first argument (self) from __init__ signature
    +                init_sig = inspect.signature(doc_obj.obj.__init__)
    +                init_params = list(init_sig.parameters.values())
    +                signature = init_sig.replace(parameters=init_params[1:])
    +            else:
    +                signature = inspect.signature(doc_obj.obj)
    +        except ValueError:
    +            signature = Function._signature_from_string(doc_obj)
    +            if not signature:
    +                return ['...']
    +
    +        def safe_default_value(p: inspect.Parameter):
    +            value = p.default
    +            if value is inspect.Parameter.empty:
    +                return p
    +
    +            replacement = next((i for i in ('os.environ',
    +                                            'sys.stdin',
    +                                            'sys.stdout',
    +                                            'sys.stderr',)
    +                                if value is eval(i)), None)
    +            if not replacement:
    +                if isinstance(value, enum.Enum):
    +                    replacement = str(value)
    +                elif inspect.isclass(value):
    +                    replacement = f'{value.__module__ or _UNKNOWN_MODULE}.{value.__qualname__}'
    +                elif ' at 0x' in repr(value):
    +                    replacement = re.sub(r' at 0x\w+', '', repr(value))
    +
    +                nonlocal link
    +                if link and ('<' in repr(value) or '>' in repr(value)):
    +                    import html
    +                    replacement = html.escape(replacement or repr(value))
    +
    +            if replacement:
    +                class mock:
    +                    def __repr__(self):
    +                        return replacement
    +                return p.replace(default=mock())
    +            return p
    +
    +        params = []
    +        kw_only = False
    +        pos_only = False
    +        EMPTY = inspect.Parameter.empty
    +
    +        if link:
    +            from pdoc.html_helpers import _linkify
    +            _linkify = partial(_linkify, link=link, module=module)
    +
    +        for p in signature.parameters.values():  # type: inspect.Parameter
    +            if not _is_public(p.name) and p.default is not EMPTY:
    +                continue
    +
    +            if p.kind == p.POSITIONAL_ONLY:
    +                pos_only = True
    +            elif pos_only:
                     params.append("/")
                     pos_only = False
     
    -            if p.kind == p.VAR_POSITIONAL:
    -                kw_only = True
    -            if p.kind == p.KEYWORD_ONLY and not kw_only:
    -                kw_only = True
    -                params.append('*')
    +            if p.kind == p.VAR_POSITIONAL:
    +                kw_only = True
    +            if p.kind == p.KEYWORD_ONLY and not kw_only:
    +                kw_only = True
    +                params.append('*')
    +
    +            p = safe_default_value(p)
    +
    +            if not annotate:
    +                p = p.replace(annotation=EMPTY)
    +
    +            formatted = p.name
    +            if p.annotation is not EMPTY:
    +                annotation = _formatannotation(p.annotation).replace(' ', '\N{NBSP}')
    +                # "Eval" forward-declarations (typing string literals)
    +                if isinstance(p.annotation, str):
    +                    annotation = annotation.strip("'")
    +                if link:
    +                    annotation = re.sub(r'[\w\.]+', _linkify, annotation)
    +                formatted += f':\N{NBSP}{annotation}'
    +            if p.default is not EMPTY:
    +                if p.annotation is not EMPTY:
    +                    formatted += f'\N{NBSP}=\N{NBSP}{repr(p.default)}'
    +                else:
    +                    formatted += f'={repr(p.default)}'
    +            if p.kind == p.VAR_POSITIONAL:
    +                formatted = f'*{formatted}'
    +            elif p.kind == p.VAR_KEYWORD:
    +                formatted = f'**{formatted}'
    +
    +            params.append(formatted)
    +
    +        if pos_only:
    +            params.append("/")
    +
    +        return params
    +
    +    @staticmethod
    +    @lru_cache()
    +    def _signature_from_string(self):
    +        signature = None
    +        for expr, cleanup_docstring, filter in (
    +                # Full proper typed signature, such as one from pybind11
    +                (r'^{}\(.*\)(?: -> .*)?$', True, lambda s: s),
    +                # Human-readable, usage-like signature from some Python builtins
    +                # (e.g. `range` or `slice` or `itertools.repeat` or `numpy.arange`)
    +                (r'^{}\(.*\)(?= -|$)', False, lambda s: s.replace('[', '').replace(']', '')),
    +        ):
    +            strings = sorted(re.findall(expr.format(self.name),
    +                                        self.docstring, re.MULTILINE),
    +                             key=len, reverse=True)
    +            if strings:
    +                string = filter(strings[0])
    +                _locals, _globals = {}, {}
    +                _globals.update({'capsule': None})  # pybind11 capsule data type
    +                _globals.update(typing.__dict__)
    +                _globals.update(self.module.obj.__dict__)
    +                # Trim binding module basename from type annotations
    +                # See: https://github.com/pdoc3/pdoc/pull/148#discussion_r407114141
    +                module_basename = self.module.name.rsplit('.', maxsplit=1)[-1]
    +                if module_basename in string and module_basename not in _globals:
    +                    string = re.sub(fr'(?<!\.)\b{module_basename}\.\b', '', string)
    +
    +                try:
    +                    exec(f'def {string}: pass', _globals, _locals)
    +                except Exception:
    +                    continue
    +                signature = inspect.signature(_locals[self.name])
    +                if cleanup_docstring and len(strings) == 1:
    +                    # Remove signature from docstring variable
    +                    self.docstring = self.docstring.replace(strings[0], '')
    +                break
    +        return signature
    +
    +    @property
    +    def refname(self) -> str:
    +        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    +
    +
    +
    prop is_method : bool
    +
    +

    Whether this function is a normal bound method.

    +

    In particular, static and class methods have this set to False.

    +
    + +Expand source code +Browse git + +
    @property
    +def is_method(self) -> bool:
    +    """
    +    Whether this function is a normal bound method.
    +
    +    In particular, static and class methods have this set to False.
    +    """
    +    assert self.cls
    +    return not Class._method_type(self.cls.obj, self.name)
    +
    +
    +
    +

    Methods

    +
    +
    +def funcdef(self) ‑> str +
    +
    +

    Generates the string of keywords used to define the function, +for example def or async def.

    +
    + +Expand source code +Browse git + +
    def funcdef(self) -> str:
    +    """
    +    Generates the string of keywords used to define the function,
    +    for example `def` or `async def`.
    +    """
    +    return 'async def' if self._is_async else 'def'
    +
    +
    +
    +def params(self,
    *,
    annotate: bool = False,
    link: Callable[[Doc], str] | None = None) ‑> List[str]
    +
    +
    +

    Returns a list where each element is a nicely formatted +parameter of this function. This includes argument lists, +keyword arguments and default values, and it doesn't include any +optional arguments whose names begin with an underscore.

    +

    If annotate is True, the parameter strings include PEP 484 +type hint annotations.

    +
    + +Expand source code +Browse git + +
    def params(self, *, annotate: bool = False,
    +           link: Optional[Callable[[Doc], str]] = None) -> List[str]:
    +    """
    +    Returns a list where each element is a nicely formatted
    +    parameter of this function. This includes argument lists,
    +    keyword arguments and default values, and it doesn't include any
    +    optional arguments whose names begin with an underscore.
    +
    +    If `annotate` is True, the parameter strings include [PEP 484]
    +    type hint annotations.
    +
    +    [PEP 484]: https://www.python.org/dev/peps/pep-0484/
    +    """
    +    return self._params(self, annotate=annotate, link=link, module=self.module)
    +
    +
    +
    +def return_annotation(self, *, link=None) ‑> str +
    +
    +

    Formatted function return type annotation or empty string if none.

    +
    + +Expand source code +Browse git + +
    def return_annotation(self, *, link=None) -> str:
    +    """Formatted function return type annotation or empty string if none."""
    +    annot = ''
    +    for method in (
    +            lambda: _get_type_hints(self.obj)['return'],
    +            # Mainly for non-property variables
    +            lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name],
    +            # global variables
    +            lambda: _get_type_hints(not self.cls and self.module.obj)[self.name],
    +            # properties
    +            lambda: inspect.signature(_unwrap_descriptor(self)).return_annotation,
    +            # Use raw annotation strings in unmatched forward declarations
    +            lambda: cast(Class, self.cls).obj.__annotations__[self.name],
    +            # Extract annotation from the docstring for C builtin function
    +            lambda: Function._signature_from_string(self).return_annotation,
    +    ):
    +        try:
    +            annot = method()
    +        except Exception:
    +            continue
    +        else:
    +            break
    +    else:
    +        # Don't warn on variables. The annotation just isn't available.
    +        if not isinstance(self, Variable):
    +            warn(f"Error handling return annotation for {self!r}", stacklevel=3)
    +
    +    if annot is inspect.Parameter.empty or not annot:
    +        return ''
    +
    +    if isinstance(annot, str):
    +        s = annot
    +    else:
    +        s = _formatannotation(annot)
    +        s = re.sub(r'\bForwardRef\((?P<quot>[\"\'])(?P<str>.*?)(?P=quot)\)',
    +                   r'\g<str>', s)
    +    s = s.replace(' ', '\N{NBSP}')  # Better line breaks in html signatures
    +
    +    if link:
    +        from pdoc.html_helpers import _linkify
    +        s = re.sub(r'[\w\.]+', partial(_linkify, link=link, module=self.module), s)
    +    return s
    +
    +
    +
    +

    Inherited members

    + +
    +
    +class Module +(module: str | module,
    *,
    docfilter: Callable[[Doc], bool] | None = None,
    supermodule: ForwardRef('Module') | None = None,
    context: Context | None = None,
    skip_errors: bool = False)
    +
    +
    +

    Representation of a module's documentation.

    +

    Creates a Module documentation object given the actual +module Python object.

    +

    docfilter is an optional predicate that controls which +sub-objects are documentated (see also: html()).

    +

    supermodule is the parent Module this module is +a submodule of.

    +

    context is an instance of Context. If None a +global context object will be used.

    +

    If skip_errors is True and an unimportable, erroneous +submodule is encountered, a warning will be issued instead +of raising an exception.

    +
    + +Expand source code +Browse git + +
    class Module(Doc):
    +    """
    +    Representation of a module's documentation.
    +    """
    +    __pdoc__["Module.name"] = """
    +        The name of this module with respect to the context/path in which
    +        it was imported from. It is always an absolute import path.
    +        """
    +
    +    __slots__ = ('supermodule', 'doc', '_context', '_is_inheritance_linked',
    +                 '_skipped_submodules')
    +
    +    def __init__(self, module: Union[ModuleType, str], *,
    +                 docfilter: Optional[Callable[[Doc], bool]] = None,
    +                 supermodule: Optional['Module'] = None,
    +                 context: Optional[Context] = None,
    +                 skip_errors: bool = False):
    +        """
    +        Creates a `Module` documentation object given the actual
    +        module Python object.
    +
    +        `docfilter` is an optional predicate that controls which
    +        sub-objects are documentated (see also: `pdoc.html()`).
    +
    +        `supermodule` is the parent `pdoc.Module` this module is
    +        a submodule of.
    +
    +        `context` is an instance of `pdoc.Context`. If `None` a
    +        global context object will be used.
    +
    +        If `skip_errors` is `True` and an unimportable, erroneous
    +        submodule is encountered, a warning will be issued instead
    +        of raising an exception.
    +        """
    +        if isinstance(module, str):
    +            module = import_module(module, skip_errors=skip_errors)
    +
    +        super().__init__(module.__name__, self, module)
    +        if self.name.endswith('.__init__') and not self.is_package:
    +            self.name = self.name[:-len('.__init__')]
    +
    +        self._context = _global_context if context is None else context
    +        """
    +        A lookup table for ALL doc objects of all modules that share this context,
    +        mainly used in `Module.find_ident()`.
    +        """
    +        assert isinstance(self._context, Context), \
    +            'pdoc.Module(context=) should be a pdoc.Context instance'
    +
    +        self.supermodule = supermodule
    +        """
    +        The parent `pdoc.Module` this module is a submodule of, or `None`.
    +        """
    +
    +        self.doc: Dict[str, Union[Module, Class, Function, Variable]] = {}
    +        """A mapping from identifier name to a documentation object."""
    +
    +        self._is_inheritance_linked = False
    +        """Re-entry guard for `pdoc.Module._link_inheritance()`."""
    +
    +        self._skipped_submodules = set()
    +
    +        var_docstrings, _ = _pep224_docstrings(self)
    +
    +        # Populate self.doc with this module's public members
    +        public_objs = []
    +        if hasattr(self.obj, '__all__'):
    +            for name in self.obj.__all__:
    +                try:
    +                    obj = getattr(self.obj, name)
    +                except AttributeError:
    +                    warn(f"Module {self.module!r} doesn't contain identifier `{name}` "
    +                         "exported in `__all__`")
    +                else:
    +                    if not _is_blacklisted(name, self):
    +                        obj = inspect.unwrap(obj)
    +                    public_objs.append((name, obj))
    +        else:
    +            def is_from_this_module(obj):
    +                mod = inspect.getmodule(inspect.unwrap(obj))
    +                return mod is None or mod.__name__ == self.obj.__name__
    +
    +            for name, obj in inspect.getmembers(self.obj):
    +                if ((_is_public(name) or
    +                     _is_whitelisted(name, self)) and
    +                        (_is_blacklisted(name, self) or  # skips unwrapping that follows
    +                         is_from_this_module(obj) or
    +                         name in var_docstrings)):
    +
    +                    if _is_blacklisted(name, self):
    +                        self._context.blacklisted.add(f'{self.refname}.{name}')
    +                        continue
    +
    +                    obj = inspect.unwrap(obj)
    +                    public_objs.append((name, obj))
    +
    +            index = list(self.obj.__dict__).index
    +            public_objs.sort(key=lambda i: index(i[0]))
    +
    +        for name, obj in public_objs:
    +            if _is_function(obj):
    +                self.doc[name] = Function(name, self, obj)
    +            elif inspect.isclass(obj):
    +                self.doc[name] = Class(name, self, obj)
    +            elif name in var_docstrings:
    +                self.doc[name] = Variable(name, self, var_docstrings[name], obj=obj)
    +
    +        # If the module is a package, scan the directory for submodules
    +        if self.is_package:
    +
    +            def iter_modules(paths):
    +                """
    +                Custom implementation of `pkgutil.iter_modules()`
    +                because that one doesn't play well with namespace packages.
    +                See: https://github.com/pypa/setuptools/issues/83
    +                """
    +                from os.path import isdir, join
    +                for pth in paths:
    +                    if pth.startswith("__editable__."):
    +                        # See https://github.com/pypa/pip/issues/11380
    +                        continue
    +                    for file in os.listdir(pth):
    +                        if file.startswith(('.', '__pycache__', '__init__.py')):
    +                            continue
    +                        module_name = inspect.getmodulename(file)
    +                        if module_name:
    +                            yield module_name
    +                        if isdir(join(pth, file)) and '.' not in file:
    +                            yield file
    +
    +            for root in iter_modules(self.obj.__path__):
    +                # Ignore if this module was already doc'd.
    +                if root in self.doc:
    +                    continue
    +
    +                # Ignore if it isn't exported
    +                if not _is_public(root) and not _is_whitelisted(root, self):
    +                    continue
    +                if _is_blacklisted(root, self):
    +                    self._skipped_submodules.add(root)
    +                    continue
    +
    +                assert self.refname == self.name
    +                fullname = f"{self.name}.{root}"
    +                m = Module(import_module(fullname, skip_errors=skip_errors),
    +                           docfilter=docfilter, supermodule=self,
    +                           context=self._context, skip_errors=skip_errors)
    +
    +                self.doc[root] = m
    +                # Skip empty namespace packages because they may
    +                # as well be other auxiliary directories
    +                if m.is_namespace and not m.doc:
    +                    del self.doc[root]
    +                    self._context.pop(m.refname)
    +
    +        # Apply docfilter
    +        if docfilter:
    +            for name, dobj in self.doc.copy().items():
    +                if not docfilter(dobj):
    +                    self.doc.pop(name)
    +                    self._context.pop(dobj.refname, None)
    +
    +        # Build the reference name dictionary of the module
    +        self._context[self.refname] = self
    +        for docobj in self.doc.values():
    +            self._context[docobj.refname] = docobj
    +            if isinstance(docobj, Class):
    +                self._context.update((obj.refname, obj)
    +                                     for obj in docobj.doc.values())
    +
    +    class ImportWarning(UserWarning):
    +        """
    +        Our custom import warning because the builtin is ignored by default.
    +        https://docs.python.org/3/library/warnings.html#default-warning-filter
    +        """
    +
    +    __pdoc__['Module.ImportWarning'] = False
    +
    +    @property
    +    def __pdoc__(self) -> dict:
    +        """This module's __pdoc__ dict, or an empty dict if none."""
    +        return getattr(self.obj, '__pdoc__', {})
    +
    +    def _link_inheritance(self):
    +        # Inherited members are already in place since
    +        # `Class._fill_inheritance()` has been called from
    +        # `pdoc.fill_inheritance()`.
    +        # Now look for docstrings in the module's __pdoc__ override.
    +
    +        if self._is_inheritance_linked:
    +            # Prevent re-linking inheritance for modules which have already
    +            # had done so. Otherwise, this would raise "does not exist"
    +            # errors if `pdoc.link_inheritance()` is called multiple times.
    +            return
    +
    +        # Apply __pdoc__ overrides
    +        for name, docstring in self.__pdoc__.items():
    +            # In case of whitelisting with "True", there's nothing to do
    +            if docstring is True:
    +                continue
    +
    +            refname = f"{self.refname}.{name}"
    +            if docstring in (False, None):
    +                if docstring is None:
    +                    warn('Setting `__pdoc__[key] = None` is deprecated; '
    +                         'use `__pdoc__[key] = False` '
    +                         f'(key: {name!r}, module: {self.name!r}).')
    +
    +                if name in self._skipped_submodules:
    +                    continue
    +
    +                if (not name.endswith('.__init__') and
    +                        name not in self.doc and
    +                        refname not in self._context and
    +                        refname not in self._context.blacklisted):
    +                    warn(f'__pdoc__-overriden key {name!r} does not exist '
    +                         f'in module {self.name!r}')
    +
    +                obj = self.find_ident(name)
    +                cls = getattr(obj, 'cls', None)
    +                if cls:
    +                    del cls.doc[obj.name]
    +                self.doc.pop(name, None)
    +                self._context.pop(refname, None)
    +
    +                # Pop also all that startwith refname
    +                for key in list(self._context.keys()):
    +                    if key.startswith(refname + '.'):
    +                        del self._context[key]
    +
    +                continue
    +
    +            dobj = self.find_ident(refname)
    +            if isinstance(dobj, External):
    +                continue
    +            if not isinstance(docstring, str):
    +                raise ValueError('__pdoc__ dict values must be strings; '
    +                                 f'__pdoc__[{name!r}] is of type {type(docstring)}')
    +            dobj.docstring = inspect.cleandoc(docstring)
    +
    +        # Now after docstrings are set correctly, continue the
    +        # inheritance routine, marking members inherited or not
    +        for c in _filter_type(Class, self.doc):
    +            c._link_inheritance()
    +
    +        self._is_inheritance_linked = True
    +
    +    def text(self, **kwargs) -> str:
    +        """
    +        Returns the documentation for this module as plain text.
    +        """
    +        txt = _render_template('/text.mako', module=self, **kwargs)
    +        return re.sub("\n\n\n+", "\n\n", txt)
    +
    +    def html(self, minify=True, **kwargs) -> str:
    +        """
    +        Returns the documentation for this module as
    +        self-contained HTML.
    +
    +        If `minify` is `True`, the resulting HTML is minified.
    +
    +        For explanation of other arguments, see `pdoc.html()`.
    +
    +        `kwargs` is passed to the `mako` render function.
    +        """
    +        html = _render_template('/html.mako', module=self, **kwargs)
    +        if minify:
    +            from pdoc.html_helpers import minify_html
    +            html = minify_html(html)
    +        if not html.endswith('\n'):
    +            html = html + '\n'
    +        return html
    +
    +    @property
    +    def is_package(self) -> bool:
    +        """
    +        `True` if this module is a package.
    +
    +        Works by checking whether the module has a `__path__` attribute.
    +        """
    +        return hasattr(self.obj, "__path__")
    +
    +    @property
    +    def is_namespace(self) -> bool:
    +        """
    +        `True` if this module is a namespace package.
    +        """
    +        try:
    +            return self.obj.__spec__.origin in (None, 'namespace')  # None in Py3.7+
    +        except AttributeError:
    +            return False
    +
    +    def find_class(self, cls: type) -> Doc:
    +        """
    +        Given a Python `cls` object, try to find it in this module
    +        or in any of the exported identifiers of the submodules.
    +        """
    +        # XXX: Is this corrent? Does it always match
    +        # `Class.module.name + Class.qualname`?. Especially now?
    +        # If not, see what was here before.
    +        return self.find_ident(f'{cls.__module__ or _UNKNOWN_MODULE}.{cls.__qualname__}')
    +
    +    def find_ident(self, name: str) -> Doc:
    +        """
    +        Searches this module and **all** other public modules
    +        for an identifier with name `name` in its list of
    +        exported identifiers.
    +
    +        The documentation object corresponding to the identifier is
    +        returned. If one cannot be found, then an instance of
    +        `External` is returned populated with the given identifier.
    +        """
    +        _name = name.rstrip('()')  # Function specified with parentheses
    +
    +        if _name.endswith('.__init__'):  # Ref to class' init is ref to class itself
    +            _name = _name[:-len('.__init__')]
    +
    +        return (self.doc.get(_name) or
    +                self._context.get(_name) or
    +                self._context.get(f'{self.name}.{_name}') or
    +                External(name))
    +
    +    def _filter_doc_objs(self, type: Type[T], sort=True) -> List[T]:
    +        result = _filter_type(type, self.doc)
    +        return sorted(result) if sort else result
    +
    +    def variables(self, sort=True) -> List['Variable']:
    +        """
    +        Returns all documented module-level variables in the module,
    +        optionally sorted alphabetically, as a list of `pdoc.Variable`.
    +        """
    +        return self._filter_doc_objs(Variable, sort)
    +
    +    def classes(self, sort=True) -> List['Class']:
    +        """
    +        Returns all documented module-level classes in the module,
    +        optionally sorted alphabetically, as a list of `pdoc.Class`.
    +        """
    +        return self._filter_doc_objs(Class, sort)
    +
    +    def functions(self, sort=True) -> List['Function']:
    +        """
    +        Returns all documented module-level functions in the module,
    +        optionally sorted alphabetically, as a list of `pdoc.Function`.
    +        """
    +        return self._filter_doc_objs(Function, sort)
    +
    +    def submodules(self) -> List['Module']:
    +        """
    +        Returns all documented sub-modules of the module sorted
    +        alphabetically as a list of `pdoc.Module`.
    +        """
    +        return self._filter_doc_objs(Module)
    +
    +    def _url(self):
    +        url = self.module.name.replace('.', '/')
    +        if self.is_package:
    +            return url + _URL_PACKAGE_SUFFIX
    +        elif url.endswith('/index'):
    +            return url + _URL_INDEX_MODULE_SUFFIX
    +        return url + _URL_MODULE_SUFFIX
    +
    +

    Ancestors

    + +

    Instance variables

    +
    +
    var doc
    +
    +

    A mapping from identifier name to a documentation object.

    +
    + +Expand source code +Browse git + +
    class Module(Doc):
    +    """
    +    Representation of a module's documentation.
    +    """
    +    __pdoc__["Module.name"] = """
    +        The name of this module with respect to the context/path in which
    +        it was imported from. It is always an absolute import path.
    +        """
    +
    +    __slots__ = ('supermodule', 'doc', '_context', '_is_inheritance_linked',
    +                 '_skipped_submodules')
    +
    +    def __init__(self, module: Union[ModuleType, str], *,
    +                 docfilter: Optional[Callable[[Doc], bool]] = None,
    +                 supermodule: Optional['Module'] = None,
    +                 context: Optional[Context] = None,
    +                 skip_errors: bool = False):
    +        """
    +        Creates a `Module` documentation object given the actual
    +        module Python object.
    +
    +        `docfilter` is an optional predicate that controls which
    +        sub-objects are documentated (see also: `pdoc.html()`).
    +
    +        `supermodule` is the parent `pdoc.Module` this module is
    +        a submodule of.
    +
    +        `context` is an instance of `pdoc.Context`. If `None` a
    +        global context object will be used.
    +
    +        If `skip_errors` is `True` and an unimportable, erroneous
    +        submodule is encountered, a warning will be issued instead
    +        of raising an exception.
    +        """
    +        if isinstance(module, str):
    +            module = import_module(module, skip_errors=skip_errors)
    +
    +        super().__init__(module.__name__, self, module)
    +        if self.name.endswith('.__init__') and not self.is_package:
    +            self.name = self.name[:-len('.__init__')]
    +
    +        self._context = _global_context if context is None else context
    +        """
    +        A lookup table for ALL doc objects of all modules that share this context,
    +        mainly used in `Module.find_ident()`.
    +        """
    +        assert isinstance(self._context, Context), \
    +            'pdoc.Module(context=) should be a pdoc.Context instance'
    +
    +        self.supermodule = supermodule
    +        """
    +        The parent `pdoc.Module` this module is a submodule of, or `None`.
    +        """
    +
    +        self.doc: Dict[str, Union[Module, Class, Function, Variable]] = {}
    +        """A mapping from identifier name to a documentation object."""
    +
    +        self._is_inheritance_linked = False
    +        """Re-entry guard for `pdoc.Module._link_inheritance()`."""
    +
    +        self._skipped_submodules = set()
    +
    +        var_docstrings, _ = _pep224_docstrings(self)
    +
    +        # Populate self.doc with this module's public members
    +        public_objs = []
    +        if hasattr(self.obj, '__all__'):
    +            for name in self.obj.__all__:
    +                try:
    +                    obj = getattr(self.obj, name)
    +                except AttributeError:
    +                    warn(f"Module {self.module!r} doesn't contain identifier `{name}` "
    +                         "exported in `__all__`")
    +                else:
    +                    if not _is_blacklisted(name, self):
    +                        obj = inspect.unwrap(obj)
    +                    public_objs.append((name, obj))
    +        else:
    +            def is_from_this_module(obj):
    +                mod = inspect.getmodule(inspect.unwrap(obj))
    +                return mod is None or mod.__name__ == self.obj.__name__
    +
    +            for name, obj in inspect.getmembers(self.obj):
    +                if ((_is_public(name) or
    +                     _is_whitelisted(name, self)) and
    +                        (_is_blacklisted(name, self) or  # skips unwrapping that follows
    +                         is_from_this_module(obj) or
    +                         name in var_docstrings)):
     
    -            p = safe_default_value(p)
    +                    if _is_blacklisted(name, self):
    +                        self._context.blacklisted.add(f'{self.refname}.{name}')
    +                        continue
     
    -            if not annotate:
    -                p = p.replace(annotation=EMPTY)
    +                    obj = inspect.unwrap(obj)
    +                    public_objs.append((name, obj))
     
    -            formatted = p.name
    -            if p.annotation is not EMPTY:
    -                annotation = _formatannotation(p.annotation).replace(' ', '\N{NBSP}')
    -                # "Eval" forward-declarations (typing string literals)
    -                if isinstance(p.annotation, str):
    -                    annotation = annotation.strip("'")
    -                if link:
    -                    annotation = re.sub(r'[\w\.]+', _linkify, annotation)
    -                formatted += f':\N{NBSP}{annotation}'
    -            if p.default is not EMPTY:
    -                if p.annotation is not EMPTY:
    -                    formatted += f'\N{NBSP}=\N{NBSP}{repr(p.default)}'
    -                else:
    -                    formatted += f'={repr(p.default)}'
    -            if p.kind == p.VAR_POSITIONAL:
    -                formatted = f'*{formatted}'
    -            elif p.kind == p.VAR_KEYWORD:
    -                formatted = f'**{formatted}'
    +            index = list(self.obj.__dict__).index
    +            public_objs.sort(key=lambda i: index(i[0]))
    +
    +        for name, obj in public_objs:
    +            if _is_function(obj):
    +                self.doc[name] = Function(name, self, obj)
    +            elif inspect.isclass(obj):
    +                self.doc[name] = Class(name, self, obj)
    +            elif name in var_docstrings:
    +                self.doc[name] = Variable(name, self, var_docstrings[name], obj=obj)
    +
    +        # If the module is a package, scan the directory for submodules
    +        if self.is_package:
    +
    +            def iter_modules(paths):
    +                """
    +                Custom implementation of `pkgutil.iter_modules()`
    +                because that one doesn't play well with namespace packages.
    +                See: https://github.com/pypa/setuptools/issues/83
    +                """
    +                from os.path import isdir, join
    +                for pth in paths:
    +                    if pth.startswith("__editable__."):
    +                        # See https://github.com/pypa/pip/issues/11380
    +                        continue
    +                    for file in os.listdir(pth):
    +                        if file.startswith(('.', '__pycache__', '__init__.py')):
    +                            continue
    +                        module_name = inspect.getmodulename(file)
    +                        if module_name:
    +                            yield module_name
    +                        if isdir(join(pth, file)) and '.' not in file:
    +                            yield file
    +
    +            for root in iter_modules(self.obj.__path__):
    +                # Ignore if this module was already doc'd.
    +                if root in self.doc:
    +                    continue
    +
    +                # Ignore if it isn't exported
    +                if not _is_public(root) and not _is_whitelisted(root, self):
    +                    continue
    +                if _is_blacklisted(root, self):
    +                    self._skipped_submodules.add(root)
    +                    continue
    +
    +                assert self.refname == self.name
    +                fullname = f"{self.name}.{root}"
    +                m = Module(import_module(fullname, skip_errors=skip_errors),
    +                           docfilter=docfilter, supermodule=self,
    +                           context=self._context, skip_errors=skip_errors)
    +
    +                self.doc[root] = m
    +                # Skip empty namespace packages because they may
    +                # as well be other auxiliary directories
    +                if m.is_namespace and not m.doc:
    +                    del self.doc[root]
    +                    self._context.pop(m.refname)
    +
    +        # Apply docfilter
    +        if docfilter:
    +            for name, dobj in self.doc.copy().items():
    +                if not docfilter(dobj):
    +                    self.doc.pop(name)
    +                    self._context.pop(dobj.refname, None)
    +
    +        # Build the reference name dictionary of the module
    +        self._context[self.refname] = self
    +        for docobj in self.doc.values():
    +            self._context[docobj.refname] = docobj
    +            if isinstance(docobj, Class):
    +                self._context.update((obj.refname, obj)
    +                                     for obj in docobj.doc.values())
    +
    +    class ImportWarning(UserWarning):
    +        """
    +        Our custom import warning because the builtin is ignored by default.
    +        https://docs.python.org/3/library/warnings.html#default-warning-filter
    +        """
    +
    +    __pdoc__['Module.ImportWarning'] = False
    +
    +    @property
    +    def __pdoc__(self) -> dict:
    +        """This module's __pdoc__ dict, or an empty dict if none."""
    +        return getattr(self.obj, '__pdoc__', {})
    +
    +    def _link_inheritance(self):
    +        # Inherited members are already in place since
    +        # `Class._fill_inheritance()` has been called from
    +        # `pdoc.fill_inheritance()`.
    +        # Now look for docstrings in the module's __pdoc__ override.
    +
    +        if self._is_inheritance_linked:
    +            # Prevent re-linking inheritance for modules which have already
    +            # had done so. Otherwise, this would raise "does not exist"
    +            # errors if `pdoc.link_inheritance()` is called multiple times.
    +            return
    +
    +        # Apply __pdoc__ overrides
    +        for name, docstring in self.__pdoc__.items():
    +            # In case of whitelisting with "True", there's nothing to do
    +            if docstring is True:
    +                continue
    +
    +            refname = f"{self.refname}.{name}"
    +            if docstring in (False, None):
    +                if docstring is None:
    +                    warn('Setting `__pdoc__[key] = None` is deprecated; '
    +                         'use `__pdoc__[key] = False` '
    +                         f'(key: {name!r}, module: {self.name!r}).')
    +
    +                if name in self._skipped_submodules:
    +                    continue
    +
    +                if (not name.endswith('.__init__') and
    +                        name not in self.doc and
    +                        refname not in self._context and
    +                        refname not in self._context.blacklisted):
    +                    warn(f'__pdoc__-overriden key {name!r} does not exist '
    +                         f'in module {self.name!r}')
    +
    +                obj = self.find_ident(name)
    +                cls = getattr(obj, 'cls', None)
    +                if cls:
    +                    del cls.doc[obj.name]
    +                self.doc.pop(name, None)
    +                self._context.pop(refname, None)
    +
    +                # Pop also all that startwith refname
    +                for key in list(self._context.keys()):
    +                    if key.startswith(refname + '.'):
    +                        del self._context[key]
    +
    +                continue
    +
    +            dobj = self.find_ident(refname)
    +            if isinstance(dobj, External):
    +                continue
    +            if not isinstance(docstring, str):
    +                raise ValueError('__pdoc__ dict values must be strings; '
    +                                 f'__pdoc__[{name!r}] is of type {type(docstring)}')
    +            dobj.docstring = inspect.cleandoc(docstring)
    +
    +        # Now after docstrings are set correctly, continue the
    +        # inheritance routine, marking members inherited or not
    +        for c in _filter_type(Class, self.doc):
    +            c._link_inheritance()
    +
    +        self._is_inheritance_linked = True
    +
    +    def text(self, **kwargs) -> str:
    +        """
    +        Returns the documentation for this module as plain text.
    +        """
    +        txt = _render_template('/text.mako', module=self, **kwargs)
    +        return re.sub("\n\n\n+", "\n\n", txt)
    +
    +    def html(self, minify=True, **kwargs) -> str:
    +        """
    +        Returns the documentation for this module as
    +        self-contained HTML.
    +
    +        If `minify` is `True`, the resulting HTML is minified.
    +
    +        For explanation of other arguments, see `pdoc.html()`.
    +
    +        `kwargs` is passed to the `mako` render function.
    +        """
    +        html = _render_template('/html.mako', module=self, **kwargs)
    +        if minify:
    +            from pdoc.html_helpers import minify_html
    +            html = minify_html(html)
    +        if not html.endswith('\n'):
    +            html = html + '\n'
    +        return html
    +
    +    @property
    +    def is_package(self) -> bool:
    +        """
    +        `True` if this module is a package.
    +
    +        Works by checking whether the module has a `__path__` attribute.
    +        """
    +        return hasattr(self.obj, "__path__")
    +
    +    @property
    +    def is_namespace(self) -> bool:
    +        """
    +        `True` if this module is a namespace package.
    +        """
    +        try:
    +            return self.obj.__spec__.origin in (None, 'namespace')  # None in Py3.7+
    +        except AttributeError:
    +            return False
    +
    +    def find_class(self, cls: type) -> Doc:
    +        """
    +        Given a Python `cls` object, try to find it in this module
    +        or in any of the exported identifiers of the submodules.
    +        """
    +        # XXX: Is this corrent? Does it always match
    +        # `Class.module.name + Class.qualname`?. Especially now?
    +        # If not, see what was here before.
    +        return self.find_ident(f'{cls.__module__ or _UNKNOWN_MODULE}.{cls.__qualname__}')
    +
    +    def find_ident(self, name: str) -> Doc:
    +        """
    +        Searches this module and **all** other public modules
    +        for an identifier with name `name` in its list of
    +        exported identifiers.
    +
    +        The documentation object corresponding to the identifier is
    +        returned. If one cannot be found, then an instance of
    +        `External` is returned populated with the given identifier.
    +        """
    +        _name = name.rstrip('()')  # Function specified with parentheses
     
    -            params.append(formatted)
    +        if _name.endswith('.__init__'):  # Ref to class' init is ref to class itself
    +            _name = _name[:-len('.__init__')]
     
    -        if pos_only:
    -            params.append("/")
    +        return (self.doc.get(_name) or
    +                self._context.get(_name) or
    +                self._context.get(f'{self.name}.{_name}') or
    +                External(name))
     
    -        return params
    +    def _filter_doc_objs(self, type: Type[T], sort=True) -> List[T]:
    +        result = _filter_type(type, self.doc)
    +        return sorted(result) if sort else result
     
    -    @staticmethod
    -    @lru_cache()
    -    def _signature_from_string(self):
    -        signature = None
    -        for expr, cleanup_docstring, filter in (
    -                # Full proper typed signature, such as one from pybind11
    -                (r'^{}\(.*\)(?: -> .*)?$', True, lambda s: s),
    -                # Human-readable, usage-like signature from some Python builtins
    -                # (e.g. `range` or `slice` or `itertools.repeat` or `numpy.arange`)
    -                (r'^{}\(.*\)(?= -|$)', False, lambda s: s.replace('[', '').replace(']', '')),
    -        ):
    -            strings = sorted(re.findall(expr.format(self.name),
    -                                        self.docstring, re.MULTILINE),
    -                             key=len, reverse=True)
    -            if strings:
    -                string = filter(strings[0])
    -                _locals, _globals = {}, {}
    -                _globals.update({'capsule': None})  # pybind11 capsule data type
    -                _globals.update(typing.__dict__)
    -                _globals.update(self.module.obj.__dict__)
    -                # Trim binding module basename from type annotations
    -                # See: https://github.com/pdoc3/pdoc/pull/148#discussion_r407114141
    -                module_basename = self.module.name.rsplit('.', maxsplit=1)[-1]
    -                if module_basename in string and module_basename not in _globals:
    -                    string = re.sub(fr'(?<!\.)\b{module_basename}\.\b', '', string)
    +    def variables(self, sort=True) -> List['Variable']:
    +        """
    +        Returns all documented module-level variables in the module,
    +        optionally sorted alphabetically, as a list of `pdoc.Variable`.
    +        """
    +        return self._filter_doc_objs(Variable, sort)
     
    -                try:
    -                    exec(f'def {string}: pass', _globals, _locals)
    -                except Exception:
    -                    continue
    -                signature = inspect.signature(_locals[self.name])
    -                if cleanup_docstring and len(strings) == 1:
    -                    # Remove signature from docstring variable
    -                    self.docstring = self.docstring.replace(strings[0], '')
    -                break
    -        return signature
    +    def classes(self, sort=True) -> List['Class']:
    +        """
    +        Returns all documented module-level classes in the module,
    +        optionally sorted alphabetically, as a list of `pdoc.Class`.
    +        """
    +        return self._filter_doc_objs(Class, sort)
     
    -    @property
    -    def refname(self) -> str:
    -        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    + def functions(self, sort=True) -> List['Function']: + """ + Returns all documented module-level functions in the module, + optionally sorted alphabetically, as a list of `pdoc.Function`. + """ + return self._filter_doc_objs(Function, sort) + + def submodules(self) -> List['Module']: + """ + Returns all documented sub-modules of the module sorted + alphabetically as a list of `pdoc.Module`. + """ + return self._filter_doc_objs(Module) + + def _url(self): + url = self.module.name.replace('.', '/') + if self.is_package: + return url + _URL_PACKAGE_SUFFIX + elif url.endswith('/index'): + return url + _URL_INDEX_MODULE_SUFFIX + return url + _URL_MODULE_SUFFIX
    -

    Ancestors

    - -

    Instance variables

    -
    -
    var cls
    -
    -

    The Class documentation object if the function is a method. -If not, this is None.

    -
    prop is_method : bool
    +
    prop is_namespace : bool
    -

    Whether this function is a normal bound method.

    -

    In particular, static and class methods have this set to False.

    +

    True if this module is a namespace package.

    Expand source code +Browse git
    @property
    -def is_method(self) -> bool:
    +def is_namespace(self) -> bool:
         """
    -    Whether this function is a normal bound method.
    -
    -    In particular, static and class methods have this set to False.
    +    `True` if this module is a namespace package.
         """
    -    assert self.cls
    -    return not Class._method_type(self.cls.obj, self.name)
    + try: + return self.obj.__spec__.origin in (None, 'namespace') # None in Py3.7+ + except AttributeError: + return False
    -
    -

    Methods

    -
    -
    -def funcdef(self) ‑> str -
    -
    -

    Generates the string of keywords used to define the function, -for example def or async def.

    -
    -
    -def params(self,
    *,
    annotate: bool = False,
    link: Callable[[Doc], str] | None = None) ‑> List[str]
    -
    -
    -

    Returns a list where each element is a nicely formatted -parameter of this function. This includes argument lists, -keyword arguments and default values, and it doesn't include any -optional arguments whose names begin with an underscore.

    -

    If annotate is True, the parameter strings include PEP 484 -type hint annotations.

    -
    -
    -def return_annotation(self, *, link=None) ‑> str -
    +
    prop is_package : bool
    -

    Formatted function return type annotation or empty string if none.

    -
    -
    -

    Inherited members

    - +

    True if this module is a package.

    +

    Works by checking whether the module has a __path__ attribute.

    +
    + +Expand source code +Browse git + +
    @property
    +def is_package(self) -> bool:
    +    """
    +    `True` if this module is a package.
    +
    +    Works by checking whether the module has a `__path__` attribute.
    +    """
    +    return hasattr(self.obj, "__path__")
    +
    -
    -class Module -(module: str | module,
    *,
    docfilter: Callable[[Doc], bool] | None = None,
    supermodule: ForwardRef('Module') | None = None,
    context: Context | None = None,
    skip_errors: bool = False)
    -
    +
    var supermodule
    -

    Representation of a module's documentation.

    -

    Creates a Module documentation object given the actual -module Python object.

    -

    docfilter is an optional predicate that controls which -sub-objects are documentated (see also: html()).

    -

    supermodule is the parent Module this module is -a submodule of.

    -

    context is an instance of Context. If None a -global context object will be used.

    -

    If skip_errors is True and an unimportable, erroneous -submodule is encountered, a warning will be issued instead -of raising an exception.

    +

    The parent Module this module is a submodule of, or None.

    Expand source code -Browse git +Browse git
    class Module(Doc):
         """
    @@ -1882,81 +4342,32 @@ 

    Inherited members

    """ Returns all documented module-level classes in the module, optionally sorted alphabetically, as a list of `pdoc.Class`. - """ - return self._filter_doc_objs(Class, sort) - - def functions(self, sort=True) -> List['Function']: - """ - Returns all documented module-level functions in the module, - optionally sorted alphabetically, as a list of `pdoc.Function`. - """ - return self._filter_doc_objs(Function, sort) - - def submodules(self) -> List['Module']: - """ - Returns all documented sub-modules of the module sorted - alphabetically as a list of `pdoc.Module`. - """ - return self._filter_doc_objs(Module) - - def _url(self): - url = self.module.name.replace('.', '/') - if self.is_package: - return url + _URL_PACKAGE_SUFFIX - elif url.endswith('/index'): - return url + _URL_INDEX_MODULE_SUFFIX - return url + _URL_MODULE_SUFFIX
    -
    -

    Ancestors

    - -

    Instance variables

    -
    -
    var doc
    -
    -

    A mapping from identifier name to a documentation object.

    -
    -
    prop is_namespace : bool
    -
    -

    True if this module is a namespace package.

    -
    - -Expand source code - -
    @property
    -def is_namespace(self) -> bool:
    -    """
    -    `True` if this module is a namespace package.
    -    """
    -    try:
    -        return self.obj.__spec__.origin in (None, 'namespace')  # None in Py3.7+
    -    except AttributeError:
    -        return False
    -
    -
    -
    prop is_package : bool
    -
    -

    True if this module is a package.

    -

    Works by checking whether the module has a __path__ attribute.

    -
    - -Expand source code - -
    @property
    -def is_package(self) -> bool:
    -    """
    -    `True` if this module is a package.
    +        """
    +        return self._filter_doc_objs(Class, sort)
     
    -    Works by checking whether the module has a `__path__` attribute.
    -    """
    -    return hasattr(self.obj, "__path__")
    + def functions(self, sort=True) -> List['Function']: + """ + Returns all documented module-level functions in the module, + optionally sorted alphabetically, as a list of `pdoc.Function`. + """ + return self._filter_doc_objs(Function, sort) + + def submodules(self) -> List['Module']: + """ + Returns all documented sub-modules of the module sorted + alphabetically as a list of `pdoc.Module`. + """ + return self._filter_doc_objs(Module) + + def _url(self): + url = self.module.name.replace('.', '/') + if self.is_package: + return url + _URL_PACKAGE_SUFFIX + elif url.endswith('/index'): + return url + _URL_INDEX_MODULE_SUFFIX + return url + _URL_MODULE_SUFFIX
    -
    var supermodule
    -
    -

    The parent Module this module is a submodule of, or None.

    -

    Methods

    @@ -1966,6 +4377,18 @@

    Methods

    Returns all documented module-level classes in the module, optionally sorted alphabetically, as a list of Class.

    +
    + +Expand source code +Browse git + +
    def classes(self, sort=True) -> List['Class']:
    +    """
    +    Returns all documented module-level classes in the module,
    +    optionally sorted alphabetically, as a list of `pdoc.Class`.
    +    """
    +    return self._filter_doc_objs(Class, sort)
    +
    def find_class(self, cls: type) ‑> Doc @@ -1973,6 +4396,21 @@

    Methods

    Given a Python cls object, try to find it in this module or in any of the exported identifiers of the submodules.

    +
    + +Expand source code +Browse git + +
    def find_class(self, cls: type) -> Doc:
    +    """
    +    Given a Python `cls` object, try to find it in this module
    +    or in any of the exported identifiers of the submodules.
    +    """
    +    # XXX: Is this corrent? Does it always match
    +    # `Class.module.name + Class.qualname`?. Especially now?
    +    # If not, see what was here before.
    +    return self.find_ident(f'{cls.__module__ or _UNKNOWN_MODULE}.{cls.__qualname__}')
    +
    def find_ident(self, name: str) ‑> Doc @@ -1984,6 +4422,31 @@

    Methods

    The documentation object corresponding to the identifier is returned. If one cannot be found, then an instance of External is returned populated with the given identifier.

    +
    + +Expand source code +Browse git + +
    def find_ident(self, name: str) -> Doc:
    +    """
    +    Searches this module and **all** other public modules
    +    for an identifier with name `name` in its list of
    +    exported identifiers.
    +
    +    The documentation object corresponding to the identifier is
    +    returned. If one cannot be found, then an instance of
    +    `External` is returned populated with the given identifier.
    +    """
    +    _name = name.rstrip('()')  # Function specified with parentheses
    +
    +    if _name.endswith('.__init__'):  # Ref to class' init is ref to class itself
    +        _name = _name[:-len('.__init__')]
    +
    +    return (self.doc.get(_name) or
    +            self._context.get(_name) or
    +            self._context.get(f'{self.name}.{_name}') or
    +            External(name))
    +
    def functions(self, sort=True) ‑> List[Function] @@ -1991,6 +4454,18 @@

    Methods

    Returns all documented module-level functions in the module, optionally sorted alphabetically, as a list of Function.

    +
    + +Expand source code +Browse git + +
    def functions(self, sort=True) -> List['Function']:
    +    """
    +    Returns all documented module-level functions in the module,
    +    optionally sorted alphabetically, as a list of `pdoc.Function`.
    +    """
    +    return self._filter_doc_objs(Function, sort)
    +
    def html(self, minify=True, **kwargs) ‑> str @@ -2001,6 +4476,30 @@

    Methods

    If minify is True, the resulting HTML is minified.

    For explanation of other arguments, see html().

    kwargs is passed to the mako render function.

    +
    + +Expand source code +Browse git + +
    def html(self, minify=True, **kwargs) -> str:
    +    """
    +    Returns the documentation for this module as
    +    self-contained HTML.
    +
    +    If `minify` is `True`, the resulting HTML is minified.
    +
    +    For explanation of other arguments, see `pdoc.html()`.
    +
    +    `kwargs` is passed to the `mako` render function.
    +    """
    +    html = _render_template('/html.mako', module=self, **kwargs)
    +    if minify:
    +        from pdoc.html_helpers import minify_html
    +        html = minify_html(html)
    +    if not html.endswith('\n'):
    +        html = html + '\n'
    +    return html
    +
    def submodules(self) ‑> List[Module] @@ -2008,12 +4507,36 @@

    Methods

    Returns all documented sub-modules of the module sorted alphabetically as a list of Module.

    +
    + +Expand source code +Browse git + +
    def submodules(self) -> List['Module']:
    +    """
    +    Returns all documented sub-modules of the module sorted
    +    alphabetically as a list of `pdoc.Module`.
    +    """
    +    return self._filter_doc_objs(Module)
    +
    def text(self, **kwargs) ‑> str

    Returns the documentation for this module as plain text.

    +
    + +Expand source code +Browse git + +
    def text(self, **kwargs) -> str:
    +    """
    +    Returns the documentation for this module as plain text.
    +    """
    +    txt = _render_template('/text.mako', module=self, **kwargs)
    +    return re.sub("\n\n\n+", "\n\n", txt)
    +
    def variables(self, sort=True) ‑> List[Variable] @@ -2021,6 +4544,18 @@

    Methods

    Returns all documented module-level variables in the module, optionally sorted alphabetically, as a list of Variable.

    +
    + +Expand source code +Browse git + +
    def variables(self, sort=True) -> List['Variable']:
    +    """
    +    Returns all documented module-level variables in the module,
    +    optionally sorted alphabetically, as a list of `pdoc.Variable`.
    +    """
    +    return self._filter_doc_objs(Variable, sort)
    +

    Inherited members

    @@ -2053,7 +4588,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Variable(Doc):
         """
    @@ -2114,16 +4649,178 @@ 

    Instance variables

    The Class object if this is a class or instance variable. If not (i.e. it is a global variable), this is None.

    +
    + +Expand source code +Browse git + +
    class Variable(Doc):
    +    """
    +    Representation of a variable's documentation. This includes
    +    module, class, and instance variables.
    +    """
    +    __slots__ = ('cls', 'instance_var', 'kind')
    +
    +    def __init__(self, name: str, module: Module, docstring, *,
    +                 obj=None, cls: Optional[Class] = None, instance_var: bool = False,
    +                 kind: Literal["prop", "var"] = 'var'):
    +        """
    +        Same as `pdoc.Doc`, except `cls` should be provided
    +        as a `pdoc.Class` object when this is a class or instance
    +        variable.
    +        """
    +        super().__init__(name, module, obj, docstring)
    +
    +        self.cls = cls
    +        """
    +        The `pdoc.Class` object if this is a class or instance
    +        variable. If not (i.e. it is a global variable), this is None.
    +        """
    +
    +        self.instance_var = instance_var
    +        """
    +        True if variable is some class' instance variable (as
    +        opposed to class variable).
    +        """
    +
    +        self.kind = kind
    +        """
    +        `prop` if variable is a dynamic property (has getter/setter or deleter),
    +        or `var` otherwise.
    +        """
    +
    +    @property
    +    def qualname(self) -> str:
    +        if self.cls:
    +            return f'{self.cls.qualname}.{self.name}'
    +        return self.name
    +
    +    @property
    +    def refname(self) -> str:
    +        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    +
    +    def type_annotation(self, *, link=None) -> str:
    +        """Formatted variable type annotation or empty string if none."""
    +        return Function.return_annotation(cast(Function, self), link=link)
    +
    var instance_var

    True if variable is some class' instance variable (as opposed to class variable).

    +
    + +Expand source code +Browse git + +
    class Variable(Doc):
    +    """
    +    Representation of a variable's documentation. This includes
    +    module, class, and instance variables.
    +    """
    +    __slots__ = ('cls', 'instance_var', 'kind')
    +
    +    def __init__(self, name: str, module: Module, docstring, *,
    +                 obj=None, cls: Optional[Class] = None, instance_var: bool = False,
    +                 kind: Literal["prop", "var"] = 'var'):
    +        """
    +        Same as `pdoc.Doc`, except `cls` should be provided
    +        as a `pdoc.Class` object when this is a class or instance
    +        variable.
    +        """
    +        super().__init__(name, module, obj, docstring)
    +
    +        self.cls = cls
    +        """
    +        The `pdoc.Class` object if this is a class or instance
    +        variable. If not (i.e. it is a global variable), this is None.
    +        """
    +
    +        self.instance_var = instance_var
    +        """
    +        True if variable is some class' instance variable (as
    +        opposed to class variable).
    +        """
    +
    +        self.kind = kind
    +        """
    +        `prop` if variable is a dynamic property (has getter/setter or deleter),
    +        or `var` otherwise.
    +        """
    +
    +    @property
    +    def qualname(self) -> str:
    +        if self.cls:
    +            return f'{self.cls.qualname}.{self.name}'
    +        return self.name
    +
    +    @property
    +    def refname(self) -> str:
    +        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    +
    +    def type_annotation(self, *, link=None) -> str:
    +        """Formatted variable type annotation or empty string if none."""
    +        return Function.return_annotation(cast(Function, self), link=link)
    +
    var kind

    prop if variable is a dynamic property (has getter/setter or deleter), or var otherwise.

    +
    + +Expand source code +Browse git + +
    class Variable(Doc):
    +    """
    +    Representation of a variable's documentation. This includes
    +    module, class, and instance variables.
    +    """
    +    __slots__ = ('cls', 'instance_var', 'kind')
    +
    +    def __init__(self, name: str, module: Module, docstring, *,
    +                 obj=None, cls: Optional[Class] = None, instance_var: bool = False,
    +                 kind: Literal["prop", "var"] = 'var'):
    +        """
    +        Same as `pdoc.Doc`, except `cls` should be provided
    +        as a `pdoc.Class` object when this is a class or instance
    +        variable.
    +        """
    +        super().__init__(name, module, obj, docstring)
    +
    +        self.cls = cls
    +        """
    +        The `pdoc.Class` object if this is a class or instance
    +        variable. If not (i.e. it is a global variable), this is None.
    +        """
    +
    +        self.instance_var = instance_var
    +        """
    +        True if variable is some class' instance variable (as
    +        opposed to class variable).
    +        """
    +
    +        self.kind = kind
    +        """
    +        `prop` if variable is a dynamic property (has getter/setter or deleter),
    +        or `var` otherwise.
    +        """
    +
    +    @property
    +    def qualname(self) -> str:
    +        if self.cls:
    +            return f'{self.cls.qualname}.{self.name}'
    +        return self.name
    +
    +    @property
    +    def refname(self) -> str:
    +        return f'{self.cls.refname if self.cls else self.module.refname}.{self.name}'
    +
    +    def type_annotation(self, *, link=None) -> str:
    +        """Formatted variable type annotation or empty string if none."""
    +        return Function.return_annotation(cast(Function, self), link=link)
    +

    Methods

    @@ -2133,6 +4830,15 @@

    Methods

    Formatted variable type annotation or empty string if none.

    +
    + +Expand source code +Browse git + +
    def type_annotation(self, *, link=None) -> str:
    +    """Formatted variable type annotation or empty string if none."""
    +    return Function.return_annotation(cast(Function, self), link=link)
    +

    Inherited members

    @@ -2292,7 +4998,7 @@

    Variable

    diff --git a/doc/pdoc/test/example_pkg/index.html b/doc/pdoc/test/example_pkg/index.html index 8689cdfc..1caab2eb 100644 --- a/doc/pdoc/test/example_pkg/index.html +++ b/doc/pdoc/test/example_pkg/index.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg API documentation @@ -108,12 +108,60 @@

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -195,6 +243,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -206,12 +317,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -281,12 +420,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -330,6 +554,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -344,7 +610,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -371,18 +637,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -397,7 +687,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -508,6 +798,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -522,6 +821,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -535,6 +835,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -548,6 +849,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -563,12 +865,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -592,7 +910,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -638,7 +956,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -678,7 +996,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -916,6 +1234,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -997,6 +1355,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1066,6 +1487,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1109,6 +1607,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1120,7 +1660,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1151,7 +1691,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1169,7 +1709,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1287,7 +1827,7 @@ 

    -

    Generated by pdoc 0.11.3.

    +

    Generated by pdoc 0.11.4.

    diff --git a/doc/pdoc/test/example_pkg/index.m.html b/doc/pdoc/test/example_pkg/index.m.html index d18ba23b..0604edf3 100644 --- a/doc/pdoc/test/example_pkg/index.m.html +++ b/doc/pdoc/test/example_pkg/index.m.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg.index API documentation @@ -89,12 +89,60 @@

    Example

    ... Exception: something went wrong

    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -176,6 +224,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -187,12 +298,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -262,12 +401,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -311,6 +535,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -325,7 +591,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -352,18 +618,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -378,7 +668,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -489,6 +779,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -503,6 +802,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -516,6 +816,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -529,6 +830,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -544,12 +846,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -573,7 +891,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -619,7 +937,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -659,7 +977,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -897,6 +1215,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -978,6 +1336,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1047,6 +1468,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1090,6 +1588,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1101,7 +1641,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1132,7 +1672,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1150,7 +1690,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1260,7 +1800,7 @@ 

    -

    Generated by pdoc 0.11.3.

    +

    Generated by pdoc 0.11.4.

    diff --git a/doc/pdoc/test/example_pkg/module.html b/doc/pdoc/test/example_pkg/module.html index b5da0489..d721c1e2 100644 --- a/doc/pdoc/test/example_pkg/module.html +++ b/doc/pdoc/test/example_pkg/module.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg.module API documentation @@ -89,12 +89,60 @@

    Example

    ... Exception: something went wrong

    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -176,6 +224,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -187,12 +298,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -262,12 +401,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -311,6 +535,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -325,7 +591,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -352,18 +618,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -378,7 +668,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -489,6 +779,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -503,6 +802,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -516,6 +816,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -529,6 +830,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -544,12 +846,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -573,7 +891,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -619,7 +937,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -659,7 +977,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -897,6 +1215,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -978,6 +1336,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1047,6 +1468,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1090,6 +1588,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1101,7 +1641,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1132,7 +1672,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1150,7 +1690,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1260,7 +1800,7 @@ 

    -

    Generated by pdoc 0.11.3.

    +

    Generated by pdoc 0.11.4.

    diff --git a/doc/pdoc/test/example_pkg/subpkg/index.html b/doc/pdoc/test/example_pkg/subpkg/index.html index 5ea3e282..ebb0b3e8 100644 --- a/doc/pdoc/test/example_pkg/subpkg/index.html +++ b/doc/pdoc/test/example_pkg/subpkg/index.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg.subpkg API documentation @@ -89,12 +89,60 @@

    Example

    ... Exception: something went wrong

    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -176,6 +224,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -187,12 +298,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -262,12 +401,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -311,6 +535,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -325,7 +591,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -352,18 +618,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -378,7 +668,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -489,6 +779,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -503,6 +802,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -516,6 +816,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -529,6 +830,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -544,12 +846,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -573,7 +891,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -619,7 +937,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -659,7 +977,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -897,6 +1215,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -978,6 +1336,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1047,6 +1468,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1090,6 +1588,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1101,7 +1641,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1132,7 +1672,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1150,7 +1690,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1260,7 +1800,7 @@ 

    -

    Generated by pdoc 0.11.3.

    +

    Generated by pdoc 0.11.4.

    diff --git a/doc/pdoc/test/example_pkg/subpkg2/index.html b/doc/pdoc/test/example_pkg/subpkg2/index.html index e28dc714..e3029a3c 100644 --- a/doc/pdoc/test/example_pkg/subpkg2/index.html +++ b/doc/pdoc/test/example_pkg/subpkg2/index.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg.subpkg2 API documentation @@ -96,12 +96,60 @@

    Example

    ... Exception: something went wrong

    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -183,6 +231,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -194,12 +305,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -269,12 +408,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -318,6 +542,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -332,7 +598,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -359,18 +625,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -385,7 +675,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -496,6 +786,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -510,6 +809,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -523,6 +823,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -536,6 +837,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -551,12 +853,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -580,7 +898,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -626,7 +944,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -666,7 +984,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -904,6 +1222,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -985,6 +1343,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1054,6 +1475,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1097,6 +1595,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1108,7 +1648,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1139,7 +1679,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1157,7 +1697,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1272,7 +1812,7 @@ 

    diff --git a/doc/pdoc/test/example_pkg/subpkg2/module.html b/doc/pdoc/test/example_pkg/subpkg2/module.html index 922cf8ed..34ac05ce 100644 --- a/doc/pdoc/test/example_pkg/subpkg2/module.html +++ b/doc/pdoc/test/example_pkg/subpkg2/module.html @@ -3,7 +3,7 @@ - + pdoc.test.example_pkg.subpkg2.module API documentation @@ -89,12 +89,60 @@

    Example

    ... Exception: something went wrong

    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def foo(env=os.environ)

    Doesn't leak environ

    +
    + +Expand source code +Browse git + +
    def foo(env=os.environ):
    +    """Doesn't leak environ"""
    +
    def google(self) @@ -176,6 +224,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def latex_math() @@ -187,12 +298,40 @@

    Todos

    $\mathcal{O}(N)$

    Escaping \$ should work in math like $X = \$3.25$ once it is implemented.

    [ v_t \frac{1}{2} j_i + [a] < 3 ]

    +
    + +Expand source code +Browse git + +
    def latex_math():
    +    """
    +    Inline equation: \\( v_t *\\frac{1}{2}* j_i + [a] < 3 \\).
    +
    +    Block equation: \\[ v_t *\\frac{1}{2}* j_i + [a] < 3 \\]
    +
    +    Block equation: $$ v_t *\\frac{1}{2}* j_i + [a] < 3 $$
    +
    +    $\\mathcal{O}(N)$
    +
    +    Escaping \\$ should work in math like $X = \\$3.25$ once it is implemented.
    +
    +    ..math::
    +        v_t *\\frac{1}{2}* j_i + [a] < 3
    +    """
    +
    def non_callable_routine(x)
    +
    + +Expand source code +Browse git + +
    non_callable_routine = staticmethod(lambda x: 2)  # Not interpreted as Function; skipped
    +
    def numpy(self) @@ -262,12 +401,97 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def object_as_arg_default(*args, a=<object object>, **kwargs)

    Html-encodes angle brackets in params

    +
    + +Expand source code +Browse git + +
    def object_as_arg_default(*args, a=object(), **kwargs):
    +    """Html-encodes angle brackets in params"""
    +
    def reST_directives(self) @@ -311,6 +535,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -325,7 +591,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class A:
         """`A` is base class for `example_pkg.B`."""  # Test refname link
    @@ -352,18 +618,42 @@ 

    Methods

    A.inherited docstring

    +
    + +Expand source code +Browse git + +
    def inherited(self):  # Inherited in B
    +    """A.inherited docstring"""
    +
    def overridden(self)

    A.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    """A.overridden docstring"""
    +
    def overridden_same_docstring(self)

    A.overridden_same_docstring docstring

    +
    + +Expand source code +Browse git + +
    def overridden_same_docstring(self):
    +    """A.overridden_same_docstring docstring"""
    +
    @@ -378,7 +668,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class B(A, int):
         """
    @@ -489,6 +779,15 @@ 

    Static methods

    B.static docstring

    +
    + +Expand source code +Browse git + +
    @staticmethod
    +def static(x):
    +    """B.static docstring"""
    +

    Instance variables

    @@ -503,6 +802,7 @@

    Instance variables

    Expand source code +Browse git
    @property
     def p(self):
    @@ -516,6 +816,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -529,6 +830,7 @@ 

    Instance variables

    Expand source code +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -544,12 +846,28 @@ 

    Methods

    B.f docstring

    +
    + +Expand source code +Browse git + +
    def f(self, a: int, b: int = 1, *args, c: str = 'c', **kwargs):
    +    """B.f docstring"""
    +
    def overridden(self)

    B.overridden docstring

    +
    + +Expand source code +Browse git + +
    def overridden(self):
    +    pass
    +

    Inherited members

    @@ -573,7 +891,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class C(B): pass  # noqa: E701, E302
    @@ -619,7 +937,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class D(C): pass  # noqa: E701, E302
    @@ -659,7 +977,7 @@

    Inherited members

    Expand source code -Browse git +Browse git
    class Docformats:
         def numpy(self):
    @@ -897,6 +1215,46 @@ 

    Example

    ... Exception: something went wrong
    +
    + +Expand source code +Browse git + +
    def doctests(self):
    +    """
    +    Need an intro paragrapgh.
    +
    +        >>> Then code is indented one level
    +        line1
    +        line2
    +
    +    Alternatively
    +    ```
    +    >>> doctest
    +    fenced code works
    +    always
    +    ```
    +
    +    Examples:
    +        >>> nbytes(100)
    +        '100.0 bytes'
    +        line2
    +
    +        some text
    +
    +    some text
    +
    +    >>> another doctest
    +    line1
    +    line2
    +
    +    Example:
    +        >>> f()
    +        Traceback (most recent call last):
    +            ...
    +        Exception: something went wrong
    +    """
    +
    def google(self) @@ -978,6 +1336,69 @@

    Todos

    • For module TODOs
    +
    + +Expand source code +Browse git + +
    def google(self):
    +    """
    +    Summary line.
    +    Nomatch:
    +
    +    Args:
    +        arg1 (str, optional): Text1
    +        arg2 (List[str], optional, default=10): Text2
    +        data (array-like object): foo
    +
    +    Args:
    +      arg1 (int): Description of arg1
    +      arg2 (str or int): Description of arg2
    +      arg3 (str | None): Description of arg3
    +      test_sequence: 2-dim numpy array of real numbers, size: N * D
    +        - the test observation sequence.
    +
    +            test_sequence =
    +            code
    +
    +        Continue.
    +      *args: passed around
    +
    +    Returns:
    +        issue_10: description didn't work across multiple lines
    +            if only a single item was listed. `inspect.cleandoc()`
    +            somehow stripped the required extra indentation.
    +
    +    Returns:
    +        A very special number
    +        which is the answer of everything.
    +
    +    Returns:
    +        Dict[int, pdoc.Doc]: Description.
    +
    +    Returns:
    +        int | str: Description.
    +
    +    Raises:
    +        AttributeError: The ``Raises`` section is a list of all exceptions
    +            that are relevant to the interface.
    +
    +            and a third line.
    +        ValueError: If `arg2` is equal to `arg1`.
    +
    +    Test a title without a blank line before it.
    +    Args:
    +        A: a
    +
    +    Examples:
    +      Examples in doctest format.
    +
    +      >>> a = [1,2,3]
    +
    +    Todos:
    +        * For module TODOs
    +    """
    +
    def numpy(self) @@ -1047,6 +1468,83 @@

    Notes

    Foo bar.

    H3 Title

    Foo bar.

    +
    + +Expand source code +Browse git + +
    def numpy(self):
    +    """
    +    Summary line.
    +
    +    **Documentation**: https://pdoc3.github.io/pdoc/doc/pdoc/
    +    **Source Code**: https://github.com/pdoc3/
    +
    +    Parameters
    +    ----------
    +    x1, x2 : array_like
    +        Input arrays,
    +        description of `x1`, `x2`.
    +
    +        .. versionadded:: 1.5.0
    +    x : { NoneType, 'B', 'C' }, optional
    +    n : int or list of int
    +        Description of num
    +    *args, **kwargs
    +        Passed on.
    +    complex : Union[Set[pdoc.Doc, Function], pdoc]
    +        The `List[Doc]`s of the new signal.
    +
    +    Returns
    +    -------
    +    output : pdoc.Doc
    +        The output array
    +    List[pdoc.Doc]
    +        The output array
    +    foo
    +
    +    Raises
    +    ------
    +    TypeError
    +        When something.
    +
    +    Raises
    +    ------
    +    TypeError
    +
    +    Returns
    +    -------
    +    None.
    +
    +    Invalid
    +    -------
    +    no match
    +
    +    See Also
    +    --------
    +    fromstring, loadtxt
    +
    +    See Also
    +    --------
    +    pdoc.text : Function a with its description.
    +    scipy.random.norm : Random variates, PDFs, etc.
    +    pdoc.Doc : A class description that
    +               spans several lines.
    +
    +    Examples
    +    --------
    +    >>> doctest
    +    ...
    +
    +    Notes
    +    -----
    +    Foo bar.
    +
    +    ### H3 Title
    +
    +    Foo bar.
    +    """
    +
    def reST_directives(self) @@ -1090,6 +1588,48 @@

    H3 Title

    Caution

    Don't touch this!

    +
    + +Expand source code +Browse git + +
    def reST_directives(self):
    +    """
    +    .. todo::
    +
    +       Create something.
    +
    +    .. admonition:: Example
    +
    +       Image shows something.
    +
    +       .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +       .. note::
    +          Can only nest admonitions two levels.
    +
    +    .. image:: https://www.debian.org/logos/openlogo-nd-100.png
    +
    +    Now you know.
    +
    +    .. warning::
    +
    +        Some warning
    +        lines.
    +
    +    * Describe some func in a list
    +      across multiple lines:
    +
    +        .. deprecated:: 3.1
    +          Use `spam` instead.
    +
    +        .. versionadded:: 2.5
    +         The *spam* parameter.
    +
    +    .. caution::
    +        Don't touch this!
    +    """
    +
    @@ -1101,7 +1641,7 @@

    H3 Title

    Expand source code -Browse git +Browse git
    class HasMockAttributes:
         """
    @@ -1132,7 +1672,7 @@ 

    Class variables

    Expand source code -Browse git +Browse git
    class Location(namedtuple('Location', 'lat lon')):
         """Geo-location, GPS position."""
    @@ -1150,7 +1690,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    def __get__(self, instance, instance_type=None):
         if instance is not None:
    @@ -1260,7 +1800,7 @@ 

    -

    Generated by pdoc 0.11.3.

    +

    Generated by pdoc 0.11.4.

    diff --git a/doc/pdoc/test/index.html b/doc/pdoc/test/index.html index 92a00e5a..b6a3e7b1 100644 --- a/doc/pdoc/test/index.html +++ b/doc/pdoc/test/index.html @@ -3,7 +3,7 @@ - + pdoc.test API documentation @@ -55,36 +55,113 @@

    Functions

    +
    + +Expand source code +Browse git + +
    @contextmanager
    +def chdir(path):
    +    old = os.getcwd()
    +    try:
    +        os.chdir(path)
    +        yield
    +    finally:
    +        os.chdir(old)
    +
    def ignore_warnings(func)
    +
    + +Expand source code +Browse git + +
    def ignore_warnings(func):
    +    @wraps(func)
    +    def wrapper(*args, **kwargs):
    +        with warnings.catch_warnings():
    +            warnings.simplefilter('ignore')
    +            func(*args, **kwargs)
    +    return wrapper
    +
    def redirect_streams()
    +
    + +Expand source code +Browse git + +
    @contextmanager
    +def redirect_streams():
    +    stdout, stderr = StringIO(), StringIO()
    +    with redirect_stderr(stderr), redirect_stdout(stdout):
    +        yield stdout, stderr
    +
    def run(*args, **kwargs) ‑> int
    +
    + +Expand source code +Browse git + +
    def run(*args, **kwargs) -> int:
    +    params = (('--' + key.replace('_', '-'), value)
    +              for key, value in kwargs.items())
    +    params = list(filter(None, chain.from_iterable(params)))  # type: ignore
    +    _args = cli.parser.parse_args([*params, *args])           # type: ignore
    +    try:
    +        cli.main(_args)
    +        return 0
    +    except SystemExit as e:
    +        return bool(e.code)
    +
    def run_html(*args, **kwargs)
    +
    + +Expand source code +Browse git + +
    @contextmanager
    +def run_html(*args, **kwargs):
    +    with temp_dir() as path, \
    +            redirect_streams():
    +        run(*args, html=None, output_dir=path, **kwargs)
    +        with chdir(path):
    +            yield
    +
    def temp_dir()
    +
    + +Expand source code +Browse git + +
    @contextmanager
    +def temp_dir():
    +    with TemporaryDirectory(prefix='pdoc-test-') as path:
    +        yield path
    +
    @@ -103,7 +180,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class ApiTest(unittest.TestCase):
         """
    @@ -826,222 +903,1113 @@ 

    Methods

    Hook method for setting up the test fixture before exercising it.

    +
    + +Expand source code +Browse git + +
    def setUp(self):
    +    pdoc.reset()
    +
    def test_Class_docstring(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_Class_docstring(self):
    +    class A:
    +        """foo"""
    +
    +    class B:
    +        def __init__(self):
    +            """foo"""
    +
    +    class C:
    +        """foo"""
    +        def __init__(self):
    +            """bar"""
    +
    +    class D(C):
    +        """baz"""
    +
    +    class E(C):
    +        def __init__(self):
    +            """baz"""
    +
    +    class F(typing.Generic[T]):
    +        """baz"""
    +        def __init__(self):
    +            """bar"""
    +
    +    class G(F[int]):
    +        """foo"""
    +
    +    mod = DUMMY_PDOC_MODULE
    +    self.assertEqual(pdoc.Class('A', mod, A).docstring, """foo""")
    +    self.assertEqual(pdoc.Class('B', mod, B).docstring, """foo""")
    +    self.assertEqual(pdoc.Class('C', mod, C).docstring, """foo\n\nbar""")
    +    self.assertEqual(pdoc.Class('D', mod, D).docstring, """baz\n\nbar""")
    +    self.assertEqual(pdoc.Class('E', mod, E).docstring, """foo\n\nbaz""")
    +    self.assertEqual(pdoc.Class('F', mod, F).docstring, """baz\n\nbar""")
    +    self.assertEqual(pdoc.Class('G', mod, G).docstring, """foo\n\nbar""")
    +
    def test_Class_params(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_Class_params(self):
    +    class C:
    +        def __init__(self, x):
    +            pass
    +
    +    mod = DUMMY_PDOC_MODULE
    +    self.assertEqual(pdoc.Class('C', mod, C).params(), ['x'])
    +    with patch.dict(mod.obj.__pdoc__, {'C.__init__': False}):
    +        self.assertEqual(pdoc.Class('C', mod, C).params(), [])
    +
    +    # test case for https://github.com/pdoc3/pdoc/issues/124
    +    class C2:
    +        __signature__ = inspect.signature(lambda a, b, c=None, *, d=1, e: None)
    +
    +    self.assertEqual(pdoc.Class('C2', mod, C2).params(), ['a', 'b', 'c=None', '*', 'd=1', 'e'])
    +
    +    class ClassWithNew:
    +        def __new__(self, arg):
    +            pass
    +
    +    class G(ClassWithNew):
    +        def __init__(self, a, b, c=100):
    +            pass
    +
    +    self.assertEqual(pdoc.Class('G', mod, G).params(), ['a', 'b', 'c=100'])
    +
    +    class G2(ClassWithNew):
    +        pass
    +
    +    self.assertEqual(pdoc.Class('G2', mod, G2).params(), ['arg'])
    +
    def test_Function_params(self)
    +
    + +Expand source code +Browse git + +
    def test_Function_params(self):
    +    mod = PDOC_PDOC_MODULE
    +    func = pdoc.Function('f', mod,
    +                         lambda a, _a, _b=None: None)
    +    self.assertEqual(func.params(), ['a', '_a'])
    +
    +    func = pdoc.Function('f', mod,
    +                         lambda _ok, a, _a, *args, _b=None, c=None, _d=None: None)
    +    self.assertEqual(func.params(), ['_ok', 'a', '_a', '*args', 'c=None'])
    +
    +    func = pdoc.Function('f', mod,
    +                         lambda a, b, *, _c=1: None)
    +    self.assertEqual(func.params(), ['a', 'b'])
    +
    +    func = pdoc.Function('f', mod,
    +                         lambda a, *, b, c: None)
    +    self.assertEqual(func.params(), ['a', '*', 'b', 'c'])
    +
    +    func = pdoc.Function('f', mod,
    +                         lambda a=os.environ, b=sys.stdout: None)
    +    self.assertEqual(func.params(), ['a=os.environ', 'b=sys.stdout'])
    +
    +    class Foo(enum.Enum):
    +        a, b = 1, 2
    +    func = pdoc.Function('f', mod, lambda a=Foo.a: None)
    +    self.assertEqual(func.params(), ['a=Foo.a'])
    +
    +    func = pdoc.Function('f', mod, lambda a=object(): None)
    +    self.assertEqual(func.params(), ['a=<object object>'])
    +
    +    func = pdoc.Function('f', mod, lambda a=object(): None)
    +    self.assertEqual(func.params(link=lambda x: ''), ['a=&lt;object object&gt;'])
    +
    +    # typed
    +    def f(a: int, *b, c: typing.List[pdoc.Doc] = []): pass
    +    func = pdoc.Function('f', mod, f)
    +    self.assertEqual(func.params(), ['a', '*b', "c=[]"])
    +    self.assertEqual(func.params(annotate=True),
    +                     ['a:\N{NBSP}int', '*b', "c:\N{NBSP}List[pdoc.Doc]\N{NBSP}=\N{NBSP}[]"])
    +
    +    # typed, linked
    +    def link(dobj):
    +        return f'<a href="{dobj.url(relative_to=mod)}">{dobj.qualname}</a>'
    +
    +    self.assertEqual(func.params(annotate=True, link=link),
    +                     ['a:\N{NBSP}int', '*b',
    +                      "c:\N{NBSP}List[<a href=\"#pdoc.Doc\">Doc</a>]\N{NBSP}=\N{NBSP}[]"])
    +
    +    # typed, linked, GH-311
    +    def f(a: typing.Dict[str, pdoc.Doc]): pass
    +
    +    func = pdoc.Function('f', mod, f)
    +    self.assertEqual(func.params(annotate=True, link=link),
    +                     ["a:\N{NBSP}Dict[str,\N{NBSP}<a href=\"#pdoc.Doc\">Doc</a>]"])
    +
    +    # shadowed name
    +    def f(pdoc: int): pass
    +    func = pdoc.Function('f', mod, f)
    +    self.assertEqual(func.params(annotate=True, link=link), ['pdoc:\N{NBSP}int'])
    +
    +    def bug130_str_annotation(a: "str"):
    +        return
    +
    +    self.assertEqual(pdoc.Function('bug130', mod, bug130_str_annotation).params(annotate=True),
    +                     ['a:\N{NBSP}str'])
    +
    +    # typed, NewType
    +    CustomType = typing.NewType('CustomType', bool)
    +
    +    def bug253_newtype_annotation(a: CustomType):
    +        return
    +
    +    expected = CustomType.__name__
    +    if sys.version_info > (3, 10):
    +        expected = f'{__name__}.{CustomType.__name__}'
    +
    +    self.assertEqual(
    +        pdoc.Function('bug253', mod, bug253_newtype_annotation).params(annotate=True),
    +        [f'a:\N{NBSP}{expected}'])
    +
    +    # typing.Callable bug
    +    def f(a: typing.Callable):
    +        return
    +
    +    self.assertEqual(
    +        pdoc.Function('f', mod, f).params(annotate=True),
    +        ['a:\N{NBSP}Callable'])
    +
    +    # builtin callables with signatures in docstrings
    +    from itertools import repeat
    +    self.assertEqual(pdoc.Function('repeat', mod, repeat).params(), ['object', 'times'])
    +    self.assertEqual(pdoc.Function('slice', mod, slice).params(), ['start', 'stop', 'step'])
    +
    +    class get_sample(repeat):
    +        """ get_sample(self: int, pos: int) -> Tuple[int, float] """
    +    self.assertEqual(pdoc.Function('get_sample', mod, get_sample).params(annotate=True),
    +                     ['self:\xa0int', 'pos:\xa0int'])
    +    self.assertEqual(pdoc.Function('get_sample', mod, get_sample).return_annotation(),
    +                     'Tuple[int,\xa0float]')
    +
    def test_Function_return_annotation(self)
    +
    + +Expand source code +Browse git + +
    def test_Function_return_annotation(self):
    +    def f() -> typing.List[typing.Union[str, pdoc.Doc]]: return []
    +    func = pdoc.Function('f', DUMMY_PDOC_MODULE, f)
    +    self.assertEqual(func.return_annotation(), 'List[str\N{NBSP}|\N{NBSP}pdoc.Doc]')
    +
    def test_Module_find_class(self)
    +
    + +Expand source code +Browse git + +
    def test_Module_find_class(self):
    +    class A:
    +        pass
    +
    +    mod = PDOC_PDOC_MODULE
    +    self.assertIsInstance(mod.find_class(pdoc.Doc), pdoc.Class)
    +    self.assertIsInstance(mod.find_class(A), pdoc.External)
    +
    def test_Variable_type_annotation(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_Variable_type_annotation(self):
    +    class Foobar:
    +        @property
    +        def prop(self) -> typing.Optional[int]:
    +            pass
    +
    +    mod = DUMMY_PDOC_MODULE
    +    cls = pdoc.Class('Foobar', mod, Foobar)
    +    self.assertEqual(cls.doc['prop'].type_annotation(), 'int\N{NBSP}|\N{NBSP}None')
    +
    def test_Variable_type_annotation_py36plus(self)
    +
    + +Expand source code +Browse git + +
        @ignore_warnings
    +    def test_Variable_type_annotation_py36plus(self):
    +        with temp_dir() as path:
    +            filename = os.path.join(path, 'module36syntax.py')
    +            with open(filename, 'w') as f:
    +                f.write('''
    +from typing import overload
    +
    +var: str = 'x'
    +"""dummy"""
    +
    +class Foo:
    +    var: int = 3
    +    """dummy"""
    +
    +    @overload
    +    def __init__(self, var2: float):
    +        pass
    +
    +    def __init__(self, var2):
    +        self.var2: float = float(var2)
    +        """dummy2"""
    +                ''')
    +            mod = pdoc.Module(pdoc.import_module(filename))
    +            self.assertEqual(mod.doc['var'].type_annotation(), 'str')
    +            self.assertEqual(mod.doc['Foo'].doc['var'].type_annotation(), 'int')
    +            self.assertIsInstance(mod.doc['Foo'].doc['var2'], pdoc.Variable)
    +            self.assertEqual(mod.doc['Foo'].doc['var2'].type_annotation(), '')  # Won't fix
    +            self.assertEqual(mod.doc['Foo'].doc['var2'].docstring, 'dummy2')
    +
    +            self.assertIn('var: str', mod.text())
    +            self.assertIn('var: int', mod.text())
    +
    def test__all__(self)
    +
    + +Expand source code +Browse git + +
    def test__all__(self):
    +    module = pdoc.import_module(EXAMPLE_MODULE + '.index')
    +    with patch.object(module, '__all__', ['B'], create=True):
    +        mod = pdoc.Module(module)
    +        with self.assertWarns(UserWarning):  # Only B is used but __pdoc__ contains others
    +            pdoc.link_inheritance()
    +        self.assertEqual(list(mod.doc.keys()), ['B'])
    +
    def test__pdoc__dict(self)
    +
    + +Expand source code +Browse git + +
    def test__pdoc__dict(self):
    +    module = pdoc.import_module(EXAMPLE_MODULE)
    +    with patch.object(module, '__pdoc__', {'B': False}):
    +        pdoc.reset()
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('A', mod.doc)
    +        self.assertNotIn('B', mod.doc)
    +
    +    with patch.object(module, '__pdoc__', {'B.f': False}):
    +        pdoc.reset()
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('B', mod.doc)
    +        self.assertNotIn('f', mod.doc['B'].doc)
    +        self.assertIsInstance(mod.find_ident('B.f'), pdoc.External)
    +
    +    # GH-125: https://github.com/pdoc3/pdoc/issues/125
    +    with patch.object(module, '__pdoc__', {'B.inherited': False}):
    +        pdoc.reset()
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertNotIn('inherited', mod.doc['B'].doc)
    +
    +    # Ensure "overridden key doesn't exist" warning is raised
    +    with patch.object(module, '__pdoc__', {'xxx': False}):
    +        pdoc.reset()
    +        mod = pdoc.Module(module)
    +        with self.assertWarns(UserWarning) as cm:
    +            pdoc.link_inheritance()
    +        self.assertIn("'xxx' does not exist", cm.warning.args[0])
    +
    +    # GH-99: https://github.com/pdoc3/pdoc/issues/99
    +    module = pdoc.import_module(EXAMPLE_MODULE + '._exclude_dir')
    +    with patch.object(module, '__pdoc__', {'downloaded_modules': False}, create=True):
    +        pdoc.reset()
    +        mod = pdoc.Module(module)
    +        # GH-206: https://github.com/pdoc3/pdoc/issues/206
    +        with warnings.catch_warnings(record=True) as cm:
    +            pdoc.link_inheritance()
    +        self.assertEqual(cm, [])
    +        self.assertNotIn('downloaded_modules', mod.doc)
    +
    def test__pdoc__invalid_value(self)
    +
    + +Expand source code +Browse git + +
    def test__pdoc__invalid_value(self):
    +    module = pdoc.import_module(EXAMPLE_MODULE)
    +    with patch.object(module, '__pdoc__', {'B': 1}), \
    +            self.assertRaises(ValueError):
    +        pdoc.Module(module)
    +        pdoc.link_inheritance()
    +
    def test__pdoc__whitelist(self)
    +
    + +Expand source code +Browse git + +
    def test__pdoc__whitelist(self):
    +    module = pdoc.import_module(EXAMPLE_MODULE)
    +    mod = pdoc.Module(module)
    +    pdoc.link_inheritance()
    +    self.assertNotIn('__call__', mod.doc['A'].doc)
    +    self.assertNotIn('_private_function', mod.doc)
    +
    +    # Override docstring string
    +    docstring = "Overwrite private function doc"
    +    with patch.object(module, '__pdoc__', {'A.__call__': docstring}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertEqual(mod.doc['A'].doc['__call__'].docstring, docstring)
    +
    +    # Module-relative
    +    with patch.object(module, '__pdoc__', {'_private_function': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('Private function', mod.doc['_private_function'].docstring)
    +        self.assertNotIn('_private_function', mod.doc["subpkg"].doc)
    +
    +    # Defined in example_pkg, referring to a member of its submodule
    +    with patch.object(module, '__pdoc__', {'subpkg.A.__call__': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('A.__call__', mod.doc['subpkg'].doc['A'].doc['__call__'].docstring)
    +
    +    # Using full refname
    +    with patch.object(module, '__pdoc__', {'example_pkg.subpkg.A.__call__': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('A.__call__', mod.doc['subpkg'].doc['A'].doc['__call__'].docstring)
    +
    +    # Entire module, absolute refname
    +    with patch.object(module, '__pdoc__', {'example_pkg._private': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('module', mod.doc['_private'].doc)
    +        self.assertNotIn('_private', mod.doc['_private'].doc)
    +        self.assertNotIn('__call__', mod.doc['_private'].doc['module'].doc)
    +
    +    # Entire module, relative
    +    with patch.object(module, '__pdoc__', {'_private': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('_private', mod.doc)
    +        self.assertNotIn('_private', mod.doc['_private'].doc)
    +        self.assertNotIn('__call__', mod.doc['_private'].doc['module'].doc)
    +
    +    # Private instance variables
    +    with patch.object(module, '__pdoc__', {'B._private_instance_var': True}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertIn('should be private', mod.doc['B'].doc['_private_instance_var'].docstring)
    +
    def test_builtin_methoddescriptors(self)
    +
    + +Expand source code +Browse git + +
    @unittest.skipIf(sys.version_info >= (3, 10), 'No builtin module "parser" in Py3.10')
    +def test_builtin_methoddescriptors(self):
    +    import parser  # TODO: replace with another public binary builtin
    +    with self.assertWarns(UserWarning):
    +        c = pdoc.Class('STType', pdoc.Module(parser), parser.STType)
    +    self.assertIsInstance(c.doc['compile'], pdoc.Function)
    +
    def test_class_members(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_class_members(self):
    +    module = DUMMY_PDOC_MODULE
    +
    +    # GH-200
    +    from enum import Enum
    +
    +    class Tag(Enum):
    +        Char = 1
    +
    +        def func(self):
    +            return self
    +
    +    cls = pdoc.Class('Tag', module, Tag)
    +    self.assertIsInstance(cls.doc['Char'], pdoc.Variable)
    +    self.assertIsInstance(cls.doc['func'], pdoc.Function)
    +
    +    # GH-210, GH-212
    +    my_locals = {}
    +    exec('class Employee:\n name: str', my_locals)
    +    cls = pdoc.Class('Employee', module, my_locals['Employee'])
    +    self.assertIsInstance(cls.doc['name'], pdoc.Variable)
    +    self.assertEqual(cls.doc['name'].type_annotation(), 'str')
    +
    def test_class_variables_docstring_not_from_obj(self)
    +
    + +Expand source code +Browse git + +
    def test_class_variables_docstring_not_from_obj(self):
    +    class C:
    +        vars_dont = 0
    +        but_clss_have_doc = int
    +
    +    doc = pdoc.Class('C', DUMMY_PDOC_MODULE, C)
    +    self.assertEqual(doc.doc['vars_dont'].docstring, '')
    +    self.assertIn('integer', doc.doc['but_clss_have_doc'].docstring)
    +
    def test_context(self)
    +
    + +Expand source code +Browse git + +
    def test_context(self):
    +    context = pdoc.Context()
    +    pdoc.Module(pdoc, context=context)
    +    self.assertIn('pdoc', context)
    +    self.assertIn('pdoc.cli', context)
    +    self.assertIn('pdoc.cli.main', context)
    +    self.assertIn('pdoc.Module', context)
    +    self.assertIsInstance(context['pdoc'], pdoc.Module)
    +    self.assertIsInstance(context['pdoc.cli'], pdoc.Module)
    +    self.assertIsInstance(context['pdoc.cli.main'], pdoc.Function)
    +    self.assertIsInstance(context['pdoc.Module'], pdoc.Class)
    +
    +    module = pdoc.Module(pdoc)
    +    self.assertIsInstance(module.find_ident('pdoc.Module'), pdoc.Class)
    +    pdoc.reset()
    +    self.assertIsInstance(module.find_ident('pdoc.Module'), pdoc.External)
    +
    def test_doc_comment_docstrings(self)
    +
    + +Expand source code +Browse git + +
        def test_doc_comment_docstrings(self):
    +        with temp_dir() as path:
    +            filename = os.path.join(path, 'doc_comment_docstrs.py')
    +            with open(filename, 'w') as f:
    +                f.write('''#: Not included
    +
    +#: Line 1
    +#: Line 2
    +var1 = 1  #: Line 3
    +
    +#: Not included
    +var2 = 1
    +"""PEP-224 takes precedence"""
    +
    +#: This should not appear
    +class C:
    +    #: class var
    +    class_var = 1
    +
    +    #: This also should not show
    +    def __init__(self):
    +       #: instance var
    +       self.instance_var = 1
    +''')
    +
    +            mod = pdoc.Module(pdoc.import_module(filename))
    +
    +            self.assertEqual(mod.doc['var1'].docstring, 'Line 1\nLine 2\nLine 3')
    +            self.assertEqual(mod.doc['var2'].docstring, 'PEP-224 takes precedence')
    +            self.assertEqual(mod.doc['C'].docstring, '')
    +            self.assertEqual(mod.doc['C'].doc['class_var'].docstring, 'class var')
    +            self.assertEqual(mod.doc['C'].doc['instance_var'].docstring, 'instance var')
    +
    def test_dont_touch__pdoc__blacklisted(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_dont_touch__pdoc__blacklisted(self):
    +    class Bomb:
    +        def __getattribute__(self, item):
    +            raise RuntimeError
    +
    +    class D:
    +        x = Bomb()
    +        """doc"""
    +        __qualname__ = 'D'
    +
    +    module = EMPTY_MODULE
    +    D.__module__ = module.__name__  # Need to match is_from_this_module check
    +    with patch.object(module, 'x', Bomb(), create=True), \
    +         patch.object(module, '__pdoc__', {'x': False}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertNotIn('x', mod.doc)
    +    with patch.object(module, 'D', D, create=True), \
    +         patch.object(module, '__pdoc__', {'D.x': False}):
    +        mod = pdoc.Module(module)
    +        pdoc.link_inheritance()
    +        self.assertNotIn('x', mod.doc['D'].doc)
    +
    def test_find_ident(self)
    -
    -
    +
    + +Expand source code +Browse git + +
    def test_find_ident(self):
    +    mod = pdoc.Module(EXAMPLE_MODULE)
    +    self.assertIsInstance(mod.find_ident('subpkg'), pdoc.Module)
    +    mod = pdoc.Module(pdoc)
    +    self.assertIsInstance(mod.find_ident('subpkg'), pdoc.External)
    +
    +    self.assertIsInstance(mod.find_ident(EXAMPLE_MODULE + '.subpkg'), pdoc.Module)
    +
    +    nonexistent = 'foo()'
    +    result = mod.find_ident(nonexistent)
    +    self.assertIsInstance(result, pdoc.External)
    +    self.assertEqual(result.name, nonexistent)
    +
    +    # Ref by class __init__
    +    self.assertIs(mod.find_ident('pdoc.Doc.__init__').obj, pdoc.Doc)
    +
    + +
    def test_import_filename(self)
    +
    + +Expand source code +Browse git + +
    def test_import_filename(self):
    +    with patch.object(sys, 'path', ['']), \
    +            chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE)):
    +        pdoc.import_module('index')
    +
    def test_imported_once(self)
    +
    + +Expand source code +Browse git + +
    def test_imported_once(self):
    +    with chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE)):
    +        pdoc.import_module('_imported_once.py')
    +
    def test_inherited_members(self)
    +
    + +Expand source code +Browse git + +
    def test_inherited_members(self):
    +    mod = pdoc.Module(EXAMPLE_MODULE)
    +    pdoc.link_inheritance()
    +    a = mod.doc['A']
    +    b = mod.doc['B']
    +    self.assertEqual(b.inherited_members(), [(a, [a.doc['inherited'],
    +                                                  a.doc['overridden_same_docstring']])])
    +    self.assertEqual(a.inherited_members(), [])
    +
    def test_inherits(self)
    +
    + +Expand source code +Browse git + +
    def test_inherits(self):
    +    module = pdoc.Module(EXAMPLE_MODULE)
    +    pdoc.link_inheritance()
    +
    +    a = module.doc['A']
    +    b = module.doc['B']
    +    self.assertEqual(b.doc['inherited'].inherits,
    +                     a.doc['inherited'])
    +    self.assertEqual(b.doc['overridden_same_docstring'].inherits,
    +                     a.doc['overridden_same_docstring'])
    +    self.assertEqual(b.doc['overridden'].inherits,
    +                     None)
    +
    +    c = module.doc['C']
    +    d = module.doc['D']
    +    self.assertEqual(d.doc['overridden'].inherits, c.doc['overridden'])
    +    self.assertEqual(c.doc['overridden'].inherits, b.doc['overridden'])
    +
    def test_instance_var(self)
    +
    + +Expand source code +Browse git + +
    def test_instance_var(self):
    +    mod = EXAMPLE_PDOC_MODULE
    +    var = mod.doc['B'].doc['instance_var']
    +    self.assertTrue(var.instance_var)
    +
    +
    + +Expand source code +Browse git + +
    def test_link_inheritance(self):
    +    mod = pdoc.Module(EXAMPLE_MODULE)
    +    with warnings.catch_warnings(record=True) as w:
    +        pdoc.link_inheritance()
    +        pdoc.link_inheritance()
    +    self.assertFalse(w)
    +
    +    # Test inheritance across modules
    +    pdoc.reset()
    +    mod = pdoc.Module(EXAMPLE_MODULE + '._test_linking')
    +    pdoc.link_inheritance()
    +    a = mod.doc['a'].doc['A']
    +    b = mod.doc['b'].doc['B']
    +    c = mod.doc['b'].doc['c'].doc['C']
    +    self.assertEqual(b.doc['a'].inherits, a.doc['a'])
    +    self.assertEqual(b.doc['c'].inherits, c.doc['c'])
    +    # While classes do inherit from superclasses, they just shouldn't always
    +    # say so, because public classes do want to be exposed and linked to
    +    self.assertNotEqual(b.inherits, a)
    +
    def test_mock_signature_error(self)
    +
    + +Expand source code +Browse git + +
    @expectedFailure
    +def test_mock_signature_error(self):
    +    # GH-350 -- throws `TypeError: 'Mock' object is not subscriptable`:
    +    self.assertIsInstance(inspect.signature(Mock(spec=lambda x: x)), inspect.Signature)
    +
    def test_module(self)
    +
    + +Expand source code +Browse git + +
    def test_module(self):
    +    modules = {
    +        EXAMPLE_MODULE: ('', ('index', 'module', 'subpkg', 'subpkg2')),
    +        EXAMPLE_MODULE + '.subpkg2': ('.subpkg2', ('subpkg2.module',)),
    +    }
    +    with chdir(TESTS_BASEDIR):
    +        for module, (name_suffix, submodules) in modules.items():
    +            with self.subTest(module=module):
    +                m = pdoc.Module(module)
    +                self.assertEqual(repr(m), f"<Module '{m.obj.__name__}'>")
    +                self.assertEqual(m.name, EXAMPLE_MODULE + name_suffix)
    +                self.assertEqual(sorted(m.name for m in m.submodules()),
    +                                 [EXAMPLE_MODULE + '.' + m for m in submodules])
    +
    def test_module_allsubmodules(self)
    +
    + +Expand source code +Browse git + +
    def test_module_allsubmodules(self):
    +    m = pdoc.Module(EXAMPLE_MODULE + '._private')
    +    self.assertEqual(sorted(m.name for m in m.submodules()),
    +                     [EXAMPLE_MODULE + '._private.module'])
    +
    def test_module_init(self)
    +
    + +Expand source code +Browse git + +
    def test_module_init(self):
    +    mod = pdoc.Module('pdoc.__init__')
    +    self.assertEqual(mod.name, 'pdoc')
    +    self.assertIn('Module', mod.doc)
    +
    def test_namespace(self)
    +
    + +Expand source code +Browse git + +
    def test_namespace(self):
    +    # Test the three namespace types
    +    # https://packaging.python.org/guides/packaging-namespace-packages/#creating-a-namespace-package
    +    for i in range(1, 4):
    +        path = os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE, '_namespace', str(i))
    +        with patch.object(sys, 'path', [os.path.join(path, 'a'),
    +                                        os.path.join(path, 'b')]):
    +            mod = pdoc.Module('a.main')
    +            self.assertIn('D', mod.doc)
    +
    def test_qualname(self)
    +
    + +Expand source code +Browse git + +
    def test_qualname(self):
    +    module = EXAMPLE_PDOC_MODULE
    +    var = module.doc['var']
    +    cls = module.doc['B']
    +    nested_cls = cls.doc['C']
    +    cls_var = cls.doc['var']
    +    method = cls.doc['f']
    +
    +    self.assertEqual(pdoc.External('foo').qualname, 'foo')
    +    self.assertEqual(module.qualname, EXAMPLE_MODULE)
    +    self.assertEqual(var.qualname, 'var')
    +    self.assertEqual(cls.qualname, 'B')
    +    self.assertEqual(nested_cls.qualname, 'B.C')
    +    self.assertEqual(cls_var.qualname, 'B.var')
    +    self.assertEqual(method.qualname, 'B.f')
    +
    def test_readonly_value_descriptors(self)
    +
    + +Expand source code +Browse git + +
    def test_readonly_value_descriptors(self):
    +    pdoc.reset()
    +    mod = pdoc.Module(pdoc.import_module(EXAMPLE_MODULE))
    +    var = mod.doc['B'].doc['ro_value_descriptor']
    +    self.assertIsInstance(var, pdoc.Variable)
    +    self.assertTrue(var.instance_var)
    +    self.assertEqual(var.docstring, """ro_value_descriptor docstring""")
    +    self.assertTrue(var.source)
    +
    +    var = mod.doc['B'].doc['ro_value_descriptor_no_doc']
    +    self.assertIsInstance(var, pdoc.Variable)
    +    self.assertTrue(var.instance_var)
    +    self.assertEqual(var.docstring, """Read-only value descriptor""")
    +    self.assertTrue(var.source)
    +
    def test_refname(self)
    +
    + +Expand source code +Browse git + +
    def test_refname(self):
    +    mod = EXAMPLE_MODULE + '.' + 'subpkg'
    +    module = pdoc.Module(mod)
    +    var = module.doc['var']
    +    cls = module.doc['B']
    +    nested_cls = cls.doc['C']
    +    cls_var = cls.doc['var']
    +    method = cls.doc['f']
    +
    +    self.assertEqual(pdoc.External('foo').refname, 'foo')
    +    self.assertEqual(module.refname, mod)
    +    self.assertEqual(var.refname, mod + '.var')
    +    self.assertEqual(cls.refname, mod + '.B')
    +    self.assertEqual(nested_cls.refname, mod + '.B.C')
    +    self.assertEqual(cls_var.refname, mod + '.B.var')
    +    self.assertEqual(method.refname, mod + '.B.f')
    +
    +    # Inherited method's refname points to class' implicit copy
    +    pdoc.link_inheritance()
    +    self.assertEqual(cls.doc['inherited'].refname, mod + '.B.inherited')
    +
    def test_sorting(self)
    +
    + +Expand source code +Browse git + +
    def test_sorting(self):
    +    module = EXAMPLE_PDOC_MODULE
    +
    +    sorted_variables = module.variables()
    +    unsorted_variables = module.variables(sort=False)
    +    self.assertNotEqual(sorted_variables, unsorted_variables)
    +    self.assertEqual(sorted_variables, sorted(unsorted_variables))
    +
    +    sorted_functions = module.functions()
    +    unsorted_functions = module.functions(sort=False)
    +    self.assertNotEqual(sorted_functions, unsorted_functions)
    +    self.assertEqual(sorted_functions, sorted(unsorted_functions))
    +
    +    sorted_classes = module.classes()
    +    unsorted_classes = module.classes(sort=False)
    +    self.assertNotEqual(sorted_classes, unsorted_classes)
    +    self.assertEqual(sorted_classes, sorted(unsorted_classes))
    +
    +    cls = module.doc["Docformats"]
    +
    +    sorted_methods = cls.methods()
    +    unsorted_methods = cls.methods(sort=False)
    +    self.assertNotEqual(sorted_methods, unsorted_methods)
    +    self.assertEqual(sorted_methods, sorted(unsorted_methods))
    +
    def test_subclasses(self)
    +
    + +Expand source code +Browse git + +
    @ignore_warnings
    +def test_subclasses(self):
    +    class A:
    +        pass
    +
    +    class B(type):
    +        pass
    +
    +    class C(A):
    +        pass
    +
    +    class D(B):
    +        pass
    +
    +    class G(C):
    +        pass
    +
    +    class F(C):
    +        pass
    +
    +    class E(C):
    +        pass
    +
    +    mod = DUMMY_PDOC_MODULE
    +    self.assertEqual([x.refname for x in pdoc.Class('A', mod, A).subclasses()],
    +                     [mod.find_class(C).refname])
    +    self.assertEqual([x.refname for x in pdoc.Class('B', mod, B).subclasses()],
    +                     [mod.find_class(D).refname])
    +    self.assertEqual([x.refname for x in pdoc.Class('C', mod, C).subclasses()],
    +                     [mod.find_class(x).refname for x in (E, F, G)])
    +
    def test_test_Function_params_python38_specific(self)
    +
    + +Expand source code +Browse git + +
    @unittest.skipIf(sys.version_info < (3, 8), "positional-only arguments unsupported in < py3.8")
    +def test_test_Function_params_python38_specific(self):
    +    mod = DUMMY_PDOC_MODULE
    +    func = pdoc.Function('f', mod, eval("lambda a, /, b: None"))
    +    self.assertEqual(func.params(), ['a', '/', 'b'])
    +
    +    func = pdoc.Function('f', mod, eval("lambda a, /: None"))
    +    self.assertEqual(func.params(), ['a', '/'])
    +
    def test_url(self)
    +
    + +Expand source code +Browse git + +
    def test_url(self):
    +    mod = pdoc.Module(EXAMPLE_MODULE)
    +    pdoc.link_inheritance()
    +
    +    c = mod.doc['D']
    +    self.assertEqual(c.url(), 'example_pkg/index.html#example_pkg.D')
    +    self.assertEqual(c.url(link_prefix='/'), '/example_pkg/index.html#example_pkg.D')
    +    self.assertEqual(c.url(relative_to=c.module), '#example_pkg.D')
    +    self.assertEqual(c.url(top_ancestor=True), c.url())  # Public classes do link to themselves
    +
    +    f = c.doc['overridden']
    +    self.assertEqual(f.url(), 'example_pkg/index.html#example_pkg.D.overridden')
    +    self.assertEqual(f.url(link_prefix='/'), '/example_pkg/index.html#example_pkg.D.overridden')
    +    self.assertEqual(f.url(relative_to=c.module), '#example_pkg.D.overridden')
    +    self.assertEqual(f.url(top_ancestor=1), 'example_pkg/index.html#example_pkg.B.overridden')
    +
    @@ -1057,7 +2025,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class CliTest(unittest.TestCase):
         """
    @@ -1230,7 +2198,7 @@ 

    Methods

    self._basic_html_assertions(expected_files=files) self._check_files(exclude_patterns=['class="gcse-search"']) if shutil.which('node'): - self._check_files(include_patterns=['INDEX={"version"'], + self._check_files(include_patterns=['{"version"', 'pdoc.Doc'], file_pattern='index.js') else: self._check_files( @@ -1465,153 +2433,624 @@

    Methods

    Hook method for setting up the test fixture before exercising it.

    +
    + +Expand source code +Browse git + +
    def setUp(self):
    +    pdoc.reset()
    +
    def test_config(self)
    +
    + +Expand source code +Browse git + +
    def test_config(self):
    +    with run_html(EXAMPLE_MODULE, config='link_prefix="/foobar/"'):
    +        self._basic_html_assertions()
    +        self._check_files(['/foobar/' + EXAMPLE_MODULE])
    +
    def test_docformat(self)
    +
    + +Expand source code +Browse git + +
    def test_docformat(self):
    +    with self.assertWarns(UserWarning) as cm, \
    +            run_html(EXAMPLE_MODULE, config='docformat="restructuredtext"'):
    +        self._basic_html_assertions()
    +    self.assertIn('numpy', cm.warning.args[0])
    +
    +
    + +Expand source code +Browse git + +
    def test_external_links(self):
    +    with run_html(EXAMPLE_MODULE):
    +        self._basic_html_assertions()
    +        self._check_files(exclude_patterns=['<a href="/sys.version.ext"'])
    +
    +    with self.assertWarns(DeprecationWarning), \
    +            run_html(EXAMPLE_MODULE, external_links=None):
    +        self._basic_html_assertions()
    +        self._check_files(['<a title="sys.version" href="/sys.version.ext"'])
    +
    def test_force(self)
    +
    + +Expand source code +Browse git + +
    def test_force(self):
    +    with run_html(EXAMPLE_MODULE):
    +        with redirect_streams() as (stdout, stderr):
    +            returncode = run(EXAMPLE_MODULE, html=None, output_dir=os.getcwd())
    +            self.assertNotEqual(returncode, 0)
    +            self.assertNotEqual(stderr.getvalue(), '')
    +
    +        with redirect_streams() as (stdout, stderr):
    +            returncode = run(EXAMPLE_MODULE, html=None, force=None, output_dir=os.getcwd())
    +            self.assertEqual(returncode, 0)
    +            self.assertEqual(stderr.getvalue(), '')
    +
    def test_google_analytics(self)
    +
    + +Expand source code +Browse git + +
    def test_google_analytics(self):
    +    expected = ['googletagmanager.com']
    +    with run_html(EXAMPLE_MODULE):
    +        self._check_files((), exclude_patterns=expected)
    +    with run_html(EXAMPLE_MODULE, config='google_analytics="G-xxxxxxxxxx"'):
    +        self._check_files(expected)
    +
    def test_google_search_query(self)
    +
    + +Expand source code +Browse git + +
    def test_google_search_query(self):
    +    with run_html(EXAMPLE_MODULE, config='google_search_query="anything"'):
    +        self._basic_html_assertions()
    +        self._check_files(include_patterns=['class="gcse-search"'])
    +
    def test_html(self)
    +
    + +Expand source code +Browse git + +
    def test_html(self):
    +    include_patterns = [
    +        'a=&lt;object',
    +        'CONST docstring',
    +        'var docstring',
    +        'foreign_var',
    +        'foreign var docstring',
    +        'A',
    +        'A.overridden docstring',
    +        'A.overridden_same_docstring docstring',
    +        'A.inherited',
    +        'B docstring',
    +        'B.overridden docstring',
    +        'builtins.int',
    +        'External refs: ',
    +        '>sys.version<',
    +        'B.CONST docstring',
    +        'B.var docstring',
    +        'b=1',
    +        '*args',
    +        '**kwargs',
    +        'x, y, z, w',
    +        'instance_var',
    +        'instance var docstring',
    +        'B.f docstring',
    +        'B.static docstring',
    +        'B.cls docstring',
    +        'B.p docstring',
    +        'B.C docstring',
    +        'B.overridden docstring',
    +
    +        '<code>__init__</code> docstring',
    +        ' class="ident">static',
    +    ]
    +    exclude_patterns = [
    +        '<object ',
    +        ' class="ident">_private',
    +        ' class="ident">_Private',
    +    ]
    +    if sys.version_info >= (3, 10):
    +        include_patterns.append('non_callable_routine')
    +    else:
    +        exclude_patterns.append('non_callable_routine')
    +
    +    package_files = {
    +        '': self.PUBLIC_FILES,
    +        '.subpkg2': [f for f in self.PUBLIC_FILES
    +                     if 'subpkg2' in f or f == EXAMPLE_MODULE],
    +        '._private': [f for f in self.ALL_FILES
    +                      if EXAMPLE_MODULE + os.path.sep + '_private' in f or f == EXAMPLE_MODULE],
    +    }
    +    for package, expected_files in package_files.items():
    +        with self.subTest(package=package):
    +            with run_html(EXAMPLE_MODULE + package,
    +                          '--config', 'show_type_annotations=False',
    +                          config='show_source_code=False'):
    +                self._basic_html_assertions(expected_files)
    +                self._check_files(include_patterns, exclude_patterns)
    +
    +    filenames_files = {
    +        ('module.py',): ['module.html'],
    +        ('module.py', 'subpkg2'): ['module.html', 'subpkg2',
    +                                   os.path.join('subpkg2', 'index.html'),
    +                                   os.path.join('subpkg2', 'module.html')],
    +    }
    +    with chdir(TESTS_BASEDIR):
    +        for filenames, expected_files in filenames_files.items():
    +            with self.subTest(filename=','.join(filenames)):
    +                with run_html(*(os.path.join(EXAMPLE_MODULE, f) for f in filenames),
    +                              '--config', 'show_type_annotations=False',
    +                              config='show_source_code=False'):
    +                    self._basic_html_assertions(expected_files)
    +                    self._check_files(include_patterns, exclude_patterns)
    +
    def test_html_identifier(self)
    +
    + +Expand source code +Browse git + +
    def test_html_identifier(self):
    +    for package in ('', '._private'):
    +        with self.subTest(package=package), \
    +                self.assertWarns(UserWarning) as cm:
    +            with run_html(EXAMPLE_MODULE + package, filter='A',
    +                          config='show_source_code=False'):
    +                self._check_files(['A'], ['CONST', 'B docstring'])
    +    self.assertIn('Code reference `example_pkg.B`', cm.warning.args[0])
    +
    def test_html_multiple_files(self)
    +
    + +Expand source code +Browse git + +
    def test_html_multiple_files(self):
    +    with chdir(TESTS_BASEDIR):
    +        with run_html(os.path.join(EXAMPLE_MODULE, 'module.py'),
    +                      os.path.join(EXAMPLE_MODULE, 'subpkg2')):
    +            self._basic_html_assertions(['module.html', 'subpkg2',
    +                                         os.path.join('subpkg2', 'index.html'),
    +                                         os.path.join('subpkg2', 'module.html')])
    +
    def test_html_no_source(self)
    +
    + +Expand source code +Browse git + +
    def test_html_no_source(self):
    +    with self.assertWarns(DeprecationWarning), \
    +            run_html(EXAMPLE_MODULE, html_no_source=None):
    +        self._basic_html_assertions()
    +        self._check_files(exclude_patterns=['class="source"', 'Hidden'])
    +
    +
    + +Expand source code +Browse git + +
    def test_html_ref_links(self):
    +    with run_html(EXAMPLE_MODULE, config='show_source_code=False'):
    +        self._check_files(
    +            file_pattern=os.path.join(EXAMPLE_MODULE, 'index.html'),
    +            include_patterns=[
    +                'href="#example_pkg.B">',
    +                'href="#example_pkg.A">',
    +            ],
    +        )
    +
    +
    + +Expand source code +Browse git + +
    def test_link_prefix(self):
    +    with self.assertWarns(DeprecationWarning), \
    +            run_html(EXAMPLE_MODULE, link_prefix='/foobar/'):
    +        self._basic_html_assertions()
    +        self._check_files(['/foobar/' + EXAMPLE_MODULE])
    +
    +
    + +Expand source code +Browse git + +
    def test_lunr_search(self):
    +    with run_html(EXAMPLE_MODULE, config='lunr_search={"fuzziness": 1}'):
    +        files = self.PUBLIC_FILES + ["doc-search.html", "index.js"]
    +        self._basic_html_assertions(expected_files=files)
    +        self._check_files(exclude_patterns=['class="gcse-search"'])
    +        if shutil.which('node'):
    +            self._check_files(include_patterns=['{"version"', 'pdoc.Doc'],
    +                              file_pattern='index.js')
    +        else:
    +            self._check_files(
    +                include_patterns=['URLS=[\n"example_pkg/index.html",\n"example_pkg/'],
    +                file_pattern='index.js')
    +        self._check_files(include_patterns=["'../doc-search.html#'"],
    +                          file_pattern='example_pkg/index.html')
    +        self._check_files(include_patterns=["'../doc-search.html#'"],
    +                          file_pattern='example_pkg/module.html')
    +        self._check_files(include_patterns=["'../../doc-search.html#'"],
    +                          file_pattern='example_pkg/subpkg/index.html')
    +    # Only build lunr search when --html
    +    with redirect_streams() as (_, stderr):
    +        run(EXAMPLE_MODULE,  config='lunr_search={"fuzziness": 1}')
    +        self.assertFalse(stderr.read())
    +
    def test_md_extensions(self)
    +
    + +Expand source code +Browse git + +
    def test_md_extensions(self):
    +    with temp_dir() as path, chdir(path):
    +        Path('foo.py').write_text('"""secret: meta data\n\nOnly this comment expected."""')
    +        with redirect_streams() as (stdout, _), \
    +                run_html('foo.py',
    +                         config="md_extensions={'extensions': ['markdown.extensions.meta']}",):
    +            self._check_files(include_patterns=['<p>Only this comment expected.</p>'],
    +                              exclude_patterns=['<p>secret: meta data</p>'])
    +
    def test_output_text(self)
    +
    + +Expand source code +Browse git + +
    def test_output_text(self):
    +    with temp_dir() as path, \
    +            redirect_streams():
    +        run(EXAMPLE_MODULE, output_dir=path)
    +        with chdir(path):
    +            self._basic_html_assertions([file.replace('.html', '.md')
    +                                         for file in self.PUBLIC_FILES])
    +
    def test_pdf(self)
    +
    + +Expand source code +Browse git + +
    def test_pdf(self):
    +    with redirect_streams() as (stdout, stderr):
    +        run('pdoc', pdf=None)
    +        out = stdout.getvalue()
    +        err = stderr.getvalue()
    +    self.assertIn('pdoc3.github.io', out)
    +    self.assertIn('pandoc', err)
    +    self.assertIn('Doc(name', out.replace('>', '').replace('\n', '').replace(' ', ''))
    +
    def test_pdf_pandoc(self)
    +
    + +Expand source code +Browse git + +
    @unittest.skipUnless('PDOC_TEST_PANDOC' in os.environ, 'PDOC_TEST_PANDOC not set/requested')
    +def test_pdf_pandoc(self):
    +    with temp_dir() as path, \
    +            chdir(path), \
    +            redirect_streams() as (stdout, _), \
    +            open('pdf.md', 'w') as f:
    +        run('pdoc', pdf=None)
    +        f.write(stdout.getvalue())
    +        subprocess.run(pdoc.cli._PANDOC_COMMAND, shell=True, check=True)
    +        self.assertTrue(os.path.exists('/tmp/pdoc.pdf'))
    +
    def test_project_doctests(self)
    +
    + +Expand source code +Browse git + +
    @unittest.skipIf(sys.version_info < (3, 10),
    +                 'HACK: _formatannotation() changed return value in Py3.10')
    +def test_project_doctests(self):
    +    doctests = doctest.testmod(pdoc)
    +    assert not doctests.failed and doctests.attempted, doctests
    +
    def test_relative_dir_path(self)
    +
    + +Expand source code +Browse git + +
    def test_relative_dir_path(self):
    +    with chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE)):
    +        with run_html('.'):
    +            self._check_files(())
    +
    def test_resolve_typing_forwardrefs(self)
    +
    + +Expand source code +Browse git + +
    @unittest.skipIf(sys.version_info < (3, 7), '__future__.annotations unsupported in <Py3.7')
    +def test_resolve_typing_forwardrefs(self):
    +    # GH-245
    +    with chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE, '_resolve_typing_forwardrefs')):
    +        with redirect_streams() as (out, _err):
    +            run('postponed')
    +        out = out.getvalue()
    +        self.assertIn('bar', out)
    +        self.assertIn('baz', out)
    +        self.assertIn('dt', out)
    +        self.assertIn('datetime', out)
    +
    +        with redirect_streams() as (out, _err):
    +            run('evaluated')
    +        out = out.getvalue()
    +        self.assertIn('Set[Bar]', out)
    +
    def test_skip_errors(self)
    +
    + +Expand source code +Browse git + +
    def test_skip_errors(self):
    +    with chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE, '_skip_errors')), \
    +            redirect_streams(), \
    +            self.assertWarns(pdoc.Module.ImportWarning) as cm:
    +        run('.', skip_errors=None)
    +        run('unimportable', skip_errors=None)
    +    self.assertEqual(2, sum(1 for w in cm.warnings if 'ZeroDivision' in str(w.message)))
    +
    def test_template_dir(self)
    +
    + +Expand source code +Browse git + +
    def test_template_dir(self):
    +    old_tpl_dirs = pdoc.tpl_lookup.directories.copy()
    +    # Prevent loading incorrect template cached from prev runs
    +    pdoc.tpl_lookup._collection.clear()
    +    try:
    +        with run_html(EXAMPLE_MODULE, template_dir=TESTS_BASEDIR):
    +            self._basic_html_assertions()
    +            self._check_files(['FOOBAR', '/* Empty CSS */'], ['coding: utf-8'])
    +    finally:
    +        pdoc.tpl_lookup.directories = old_tpl_dirs
    +        pdoc.tpl_lookup._collection.clear()
    +
    def test_text(self)
    +
    + +Expand source code +Browse git + +
    def test_text(self):
    +    include_patterns = [
    +        'object_as_arg_default(*args, a=<object ',
    +        'CONST docstring',
    +        'var docstring',
    +        'foreign_var',
    +        'foreign var docstring',
    +        'A',
    +        'A.overridden docstring',
    +        'A.overridden_same_docstring docstring',
    +        'A.inherited',
    +        'B docstring',
    +        'B.overridden docstring',
    +        'builtins.int',
    +        'External refs: ',
    +        'sys.version',
    +        'B.CONST docstring',
    +        'B.var docstring',
    +        'x, y, z, w',
    +        '`__init__` docstring',
    +        'instance_var',
    +        'instance var docstring',
    +        'b=1',
    +        '*args',
    +        '**kwargs',
    +        'B.f docstring',
    +        'B.static docstring',
    +        'B.cls docstring',
    +        'B.p docstring',
    +        'C',
    +        'B.overridden docstring',
    +        'function_mock',
    +        'coroutine_mock',
    +    ]
    +    exclude_patterns = [
    +        '_private',
    +        '_Private',
    +        'subprocess',
    +        'Hidden',
    +    ]
    +    if sys.version_info >= (3, 10):
    +        include_patterns.append('non_callable_routine')
    +    else:
    +        exclude_patterns.append('non_callable_routine')
    +
    +    with self.subTest(package=EXAMPLE_MODULE):
    +        with redirect_streams() as (stdout, _):
    +            run(EXAMPLE_MODULE, config='show_type_annotations=False')
    +            out = stdout.getvalue()
    +
    +        header = f"Module {EXAMPLE_MODULE}\n{'':=<{len('Module ') + len(EXAMPLE_MODULE)}}"
    +        self.assertIn(header, out)
    +        for pattern in include_patterns:
    +            self.assertIn(pattern, out)
    +        for pattern in exclude_patterns:
    +            self.assertNotIn(pattern, out)
    +
    +    with chdir(TESTS_BASEDIR):
    +        for files in (('module.py',),
    +                      ('module.py', 'subpkg2')):
    +            with self.subTest(filename=','.join(files)):
    +                with redirect_streams() as (stdout, _):
    +                    run(*(os.path.join(EXAMPLE_MODULE, f) for f in files))
    +                    out = stdout.getvalue()
    +                for f in files:
    +                    header = f'Module {os.path.splitext(f)[0]}\n'
    +                    self.assertIn(header, out)
    +
    def test_text_identifier(self)
    -
    - - +
    + +Expand source code +Browse git + +
    def test_text_identifier(self):
    +    with redirect_streams() as (stdout, _):
    +        run(EXAMPLE_MODULE, filter='A')
    +        out = stdout.getvalue()
    +    self.assertIn('A', out)
    +    self.assertIn('### Descendants\n\n    * example_pkg.B', out)
    +    self.assertNotIn('CONST', out)
    +    self.assertNotIn('B docstring', out)
    +
    + + +
    class Docformats (methodName='runTest') @@ -1648,7 +3087,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class Docformats(unittest.TestCase):
         @classmethod
    @@ -2021,54 +3460,440 @@ 

    Methods

    +
    + +Expand source code +Browse git + +
        def test_doctests(self):
    +        expected = '''<p>Need an intro paragrapgh.</p>
    +<pre><code>&gt;&gt;&gt; Then code is indented one level
    +line1
    +line2
    +</code></pre>
    +<p>Alternatively</p>
    +<pre><code>&gt;&gt;&gt; doctest
    +fenced code works
    +always
    +</code></pre>
    +<h2 id="examples">Examples</h2>
    +<pre><code class="language-python-repl">&gt;&gt;&gt; nbytes(100)
    +'100.0 bytes'
    +line2
    +</code></pre>
    +<p>some text</p>
    +<p>some text</p>
    +<pre><code class="language-python-repl">&gt;&gt;&gt; another doctest
    +line1
    +line2
    +</code></pre>
    +<h2 id="example">Example</h2>
    +<pre><code class="language-python-repl">&gt;&gt;&gt; f()
    +Traceback (most recent call last):
    +    ...
    +Exception: something went wrong
    +</code></pre>'''
    +        text = inspect.getdoc(self._docmodule.doctests)
    +        html = to_html(text, module=self._module, link=self._link)
    +        self.assertEqual(html, expected)
    +
    def test_fenced_code(self)
    +
    + +Expand source code +Browse git + +
        def test_fenced_code(self):
    +        # GH-207
    +        text = '''\
    +```
    +cmd `pwd`
    +```
    +'''
    +        expected = '''<pre><code>cmd `pwd`\n</code></pre>'''
    +        html = to_html(text, module=self._module)
    +        self.assertEqual(html, expected)
    +
    def test_google(self)
    +
    + +Expand source code +Browse git + +
        def test_google(self):
    +        expected = '''<p>Summary line.
    +Nomatch:</p>
    +<h2 id="args">Args</h2>
    +<dl>
    +<dt><strong><code>arg1</code></strong> :&ensp;<code>str</code>, optional</dt>
    +<dd>Text1</dd>
    +<dt><strong><code>arg2</code></strong> :&ensp;<code>List[str]</code>, optional,\
    + default=<code>10</code></dt>
    +<dd>Text2</dd>
    +<dt><strong><code>data</code></strong> :&ensp;<code>array-like object</code></dt>
    +<dd>foo</dd>
    +</dl>
    +<h2 id="args_1">Args</h2>
    +<dl>
    +<dt><strong><code>arg1</code></strong> :&ensp;<code>int</code></dt>
    +<dd>Description of arg1</dd>
    +<dt><strong><code>arg2</code></strong> :&ensp;<code>str</code> or <code>int</code></dt>
    +<dd>Description of arg2</dd>
    +<dt><strong><code>arg3</code></strong> :&ensp;<code>str | None</code></dt>
    +<dd>Description of arg3</dd>
    +<dt><strong><code>test_sequence</code></strong></dt>
    +<dd>
    +<p>2-dim numpy array of real numbers, size: N * D
    +- the test observation sequence.</p>
    +<pre><code>test_sequence =
    +code
    +</code></pre>
    +<p>Continue.</p>
    +</dd>
    +<dt><strong><code>*args</code></strong></dt>
    +<dd>passed around</dd>
    +</dl>
    +<h2 id="returns">Returns</h2>
    +<dl>
    +<dt><code>issue_10</code></dt>
    +<dd>description didn't work across multiple lines
    +if only a single item was listed. <code><a>inspect.cleandoc()</a></code>
    +somehow stripped the required extra indentation.</dd>
    +</dl>
    +<h2 id="returns_1">Returns</h2>
    +<p>A very special number
    +which is the answer of everything.</p>
    +<h2 id="returns_2">Returns</h2>
    +<dl>
    +<dt><code>Dict[int, <a>pdoc.Doc</a>]</code></dt>
    +<dd>Description.</dd>
    +</dl>
    +<h2 id="returns_3">Returns</h2>
    +<dl>
    +<dt><code>int | str</code></dt>
    +<dd>Description.</dd>
    +</dl>
    +<h2 id="raises">Raises</h2>
    +<dl>
    +<dt><code>AttributeError</code></dt>
    +<dd>
    +<p>The <code>Raises</code> section is a list of all exceptions
    +that are relevant to the interface.</p>
    +<p>and a third line.</p>
    +</dd>
    +<dt><code>ValueError</code></dt>
    +<dd>If <code>arg2</code> is equal to <code>arg1</code>.</dd>
    +</dl>
    +<p>Test a title without a blank line before it.</p>
    +<h2 id="args_2">Args</h2>
    +<dl>
    +<dt><strong><code>A</code></strong></dt>
    +<dd>a</dd>
    +</dl>
    +<h2 id="examples">Examples</h2>
    +<p>Examples in doctest format.</p>
    +<pre><code class="language-python-repl">&gt;&gt;&gt; a = [1,2,3]
    +</code></pre>
    +<h2 id="todos">Todos</h2>
    +<ul>
    +<li>For module TODOs</li>
    +</ul>'''
    +        text = inspect.getdoc(self._docmodule.google)
    +        html = to_html(text, module=self._module, link=self._link)
    +        self.assertEqual(html, expected)
    +
    def test_latex_math(self)
    +
    + +Expand source code +Browse git + +
        def test_latex_math(self):
    +        expected = r'''<p>Inline equation: <span><span class="MathJax_Preview"> v_t *\frac{1}{2}* j_i + [a] &lt; 3 </span><script type="math/tex"> v_t *\frac{1}{2}* j_i + [a] < 3 </script></span>.</p>
    +<p>Block equation: <span><span class="MathJax_Preview"> v_t *\frac{1}{2}* j_i + [a] &lt; 3 </span><script type="math/tex; mode=display"> v_t *\frac{1}{2}* j_i + [a] < 3 </script></span></p>
    +<p>Block equation: <span><span class="MathJax_Preview"> v_t *\frac{1}{2}* j_i + [a] &lt; 3 </span><script type="math/tex; mode=display"> v_t *\frac{1}{2}* j_i + [a] < 3 </script></span></p>
    +<p>$\mathcal{O}(N)$</p>
    +<p>Escaping \$ should work in math like $X = \$3.25$ once it is implemented.</p>
    +<p><span><span class="MathJax_Preview"> v_t *\frac{1}{2}* j_i + [a] &lt; 3 </span><script type="math/tex; mode=display"> v_t *\frac{1}{2}* j_i + [a] < 3 </script></span></p>'''  # noqa: E501
    +        text = inspect.getdoc(self._docmodule.latex_math)
    +        html = to_html(text, module=self._module, link=self._link, latex_math=True)
    +        self.assertEqual(html, expected)
    +
    def test_numpy(self)
    +
    + +Expand source code +Browse git + +
        def test_numpy(self):
    +        expected = '''<p>Summary line.</p>
    +<p><strong>Documentation</strong>: <a href="https://pdoc3.github.io/pdoc/doc/pdoc/">https://pdoc3.github.io/pdoc/doc/pdoc/</a>
    +<strong>Source Code</strong>: <a href="https://github.com/pdoc3/">https://github.com/pdoc3/</a></p>
    +<h2 id="parameters">Parameters</h2>
    +<dl>
    +<dt><strong><code>x1</code></strong>, <strong><code>x2</code></strong> :&ensp;<code>array_like</code></dt>
    +<dd>
    +<p>Input arrays,
    +description of <code>x1</code>, <code>x2</code>.</p>
    +<div class="admonition versionadded">
    +<p class="admonition-title">Added in version:&ensp;1.5.0</p>
    +</div>
    +</dd>
    +<dt><strong><code>x</code></strong> :&ensp;<code>{ NoneType, 'B', 'C' }</code>, optional</dt>
    +<dd>&nbsp;</dd>
    +<dt><strong><code>n</code></strong> :&ensp;<code>int</code> or <code>list</code> of <code>int</code></dt>
    +<dd>Description of num</dd>
    +<dt><strong><code>*args</code></strong>, <strong><code>**kwargs</code></strong></dt>
    +<dd>Passed on.</dd>
    +<dt><strong><code>complex</code></strong> :&ensp;<code>Union[Set[<a>pdoc.Doc</a>, <a>pdoc.Function</a>], <a>pdoc</a>]</code></dt>
    +<dd>The <code>List[<a>pdoc.Doc</a>]</code>s of the new signal.</dd>
    +</dl>
    +<h2 id="returns">Returns</h2>
    +<dl>
    +<dt><strong><code>output</code></strong> :&ensp;<code><a>pdoc.Doc</a></code></dt>
    +<dd>The output array</dd>
    +<dt><code>List[<a>pdoc.Doc</a>]</code></dt>
    +<dd>The output array</dd>
    +<dt><code>foo</code></dt>
    +<dd>&nbsp;</dd>
    +</dl>
    +<h2 id="raises">Raises</h2>
    +<dl>
    +<dt><code>TypeError</code></dt>
    +<dd>When something.</dd>
    +</dl>
    +<h2 id="raises_1">Raises</h2>
    +<dl>
    +<dt><code>TypeError</code></dt>
    +<dd>&nbsp;</dd>
    +</dl>
    +<h2 id="returns_1">Returns</h2>
    +<p>None.</p>
    +<h2 id="invalid">Invalid</h2>
    +<p>no match</p>
    +<h2 id="see-also">See Also</h2>
    +<p><code>fromstring</code>, <code>loadtxt</code></p>
    +<h2 id="see-also_1">See Also</h2>
    +<dl>
    +<dt><code><a>pdoc.text</a></code></dt>
    +<dd>Function a with its description.</dd>
    +<dt><code><a>scipy.random.norm</a></code></dt>
    +<dd>Random variates, PDFs, etc.</dd>
    +<dt><code><a>pdoc.Doc</a></code></dt>
    +<dd>A class description that spans several lines.</dd>
    +</dl>
    +<h2 id="examples">Examples</h2>
    +<pre><code class="language-python-repl">&gt;&gt;&gt; doctest
    +...
    +</code></pre>
    +<h2 id="notes">Notes</h2>
    +<p>Foo bar.</p>
    +<h3 id="h3-title">H3 Title</h3>
    +<p>Foo bar.</p>'''  # noqa: E501
    +        text = inspect.getdoc(self._docmodule.numpy)
    +        html = to_html(text, module=self._module, link=self._link)
    +        self.assertEqual(html, expected)
    +
    def test_numpy_curly_brace_expansion(self)
    +
    + +Expand source code +Browse git + +
        def test_numpy_curly_brace_expansion(self):
    +        # See: https://github.com/mwaskom/seaborn/blob/66191d8a179f1bfa42f03749bc4a07e1c0c08156/seaborn/regression.py#L514  # noqa: 501
    +        text = '''Parameters
    +----------
    +prefix_{x,y}_partial : str
    +    some description
    +'''
    +        expected = '''<h2 id="parameters">Parameters</h2>
    +<dl>
    +<dt><strong><code>prefix_{x,y}_partial</code></strong> :&ensp;<code>str</code></dt>
    +<dd>some description</dd>
    +</dl>'''
    +        html = to_html(text, module=self._module, link=self._link)
    +        self.assertEqual(html, expected)
    +
    def test_reST_directives(self)
    -
    -
    -def test_reST_include(self) -
    -
    -
    -
    -
    -def test_urls(self) -
    +
    + +Expand source code +Browse git + +
        def test_reST_directives(self):
    +        expected = '''<div class="admonition todo">
    +<p class="admonition-title">TODO</p>
    +<p>Create something.</p>
    +</div>
    +<div class="admonition admonition">
    +<p class="admonition-title">Example</p>
    +<p>Image shows something.</p>
    +<p><img alt="" src="https://www.debian.org/logos/openlogo-nd-100.png"></p>
    +<div class="admonition note">
    +<p class="admonition-title">Note</p>
    +<p>Can only nest admonitions two levels.</p>
    +</div>
    +</div>
    +<p><img alt="" src="https://www.debian.org/logos/openlogo-nd-100.png"></p>
    +<p>Now you know.</p>
    +<div class="admonition warning">
    +<p class="admonition-title">Warning</p>
    +<p>Some warning
    +lines.</p>
    +</div>
    +<ul>
    +<li>
    +<p>Describe some func in a list
    +  across multiple lines:</p>
    +<div class="admonition deprecated">
    +<p class="admonition-title">Deprecated since version:&ensp;3.1</p>
    +<p>Use <code>spam</code> instead.</p>
    +</div>
    +<div class="admonition versionadded">
    +<p class="admonition-title">Added in version:&ensp;2.5</p>
    +<p>The <em>spam</em> parameter.</p>
    +</div>
    +</li>
    +</ul>
    +<div class="admonition caution">
    +<p class="admonition-title">Caution</p>
    +<p>Don't touch this!</p>
    +</div>'''
    +        text = inspect.getdoc(self._docmodule.reST_directives)
    +        html = to_html(text, module=self._module, link=self._link)
    +        self.assertEqual(html, expected)
    +
    + +
    +def test_reST_include(self) +
    +
    +
    +
    + +Expand source code +Browse git + +
        def test_reST_include(self):
    +        expected = '''<pre><code class="language-python">    x = 2
    +</code></pre>
    +<p>1
    +x = 2
    +x = 3
    +x =</p>
    +<table>
    +<thead>
    +<tr>
    +<th>Name</th>
    +<th>Value</th>
    +</tr>
    +</thead>
    +<tbody>
    +<tr>
    +<td>Hello</td>
    +<td>World</td>
    +</tr>
    +</tbody>
    +</table>
    +<p>Remaining.</p>'''
    +        mod = pdoc.Module(pdoc.import_module(
    +            os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE, '_reST_include', 'test.py')))
    +        html = to_html(mod.docstring, module=mod)
    +        self.assertEqual(html, expected)
    +
    +        # Ensure includes are resolved within docstrings already,
    +        # e.g. for `pdoc.html_helpers.extract_toc()` to work
    +        self.assertIn('Command-line interface',
    +                      self._module.docstring)
    +
    +
    +
    +def test_urls(self) +
    +
    + +Expand source code +Browse git + +
        def test_urls(self):
    +        text = """Beautiful Soup
    +<a href="https://travis-ci.org/cs01/pygdbmi"><img src="https://foo" /></a>
    +<https://foo.bar>
    +Work [like this](http://foo/) and [like that].
    +[like that]: ftp://bar
    +data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
    +```
    +http://url.com
    +```
    +[https://google.com](https://google.com)
    +[https://en.wikipedia.org/wiki/Orange_(software)](https://en.wikipedia.org/wiki/Orange_(software))
    +[Check https://google.com here](https://google.com)
    +`https://google.com`
    +
    +http://www.foo.bar
    +http://www.foo.bar?q="foo"
    +https://en.wikipedia.org/wiki/Orange_(software)
    +(https://google.com)
    +(http://foo and http://bar)
    +text ``x ` http://foo`` http://bar `http://foo`
    +"""
    +
    +        expected = """<p>Beautiful Soup
    +<a href="https://travis-ci.org/cs01/pygdbmi"><img src="https://foo" /></a>
    +<a href="https://foo.bar">https://foo.bar</a>
    +Work <a href="http://foo/">like this</a> and <a href="ftp://bar">like that</a>.</p>
    +<p>data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D</p>
    +<pre><code>http://url.com
    +</code></pre>
    +<p><a href="https://google.com">https://google.com</a>
    +<a href="https://en.wikipedia.org/wiki/Orange_(software)">\
    +https://en.wikipedia.org/wiki/Orange_(software)</a>
    +<a href="https://google.com">Check https://google.com here</a>
    +<code>https://google.com</code></p>
    +<p><a href="http://www.foo.bar">http://www.foo.bar</a>
    +<a href="http://www.foo.bar?q=&quot;foo&quot;">http://www.foo.bar?q="foo"</a>
    +<a href="https://en.wikipedia.org/wiki/Orange_(software)">\
    +https://en.wikipedia.org/wiki/Orange_(software)</a>
    +(<a href="https://google.com">https://google.com</a>)
    +(<a href="http://foo">http://foo</a> and <a href="http://bar">http://bar</a>)
    +text <code>x ` http://foo</code> <a href="http://bar">http://bar</a> <code>http://foo</code></p>"""
    +
    +        html = to_html(text)
    +        self.assertEqual(html, expected)
    +
    @@ -2084,7 +3909,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class HtmlHelpersTest(unittest.TestCase):
         """
    @@ -2252,48 +4077,238 @@ 

    Methods

    +
    + +Expand source code +Browse git + +
        def test_extract_toc(self):
    +        text = '''xxx
    +
    +# Title
    +
    +>>> # doctests skipped
    +# doctest output, skipped
    +
    +## Subtitle
    +
    +```
    +>>> # code skipped
    +# skipped
    +```
    +
    +# Title 2
    +
    +```
    +>>> # code skipped
    +# skipped
    +```
    +
    +## Subtitle 2
    +'''
    +        expected = '''<div class="toc">
    +<ul>
    +<li><a href="#title">Title</a><ul>
    +<li><a href="#subtitle">Subtitle</a></li>
    +</ul>
    +</li>
    +<li><a href="#title-2">Title 2</a><ul>
    +<li><a href="#subtitle-2">Subtitle 2</a></li>
    +</ul>
    +</li>
    +</ul>
    +</div>'''
    +        toc = extract_toc(text)
    +        self.assertEqual(toc, expected)
    +
    +
    + +Expand source code +Browse git + +
    @unittest.skipIf(shutil.which("git") is None or not os.path.exists('.git'),
    +                 "git not installed or we're not within git repo")
    +def test_format_git_link(self):
    +    url = format_git_link(
    +        template='https://github.com/pdoc3/pdoc/blob/{commit}/{path}#L{start_line}-L{end_line}',
    +        dobj=EXAMPLE_PDOC_MODULE.find_ident('module.foo'),
    +    )
    +    self.assertIsInstance(url, str)
    +    self.assertRegex(url, r"https://github.com/pdoc3/pdoc/blob/[0-9a-f]{40}"
    +                          r"/pdoc/test/example_pkg/module.py#L\d+-L\d+")
    +
    def test_glimpse(self)
    +
    + +Expand source code +Browse git + +
    def test_glimpse(self):
    +    text = 'foo bar\n\nbaz'
    +    self.assertEqual(glimpse(text), 'foo bar …')
    +    self.assertEqual(glimpse(text, max_length=8, paragraph=False), 'foo …')
    +    self.assertEqual(glimpse('Foo bar\n-------'), 'Foo bar')
    +
    def test_minify_css(self)
    +
    + +Expand source code +Browse git + +
    def test_minify_css(self):
    +    css = 'a { color: white; } /*comment*/ b {;}'
    +    minified = minify_css(css)
    +    self.assertNotIn(' ', minified)
    +    self.assertNotIn(';}', minified)
    +    self.assertNotIn('*', minified)
    +
    def test_minify_html(self)
    +
    + +Expand source code +Browse git + +
    def test_minify_html(self):
    +    html = '  <p>   a   </p>    <pre>    a\n    b</pre>    c   \n    d   '
    +    expected = '\n<p>\na\n</p>\n<pre>    a\n    b</pre>\nc\nd\n'
    +    minified = minify_html(html)
    +    self.assertEqual(minified, expected)
    +
    def test_to_html(self)
    +
    + +Expand source code +Browse git + +
        def test_to_html(self):
    +        text = '''# Title
    +
    +`pdoc.Module` is a `Doc`, not `dict`.
    +
    +ref with underscore: `_x_x_`
    +
    +```
    +code block
    +```
    +reference: `package.foo`
    +'''
    +        expected = '''<h1 id="title">Title</h1>
    +<p><code><a href="#pdoc.Module">Module</a></code> is a <code><a href="#pdoc.Doc">Doc</a></code>,\
    + not <code>dict</code>.</p>
    +<p>ref with underscore: <code><a href="#pdoc._x_x_">_x_x_</a></code></p>
    +<pre><code>code block
    +</code></pre>
    +<p>reference: <code><a href="/package.foo.ext">package.foo</a></code></p>'''
    +
    +        module = PDOC_PDOC_MODULE
    +        module.doc['_x_x_'] = pdoc.Variable('_x_x_', module, '')
    +
    +        def link(dobj):
    +            return f'<a href="{dobj.url(relative_to=module)}">{dobj.qualname}</a>'
    +
    +        html = to_html(text, module=module, link=link)
    +        self.assertEqual(html, expected)
    +
    +        self.assertEqual(to_html('`pdoc.Doc.url()`', module=module, link=link),
    +                         '<p><code><a href="#pdoc.Doc.url">Doc.url</a></code></p>')
    +
    +        self.assertEqual(to_html('`foo.f()`', module=module, link=link),
    +                         '<p><code><a href="/foo.f().ext">foo.f()</a></code></p>')
    +
    def test_to_html_refname(self)
    +
    + +Expand source code +Browse git + +
        def test_to_html_refname(self):
    +        text = '''
    +[`pdoc` x][pdoc] `pdoc`
    +[x `pdoc`][pdoc] `[pdoc]()`
    +
    +`__x__`
    +
    +[`pdoc`](#)
    +[``pdoc` ``](#)
    +[```pdoc```](#)
    +
    +```
    +pdoc
    +```
    +
    +[pdoc]: #pdoc
    +'''
    +        expected = '''\
    +<p><a href="#pdoc"><code>pdoc</code> x</a> <code><a>pdoc</a></code>
    +<a href="#pdoc">x <code>pdoc</code></a> <code>[<a>pdoc</a>]()</code></p>
    +<p><code>__x__</code></p>
    +<p><a href="#"><code>pdoc</code></a>
    +<a href="#"><code>pdoc`</code></a>
    +<a href="#"><code>pdoc</code></a></p>
    +<pre><code>pdoc
    +</code></pre>\
    +'''
    +
    +        def link(dobj):
    +            return f'<a>{dobj.qualname}</a>'
    +
    +        html = to_html(text, module=PDOC_PDOC_MODULE, link=link)
    +        self.assertEqual(html, expected)
    +
    def test_to_html_refname_warning(self)
    +
    + +Expand source code +Browse git + +
    def test_to_html_refname_warning(self):
    +    mod = EXAMPLE_PDOC_MODULE
    +
    +    def f():
    +        """Reference to some `example_pkg.nonexisting` object"""
    +
    +    mod.doc['__f'] = pdoc.Function('__f', mod, f)
    +    with self.assertWarns(ReferenceWarning) as cm:
    +        mod.html()
    +    del mod.doc['__f']
    +    self.assertIn('example_pkg.nonexisting', cm.warning.args[0])
    +
    @@ -2309,7 +4324,7 @@

    Methods

    Expand source code -Browse git +Browse git
    @unittest.skipIf('win' in sys.platform, "signal.SIGALRM doesn't work on Windos")
     class HttpTest(unittest.TestCase):
    @@ -2401,18 +4416,68 @@ 

    Methods

    +
    + +Expand source code +Browse git + +
    def test_file(self):
    +    with chdir(os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE)):
    +        with self._http(['_relative_import']) as url:
    +            with urlopen(url, timeout=3) as resp:
    +                html = resp.read()
    +                self.assertIn(b'<a href="/_relative_import">', html)
    +
    def test_head(self)
    +
    + +Expand source code +Browse git + +
    def test_head(self):
    +    with self._http(['pdoc']) as url:
    +        with urlopen(Request(url + 'pdoc/',
    +                             method='HEAD',
    +                             headers={'If-None-Match': 'xxx'})) as resp:
    +            self.assertEqual(resp.status, 205)
    +        with self.assertRaises(HTTPError) as cm:
    +            urlopen(Request(url + 'pdoc/',
    +                            method='HEAD',
    +                            headers={'If-None-Match': str(os.stat(pdoc.__file__).st_mtime)}))
    +        self.assertEqual(cm.exception.code, 304)
    +
    def test_http(self)
    +
    + +Expand source code +Browse git + +
    def test_http(self):
    +    with self._http(['pdoc', os.path.join(TESTS_BASEDIR, EXAMPLE_MODULE)]) as url:
    +        with self.subTest(url='/'):
    +            with urlopen(url, timeout=3) as resp:
    +                html = resp.read()
    +                self.assertIn(b'Python package <code>pdoc</code>', html)
    +                self.assertNotIn(b'gzip', html)
    +        with self.subTest(url='/' + EXAMPLE_MODULE):
    +            with urlopen(url + 'pdoc', timeout=3) as resp:
    +                html = resp.read()
    +                self.assertIn(b'__pdoc__', html)
    +        with self.subTest(url='/csv.ext'):
    +            with urlopen(url + 'csv.ext', timeout=3) as resp:
    +                html = resp.read()
    +                self.assertIn(b'DictReader', html)
    +
    @@ -2572,7 +4637,7 @@

    HttpTest<