Skip to content

Commit 57f7e5b

Browse files
authored
Merge pull request #969 from seeM/fix-showdoc-numpy
fix: `show_doc` includes parsed sections from numpy docstrings
2 parents 26ab9d4 + 2e761f6 commit 57f7e5b

File tree

3 files changed

+50
-71
lines changed

3 files changed

+50
-71
lines changed

nbdev/_modidx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@
281281
'nbdev.showdoc.ShowDocRenderer': ('09_API/showdoc.html#showdocrenderer', 'nbdev/showdoc.py'),
282282
'nbdev.showdoc.ShowDocRenderer.__init__': ('09_API/showdoc.html#__init__', 'nbdev/showdoc.py'),
283283
'nbdev.showdoc._bold': ('09_API/showdoc.html#_bold', 'nbdev/showdoc.py'),
284-
'nbdev.showdoc._escape_fn': ('09_API/showdoc.html#_escape_fn', 'nbdev/showdoc.py'),
285-
'nbdev.showdoc._escape_pipe': ('09_API/showdoc.html#_escape_pipe', 'nbdev/showdoc.py'),
284+
'nbdev.showdoc._docstring': ('09_API/showdoc.html#_docstring', 'nbdev/showdoc.py'),
285+
'nbdev.showdoc._escape_markdown': ('09_API/showdoc.html#_escape_markdown', 'nbdev/showdoc.py'),
286286
'nbdev.showdoc._ext_link': ('09_API/showdoc.html#_ext_link', 'nbdev/showdoc.py'),
287287
'nbdev.showdoc._f_name': ('09_API/showdoc.html#_f_name', 'nbdev/showdoc.py'),
288288
'nbdev.showdoc._fmt_anno': ('09_API/showdoc.html#_fmt_anno', 'nbdev/showdoc.py'),

