Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
05708aa
Support for online source links
dhimmel Aug 29, 2019
5e9cfbe
Activate online_source_link in doc/build.sh
dhimmel Aug 29, 2019
a46ecf3
Separate online_source_link from show_source_code in html.mako
dhimmel Aug 29, 2019
3b6af2f
html.mako: terminate if statement
dhimmel Aug 29, 2019
8dbd53d
Quote online_source_link --config
dhimmel Aug 29, 2019
d8fec0a
Set online_source_link as none in config.mako
dhimmel Aug 29, 2019
b998fb2
Log exception for debugging
dhimmel Aug 29, 2019
af15129
file_path to path
dhimmel Aug 29, 2019
d51d2af
simplify html_helpers
dhimmel Aug 29, 2019
d11a0db
Some review revisions. _get_head_commit warnings
dhimmel Aug 30, 2019
df061c1
Use warnings not logging
dhimmel Aug 30, 2019
a03dbba
Merge branch 'master' into online-source-links
dhimmel Sep 3, 2019
850d3b7
Easy revisions based on PR review
dhimmel Sep 3, 2019
1dd8404
get_repo_link_template: get commit only if needed
dhimmel Sep 3, 2019
274b6d7
_project_relative_path function
dhimmel Sep 3, 2019
4213b6d
Do not insert empty link
dhimmel Sep 3, 2019
83d3ffe
Show source / repo side-by-side display
dhimmel Sep 3, 2019
ca0e07e
inspect.unwrap to fix double decorator error
dhimmel Sep 8, 2019
5af382f
Update broken mathjax docs link
dhimmel Sep 8, 2019
447cbf8
BUG: fix off-by-one error
kernc Sep 14, 2019
7d544ba
ENH: more robust project root dir detection. fallback to cwd
kernc Sep 14, 2019
4659cf9
REF: shift code around just a bit
kernc Sep 14, 2019
cd8d401
DOC: reword documentation, more example presets
kernc Sep 14, 2019
b1da5fd
REF: modify html/css
kernc Sep 14, 2019
29ec805
MNT: move pdoc config overrides into a config.mako file
kernc Sep 14, 2019
8edf3fe
TST: get_repo_link on example module
dhimmel Sep 16, 2019
b5fd1ed
REF: "repo_link" -> "git_link"; "Browse git" :-=)
kernc Sep 26, 2019
5f0d508
TST: robuster regex
kernc Sep 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/pdoc_template/config.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%!

git_link_template = 'https://github.com/pdoc3/pdoc/blob/{commit}/{path}#L{start_line}-L{end_line}'

%>
2 changes: 1 addition & 1 deletion pdoc/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ or, alternatively, use [raw string literals].
[Google-style]: http://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
[reST directives]: #supported-rest-directives
[template config]: #custom-templates
[recognized delimiters]: http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-math-delimiters
[recognized delimiters]: https://docs.mathjax.org/en/latest/input/tex/delimiters.html
[raw string literals]: https://www.journaldev.com/23598/python-raw-string