nbdev/showdoc.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,19 @@ def _non_empty_keys(d:dict): return L([k for k,v in d.items() if v != inspect._e
2626
def _bold(s): return f'**{s}**' if s.strip() else s
2727

2828
# %% ../nbs/09_API/08_showdoc.ipynb 7
29-
def _escape_pipe(s): return re.sub(r'(\\)?\|', '\|', s)
29+
def _escape_markdown(s):
30+
for c in '|^': s = re.sub(rf'\\?\{c}', f'\{c}', s)
31+
return s.replace('\n', '<br>')
3032

3133
# %% ../nbs/09_API/08_showdoc.ipynb 9
32-
def _escape_fn(s): return re.sub(r'(?<!\\)\^\[', '\^[', s)
33-
34-
# %% ../nbs/09_API/08_showdoc.ipynb 11
3534
def _maybe_nm(o):
3635
if (o == inspect._empty): return ''
37-
else: return o.__name__ if hasattr(o, '__name__') else _escape_fn(_escape_pipe(str(o)))
36+
else: return o.__name__ if hasattr(o, '__name__') else _escape_markdown(str(o))
3837

39-
# %% ../nbs/09_API/08_showdoc.ipynb 13
38+
# %% ../nbs/09_API/08_showdoc.ipynb 11
4039
def _list2row(l:list): return '| '+' | '.join([_maybe_nm(o) for o in l]) + ' |'
4140

42-
# %% ../nbs/09_API/08_showdoc.ipynb 15
41+
# %% ../nbs/09_API/08_showdoc.ipynb 13
4342
class DocmentTbl:
4443
# this is the column order we want these items to appear
4544
_map = OrderedDict({'anno':'Type', 'default':'Default', 'docment':'Details'})
@@ -109,7 +108,12 @@ def __eq__(self,other): return self.__str__() == str(other).strip()
109108
__str__ = _repr_markdown_
110109
__repr__ = basic_repr()
111110

112-
# %% ../nbs/09_API/08_showdoc.ipynb 30
111+
# %% ../nbs/09_API/08_showdoc.ipynb 28
112+
def _docstring(sym):
113+
npdoc = parse_docstring(sym)
114+
return '\n\n'.join([npdoc['Summary'], npdoc['Extended']]).strip()
115+
116+
# %% ../nbs/09_API/08_showdoc.ipynb 29
113117
def _fullname(o):
114118
module,name = getattr(o, "__module__", None),qual_name(o)
115119
return name if module is None or module in ('__main__','builtins') else module + '.' + name
@@ -124,13 +128,13 @@ def __init__(self, sym, name:str|None=None, title_level:int=3):
124128
self.isfunc = inspect.isfunction(sym)
125129
try: self.sig = signature_ex(sym, eval_str=True)
126130
except (ValueError,TypeError): self.sig = None
127-
self.docs = docstring(sym)
131+
self.docs = _docstring(sym)
128132
self.dm = DocmentTbl(sym)
129133
self.fn = _fullname(sym)
130134

131135
__repr__ = basic_repr()
132136

133-
# %% ../nbs/09_API/08_showdoc.ipynb 31
137+
# %% ../nbs/09_API/08_showdoc.ipynb 30
134138
def _f_name(o): return f'<function {o.__name__}>' if isinstance(o, FunctionType) else None
135139
def _fmt_anno(o): return inspect.formatannotation(o).strip("'").replace(' ','')
136140

@@ -143,7 +147,7 @@ def _show_param(param):
143147
if default is not inspect._empty: res += f'={_f_name(default) or repr(default)}'
144148
return res
145149

146-
# %% ../nbs/09_API/08_showdoc.ipynb 33
150+
# %% ../nbs/09_API/08_showdoc.ipynb 32
147151
def _fmt_sig(sig):
148152
if sig is None: return ''
149153
p = {k:v for k,v in sig.parameters.items()}
@@ -156,7 +160,7 @@ def _wrap_sig(s):
156160
indent = pad + ' ' * (s.find('(') + 1)
157161
return fill(s, width=80, initial_indent=pad, subsequent_indent=indent)
158162

159-
# %% ../nbs/09_API/08_showdoc.ipynb 35
163+
# %% ../nbs/09_API/08_showdoc.ipynb 34
160164
def _ext_link(url, txt, xtra=""): return f'[{txt}]({url}){{target="_blank" {xtra}}}'
161165

162166
class BasicMarkdownRenderer(ShowDocRenderer):
@@ -174,7 +178,7 @@ def _repr_markdown_(self):
174178
return doc
175179
__repr__=__str__=_repr_markdown_
176180

177-
# %% ../nbs/09_API/08_showdoc.ipynb 36
181+
# %% ../nbs/09_API/08_showdoc.ipynb 35
178182
def show_doc(sym, # Symbol to document
179183
renderer=None, # Optional renderer (defaults to markdown)
180184
name:str|None=None, # Optionally override displayed name of `sym`
@@ -188,7 +192,7 @@ def show_doc(sym, # Symbol to document
188192
if isinstance(sym, TypeDispatch): pass
189193
else:return renderer(sym or show_doc, name=name, title_level=title_level)
190194

191-
# %% ../nbs/09_API/08_showdoc.ipynb 52
195+
# %% ../nbs/09_API/08_showdoc.ipynb 51
192196
def _html_link(url, txt): return f'<a href="{url}" target="_blank" rel="noreferrer noopener">{txt}</a>'
193197

194198
class BasicHtmlRenderer(ShowDocRenderer):
@@ -208,17 +212,17 @@ def doc(self):
208212
if docs is not None: res += '\n<p>' +_html_link(docs, "Show in docs") + '</p>'
209213
display(HTML(res))
210214

211-
# %% ../nbs/09_API/08_showdoc.ipynb 53
215+
# %% ../nbs/09_API/08_showdoc.ipynb 52
212216
def doc(elt):
213217
"Show `show_doc` info along with link to docs"
214218
BasicHtmlRenderer(elt).doc()
215219

216-
# %% ../nbs/09_API/08_showdoc.ipynb 59
220+
# %% ../nbs/09_API/08_showdoc.ipynb 58
217221
def showdoc_nm(tree):
218222
"Get the fully qualified name for showdoc."
219223
return ifnone(patch_name(tree), tree.name)
220224

221-
# %% ../nbs/09_API/08_showdoc.ipynb 63
225+
# %% ../nbs/09_API/08_showdoc.ipynb 62
222226
def colab_link(path):
223227
"Get a link to the notebook at `path` on Colab"
224228
from IPython.display import Markdown

nbs/09_API/08_showdoc.ipynb

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
},
1313
{
1414
"cell_type": "markdown",
15-
"id": "04b59a7c",
15+
"id": "1b5b9e13",
1616
"metadata": {},
1717
"source": [
1818
"# showdoc\n",
@@ -86,12 +86,14 @@
8686
{
8787
"cell_type": "code",
8888
"execution_count": null,
89-
"id": "ff688058",
89+
"id": "d6d55b8a",
9090
"metadata": {},
9191
"outputs": [],
9292
"source": [
9393
"#|export\n",
94-
"def _escape_pipe(s): return re.sub(r'(\\\\)?\\|', '\\|', s)"
94+
"def _escape_markdown(s):\n",
95+
" for c in '|^': s = re.sub(rf'\\\\?\\{c}', f'\\{c}', s)\n",
96+
" return s.replace('\\n', '<br>')"
9597
]
9698
},
9799
{
@@ -102,32 +104,12 @@
102104
"outputs": [],
103105
"source": [
104106
"#|hide\n",
105-
"test_eq(_escape_pipe('|'), '\\|')\n",
106-
"test_eq(_escape_pipe('\\|'), '\\|')"
107-
]
108-
},
109-
{
110-
"cell_type": "code",
111-
"execution_count": null,
112-
"id": "75d3bf23-b88a-4ba0-afd9-df3c50be98a1",
113-
"metadata": {},
114-
"outputs": [],
115-
"source": [
116-
"#|export\n",
117-
"def _escape_fn(s): return re.sub(r'(?<!\\\\)\\^\\[', '\\^[', s)"
118-
]
119-
},
120-
{
121-
"cell_type": "code",
122-
"execution_count": null,
123-
"id": "5a63bb29-30d0-4851-b5fa-cc319e8e6af9",
124-
"metadata": {},
125-
"outputs": [],
126-
"source": [
127-
"#|hide\n",
128-
"test_eq(_escape_fn(' ^[_'), ' \\^[_')\n",
129-
"test_eq(_escape_fn('foo ^[_'), 'foo \\^[_')\n",
130-
"test_eq(_escape_fn(' \\^[_'), ' \\^[_') #if it is already escaped leave it alone"
107+
"test_eq(_escape_markdown('|'), '\\|')\n",
108+
"test_eq(_escape_markdown('\\|'), '\\|')\n",
109+
"test_eq(_escape_markdown(' ^[_'), ' \\^[_') # footnotes\n",
110+
"test_eq(_escape_markdown('foo ^[_'), 'foo \\^[_')\n",
111+
"test_eq(_escape_markdown(' \\^[_'), ' \\^[_') #if it is already escaped leave it alone\n",
112+
"test_eq(_escape_markdown('a long\\nsentence'), 'a long<br>sentence')"
131113
]
132114
},
133115
{
@@ -140,7 +122,7 @@
140122
"#|export\n",
141123
"def _maybe_nm(o): \n",
142124
" if (o == inspect._empty): return ''\n",
143-
" else: return o.__name__ if hasattr(o, '__name__') else _escape_fn(_escape_pipe(str(o)))"
125+
" else: return o.__name__ if hasattr(o, '__name__') else _escape_markdown(str(o))"
144126
]
145127
},
146128
{
@@ -506,6 +488,19 @@
506488
"Render the signature as well as the `docments` to show complete documentation for an object."
507489
]
508490
},
491+
{
492+
"cell_type": "code",
493+
"execution_count": null,
494+
"id": "cae94920",
495+
"metadata": {},
496+
"outputs": [],
497+
"source": [
498+
"#|export\n",
499+
"def _docstring(sym):\n",
500+
" npdoc = parse_docstring(sym)\n",
501+
" return '\\n\\n'.join([npdoc['Summary'], npdoc['Extended']]).strip()"
502+
]
503+
},
509504
{
510505
"cell_type": "code",
511506
"execution_count": null,
@@ -528,7 +523,7 @@
528523
" self.isfunc = inspect.isfunction(sym)\n",
529524
" try: self.sig = signature_ex(sym, eval_str=True)\n",
530525
" except (ValueError,TypeError): self.sig = None\n",
531-
" self.docs = docstring(sym)\n",
526+
" self.docs = _docstring(sym)\n",
532527
" self.dm = DocmentTbl(sym)\n",
533528
" self.fn = _fullname(sym)\n",
534529
"\n",
@@ -700,16 +695,6 @@
700695
"\n",
701696
"This is another line of the docstring.\n",
702697
"\n",
703-
"Parameters\n",
704-
"----------\n",
705-
"x : int\n",
706-
" the parameter x\n",
707-
" \n",
708-
"Returns\n",
709-
"-------\n",
710-
"None\n",
711-
" this function doesn't return anything\n",
712-
"\n",
713698
"| | **Type** | **Default** | **Details** |\n",
714699
"| -- | -------- | ----------- | ----------- |\n",
715700
"| x | int | 1 | the parameter x |\n",
@@ -726,16 +711,6 @@
726711
"\n",
727712
"This is another line of the docstring.\n",
728713
"\n",
729-
"Parameters\n",
730-
"----------\n",
731-
"x : int\n",
732-
" the parameter x\n",
733-
" \n",
734-
"Returns\n",
735-
"-------\n",
736-
"None\n",
737-
" this function doesn't return anything\n",
738-
"\n",
739714
"| | **Type** | **Default** | **Details** |\n",
740715
"| -- | -------- | ----------- | ----------- |\n",
741716
"| x | int | 1 | the parameter x |\n",
@@ -1035,7 +1010,7 @@
10351010
"<hr/>\n",
10361011
"<h3>show_doc</h3>\n",
10371012
"<blockquote><pre><code>show_doc(sym, renderer=None, name:Optional[str]=None, title_level:int=3)</code></pre></blockquote><p>Show signature and docstring for `sym`</p>\n",
1038-
"<p><a href=\"https://nbdev.fast.ai//showdoc.html#show_doc\" target=\"_blank\" rel=\"noreferrer noopener\">Show in docs</a></p>"
1013+
"<p><a href=\"https://nbdev.fast.ai/09_API/showdoc.html#show_doc\" target=\"_blank\" rel=\"noreferrer noopener\">Show in docs</a></p>"
10391014
],
10401015
"text/plain": [
10411016
"<IPython.core.display.HTML object>"

0 commit comments

Comments
 (0)