Expand Down
97 changes: 96 additions & 1 deletion pdoc/html_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
Helper functions for HTML output.
"""
import inspect
import os.path
import os
import re
import subprocess
import traceback
from functools import partial, lru_cache
from typing import Callable, Match
from warnings import warn
Expand Down Expand Up @@ -430,3 +432,96 @@ def extract_toc(text: str):
if toc.endswith('<p>'): # CUT was put into its own paragraph
toc = toc[:-3].rstrip()
return toc


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()
abs_path = inspect.getfile(inspect.unwrap(dobj.obj))
path = _project_relative_path(abs_path)
lines, start_line = inspect.getsourcelines(dobj.obj)
end_line = start_line + len(lines) - 1
url = template.format(**locals())
return url
except Exception:
warn('format_git_link for {} failed:\n{}'.format(dobj.obj, traceback.format_exc()))
return None


@lru_cache()
def _git_head_commit():
"""
If the working directory is part of a git repository, return the
head git commit hash. Otherwise, raise a CalledProcessError.
"""
process_args = ['git', 'rev-parse', 'HEAD']
try:
commit = subprocess.check_output(process_args, universal_newlines=True).strip()
return commit
except OSError as error:
warn("git executable not found on system:\n{}".format(error))
except subprocess.CalledProcessError as error:
warn(
"Ensure pdoc is run within a git repository.\n"
"`{}` failed with output:\n{}"
.format(' '.join(process_args), error.output)
)
return None


@lru_cache()
def _git_project_root():
"""
Return the path to project root directory or None if indeterminate.
"""
path = None
for cmd in (['git', 'rev-parse', '--show-superproject-working-tree'],
['git', 'rev-parse', '--show-toplevel']):
try:
path = subprocess.check_output(cmd, universal_newlines=True).rstrip('\r\n')
if path:
break
except (subprocess.CalledProcessError, OSError):
pass
return path


@lru_cache()
def _project_relative_path(absolute_path):
"""
Convert an absolute path of a python source file to a project-relative path.
Assumes the project's path is either the current working directory or
Python library installation.
"""
from distutils.sysconfig import get_python_lib
for prefix_path in (_git_project_root() or os.getcwd(),
get_python_lib()):
common_path = os.path.commonpath([prefix_path, absolute_path])
if common_path == prefix_path:
# absolute_path is a descendant of prefix_path
return os.path.relpath(absolute_path, prefix_path)
raise RuntimeError(
"absolute path {!r} is not a descendant of the current working directory "
"or of the system's python library."
.format(absolute_path)
)


@lru_cache()
def _str_template_fields(template):
"""
Return a list of `str.format` field names in a template string.
"""
from string import Formatter
return [
field_name
for _, field_name, _, _ in Formatter().parse(template)
if field_name is not None
]
9 changes: 9 additions & 0 deletions pdoc/templates/config.mako
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
# Disabling this can improve rendering speed of large modules.
show_source_code = True

# If set, format links to objects in online source code repository
# according to this template. Supported keywords for interpolation
# are: commit, path, start_line, end_line.
#git_link_template = 'https://github.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}'
#git_link_template = 'https://gitlab.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}'
#git_link_template = 'https://bitbucket.org/USER/PROJECT/src/{commit}/{path}#lines-{start_line}:{end_line}'
#git_link_template = 'https://CGIT_HOSTNAME/PROJECT/tree/{path}?id={commit}#n{start-line}'
git_link_template = None

# A prefix to use for every HTML hyperlink in the generated documentation.
# No prefix results in all links being relative.
link_prefix = ''
Expand Down
12 changes: 10 additions & 2 deletions pdoc/templates/css.mako
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,22 @@
background: inherit; /* Don't grey-back parameters */
}

.source summary {
.source summary,
.git-link-div {
color: #666;
text-align: right;
font-weight: 400;
font-size: .8em;
text-transform: uppercase;
cursor: pointer;
}
.source summary > * {
white-space: nowrap;
cursor: pointer;
}
.git-link {
color: inherit;
margin-left: 1em;
}
.source pre {
max-height: 500px;
overflow: auto;
Expand Down
22 changes: 16 additions & 6 deletions pdoc/templates/html.mako
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os

import pdoc
from pdoc.html_helpers import extract_toc, glimpse, to_html as _to_html
from pdoc.html_helpers import extract_toc, glimpse, to_html as _to_html, format_git_link


def link(d, name=None, fmt='{}'):
Expand All @@ -21,12 +21,22 @@
<%def name="ident(name)"><span class="ident">${name}</span></%def>

<%def name="show_source(d)">
% if show_source_code and d.source and d.obj is not getattr(d.inherits, 'obj', None):
<details class="source">
<summary>Source code</summary>
<pre><code class="python">${d.source | h}</code></pre>
</details>
% if (show_source_code or git_link_template) and d.source and d.obj is not getattr(d.inherits, 'obj', None):
<% git_link = format_git_link(git_link_template, d) %>
% if show_source_code:
<details class="source">
<summary>
<span>Expand source code</span>
% if git_link:
<a href="${git_link}" class="git-link">Browse git</a>
%endif
</summary>
<pre><code class="python">${d.source | h}</code></pre>
</details>
% elif git_link:
<div class="git-link-div"><a href="${git_link}" class="git-link">Browse git</a></div>
%endif
%endif
</%def>

<%def name="show_desc(d, short=False)">
Expand Down
12 changes: 11 additions & 1 deletion pdoc/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import inspect
import os
import shutil
import signal
import sys
import threading
Expand All @@ -26,7 +27,7 @@
from pdoc.cli import main, parser
from pdoc.html_helpers import (
minify_css, minify_html, glimpse, to_html,
ReferenceWarning, extract_toc,
ReferenceWarning, extract_toc, format_git_link,
)

TESTS_BASEDIR = os.path.abspath(os.path.dirname(__file__) or '.')
Expand Down Expand Up @@ -790,6 +791,15 @@ def test_extract_toc(self):
toc = extract_toc(text)
self.assertEqual(toc, expected)

@unittest.skipIf(shutil.which("git") is None, reason="test assumes git installed on system")
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=pdoc.Module(EXAMPLE_MODULE).find_ident('module.foo'),
)
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+")


class Docformats(unittest.TestCase):
@classmethod
Expand Down