Skip to content

Commit 2ae3fc0

Browse files
committed
fix showdoc for methods
1 parent f9a1321 commit 2ae3fc0

File tree

7 files changed

+319
-34
lines changed

7 files changed

+319
-34
lines changed

nbprocess/_modidx.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
'nbprocess.showdoc.ShowDocRenderer': 'https://nbprocess.fast.ai/nbprocess.showdoc#ShowDocRenderer',
4545
'nbprocess.showdoc.BasicMarkdownRenderer': 'https://nbprocess.fast.ai/nbprocess.showdoc#BasicMarkdownRenderer',
4646
'nbprocess.showdoc.show_doc': 'https://nbprocess.fast.ai/nbprocess.showdoc#show_doc',
47-
'nbprocess.showdoc.BasicHtmlRenderer': 'https://nbprocess.fast.ai/nbprocess.showdoc#BasicHtmlRenderer'},
47+
'nbprocess.showdoc.BasicHtmlRenderer': 'https://nbprocess.fast.ai/nbprocess.showdoc#BasicHtmlRenderer',
48+
'nbprocess.showdoc.get_patch_name': 'https://nbprocess.fast.ai/nbprocess.showdoc#get_patch_name'},
4849
'nbprocess.imports': {},
4950
'nbprocess.cli': { 'nbprocess.cli.nbprocess_ghp_deploy': 'https://nbprocess.fast.ai/nbprocess.cli#nbprocess_ghp_deploy',
5051
'nbprocess.cli.nbprocess_sidebar': 'https://nbprocess.fast.ai/nbprocess.cli#nbprocess_sidebar',

nbprocess/processors.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .imports import *
1212
from .process import *
1313
from .lookup import *
14+
from .showdoc import *
1415

1516
from fastcore.imports import *
1617
from fastcore.xtras import *
@@ -135,20 +136,25 @@ def insert_warning(nb):
135136
# %% ../nbs/09_processors.ipynb 40
136137
_def_types = (ast.FunctionDef,ast.AsyncFunctionDef,ast.ClassDef)
137138
def _def_names(cell, shown):
138-
return [o.name for o in concat(cell.parsed_()) if isinstance(o,_def_types) and o.name not in shown and o.name[0]!='_']
139+
return [get_patch_name(o) for o in concat(cell.parsed_()) if isinstance(o,_def_types) and o.name not in shown and o.name[0]!='_']
139140

140141
# %% ../nbs/09_processors.ipynb 41
142+
def _get_nm(tree):
143+
i = tree.value.args[0]
144+
return f'{i.value.id}.{i.attr}' if isinstance(i, ast.Attribute) else i.id
145+
146+
# %% ../nbs/09_processors.ipynb 42
141147
def add_show_docs(nb):
142148
"Add show_doc cells after exported cells, unless they are already documented"
143149
exports = L(cell for cell in nb.cells if cell.source and _re_exps(cell.source))
144150
trees = nb.cells.map(NbCell.parsed_).concat()
145-
shown_docs = {t.value.args[0].id for t in _show_docs(trees)}
151+
shown_docs = {_get_nm(t) for t in _show_docs(trees)}
146152
for cell in reversed(exports):
147153
for nm in _def_names(cell, shown_docs):
148154
code = f'show_doc({nm})'
149155
nb.cells.insert(cell.idx_+1, mk_cell(code))
150156

151-
# %% ../nbs/09_processors.ipynb 44
157+
# %% ../nbs/09_processors.ipynb 46
152158
_re_title = re.compile(r'^#\s+(.*)[\n\r](?:^>\s+(.*))?', flags=re.MULTILINE)
153159
_re_fm = re.compile(r'^---.*\S+.*---', flags=re.DOTALL)
154160
_re_defaultexp = re.compile(r'^\s*#\|\s*default_exp\s+(\S+)', flags=re.MULTILINE)

nbprocess/showdoc.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/08_showdoc.ipynb.
22

33
# %% auto 0
4-
__all__ = ['get_name', 'qual_name', 'ShowDocRenderer', 'BasicMarkdownRenderer', 'show_doc', 'BasicHtmlRenderer']
4+
__all__ = ['get_name', 'qual_name', 'ShowDocRenderer', 'BasicMarkdownRenderer', 'show_doc', 'BasicHtmlRenderer', 'get_patch_name']
55

66
# %% ../nbs/08_showdoc.ipynb 3
77
from fastcore.docments import *
@@ -55,11 +55,26 @@ def show_doc(sym, disp=True, renderer=None):
5555
renderer = getattr(import_module(p), m)
5656
return renderer(sym or show_doc, disp=disp)
5757

58-
# %% ../nbs/08_showdoc.ipynb 10
58+
# %% ../nbs/08_showdoc.ipynb 13
5959
class BasicHtmlRenderer(ShowDocRenderer):
6060
def _repr_html_(self):
6161
doc = '<hr/>\n'
6262
lvl = 4 if self.isfunc else 3
6363
doc += f'<h{lvl}>{self.nm}</h{lvl}>\n<blockquote><code>{self.nm}{self.sig}</code></blockquote>'
6464
if self.docs: doc += f"<p>{self.docs}</p>"
6565
return doc
66+
67+
# %% ../nbs/08_showdoc.ipynb 15
68+
def _is_patch(tree):
69+
decs = [d.id for d in getattr(tree, 'decorator_list', []) if hasattr(d, 'id')]
70+
return 'patch' in decs
71+
72+
# %% ../nbs/08_showdoc.ipynb 16
73+
def get_patch_name(tree):
74+
"If a method is defined with @patch, get fully qualified name."
75+
first_arg = first(L(nested_attr(tree, 'args.args')))
76+
if _is_patch(tree) and first_arg.arg == 'self':
77+
annotation = nested_attr(first_arg, 'annotation.id')
78+
if annotation: return f'{annotation}.{tree.name}'
79+
else: return tree.name
80+
else: return tree.name

nbs/08_showdoc.ipynb

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@
119119
" return renderer(sym or show_doc, disp=disp)"
120120
]
121121
},
122+
{
123+
"cell_type": "markdown",
124+
"id": "a38843d9-4fa3-40f3-bb4d-949344b2bdee",
125+
"metadata": {},
126+
"source": [
127+
"You can use `show_doc` to document apis of functions, classes or methods:"
128+
]
129+
},
122130
{
123131
"cell_type": "code",
124132
"execution_count": null,
@@ -137,7 +145,7 @@
137145
"func docstring"
138146
],
139147
"text/plain": [
140-
"<__main__.BasicMarkdownRenderer at 0x7f9bb840bee0>"
148+
"<__main__.BasicMarkdownRenderer at 0x7f9c5abb8340>"
141149
]
142150
},
143151
"execution_count": null,
@@ -153,6 +161,76 @@
153161
"show_doc(f)"
154162
]
155163
},
164+
{
165+
"cell_type": "code",
166+
"execution_count": null,
167+
"id": "1c28ec9d-29ff-497f-97b0-ca262f530cf6",
168+
"metadata": {},
169+
"outputs": [
170+
{
171+
"data": {
172+
"text/markdown": [
173+
"---\n",
174+
"\n",
175+
"### Foo\n",
176+
"\n",
177+
"> **`Foo`**` (e: int)`\n",
178+
"\n",
179+
"This is the docstring for the __init__ method"
180+
],
181+
"text/plain": [
182+
"<__main__.BasicMarkdownRenderer at 0x7f9c48502880>"
183+
]
184+
},
185+
"execution_count": null,
186+
"metadata": {},
187+
"output_type": "execute_result"
188+
}
189+
],
190+
"source": [
191+
"class Foo:\n",
192+
" def __init__(d:str,e:int):\n",
193+
" \"This is the docstring for the __init__ method\"\n",
194+
" ...\n",
195+
"\n",
196+
"show_doc(Foo)"
197+
]
198+
},
199+
{
200+
"cell_type": "code",
201+
"execution_count": null,
202+
"id": "3441e6c7-472b-411c-a179-b1e37dcbceac",
203+
"metadata": {},
204+
"outputs": [
205+
{
206+
"data": {
207+
"text/markdown": [
208+
"---\n",
209+
"\n",
210+
"#### Foo.a_method\n",
211+
"\n",
212+
"> **`Foo.a_method`**` (a: list, b: dict, c)`\n",
213+
"\n",
214+
"This is a method"
215+
],
216+
"text/plain": [
217+
"<__main__.BasicMarkdownRenderer at 0x7f9c48502be0>"
218+
]
219+
},
220+
"execution_count": null,
221+
"metadata": {},
222+
"output_type": "execute_result"
223+
}
224+
],
225+
"source": [
226+
"class Foo:\n",
227+
" def a_method(a:list,b:dict,c):\n",
228+
" \"This is a method\"\n",
229+
" ...\n",
230+
"\n",
231+
"show_doc(Foo.a_method)"
232+
]
233+
},
156234
{
157235
"cell_type": "code",
158236
"execution_count": null,
@@ -184,7 +262,7 @@
184262
"<blockquote><code>F(x: int = 1)</code></blockquote><p>class docstring</p>"
185263
],
186264
"text/plain": [
187-
"<__main__.BasicHtmlRenderer at 0x7f9bb83fdd90>"
265+
"<__main__.BasicHtmlRenderer at 0x7f9c59b4d5b0>"
188266
]
189267
},
190268
"execution_count": null,
@@ -200,6 +278,71 @@
200278
"show_doc(F, renderer=BasicHtmlRenderer)"
201279
]
202280
},
281+
{
282+
"cell_type": "code",
283+
"execution_count": null,
284+
"id": "12c4cf13-56fa-4b47-a62e-7917ab61fa7c",
285+
"metadata": {},
286+
"outputs": [],
287+
"source": [
288+
"#|export\n",
289+
"def _is_patch(tree):\n",
290+
" decs = [d.id for d in getattr(tree, 'decorator_list', []) if hasattr(d, 'id')]\n",
291+
" return 'patch' in decs"
292+
]
293+
},
294+
{
295+
"cell_type": "code",
296+
"execution_count": null,
297+
"id": "35043aa7-6b60-4ddf-8949-39a78577f23d",
298+
"metadata": {},
299+
"outputs": [],
300+
"source": [
301+
"#|export\n",
302+
"def get_patch_name(tree):\n",
303+
" \"If a method is defined with @patch, get fully qualified name.\"\n",
304+
" first_arg = first(L(nested_attr(tree, 'args.args')))\n",
305+
" if _is_patch(tree) and first_arg.arg == 'self':\n",
306+
" annotation = nested_attr(first_arg, 'annotation.id')\n",
307+
" if annotation: return f'{annotation}.{tree.name}'\n",
308+
" else: return tree.name\n",
309+
" else: return tree.name"
310+
]
311+
},
312+
{
313+
"cell_type": "code",
314+
"execution_count": null,
315+
"id": "fe22731d-ad7d-4080-ac91-e0d24e8b681c",
316+
"metadata": {},
317+
"outputs": [],
318+
"source": [
319+
"#|hide\n",
320+
"import ast\n",
321+
"code=\"\"\"\n",
322+
"@bar\n",
323+
"@patch\n",
324+
"@foo\n",
325+
"def a_method(self:Foo, a:list,b:dict,c):\n",
326+
" \"This is a method\"\n",
327+
" ...\n",
328+
"\"\"\"\n",
329+
"\n",
330+
"code2=\"\"\"\n",
331+
"@bar\n",
332+
"@foo\n",
333+
"def a_method(self:Foo, a:list,b:dict,c):\n",
334+
" \"This is a method\"\n",
335+
" ...\n",
336+
"\"\"\"\n",
337+
"\n",
338+
"_tree = ast.parse(code).body[0]\n",
339+
"assert _is_patch(_tree)\n",
340+
"test_eq(get_patch_name(_tree), 'Foo.a_method')\n",
341+
"\n",
342+
"_tree2 = ast.parse(code2).body[0]\n",
343+
"test_eq(get_patch_name(_tree2), 'a_method')"
344+
]
345+
},
203346
{
204347
"cell_type": "markdown",
205348
"id": "ec7a2f01",

nbs/09_processors.ipynb

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"from nbprocess.imports import *\n",
3434
"from nbprocess.process import *\n",
3535
"from nbprocess.lookup import *\n",
36+
"from nbprocess.showdoc import *\n",
3637
"\n",
3738
"from fastcore.imports import *\n",
3839
"from fastcore.xtras import *"
@@ -424,7 +425,8 @@
424425
"metadata": {},
425426
"outputs": [],
426427
"source": [
427-
"res = _run_procs(exec_show_docs)"
428+
"res = _run_procs(exec_show_docs)\n",
429+
"assert res"
428430
]
429431
},
430432
{
@@ -506,7 +508,20 @@
506508
"#|export\n",
507509
"_def_types = (ast.FunctionDef,ast.AsyncFunctionDef,ast.ClassDef)\n",
508510
"def _def_names(cell, shown):\n",
509-
" return [o.name for o in concat(cell.parsed_()) if isinstance(o,_def_types) and o.name not in shown and o.name[0]!='_']"
511+
" return [get_patch_name(o) for o in concat(cell.parsed_()) if isinstance(o,_def_types) and o.name not in shown and o.name[0]!='_']"
512+
]
513+
},
514+
{
515+
"cell_type": "code",
516+
"execution_count": null,
517+
"id": "6737ddea-352e-4968-9bb2-37e6002d468c",
518+
"metadata": {},
519+
"outputs": [],
520+
"source": [
521+
"#|export\n",
522+
"def _get_nm(tree):\n",
523+
" i = tree.value.args[0]\n",
524+
" return f'{i.value.id}.{i.attr}' if isinstance(i, ast.Attribute) else i.id"
510525
]
511526
},
512527
{
@@ -521,7 +536,7 @@
521536
" \"Add show_doc cells after exported cells, unless they are already documented\"\n",
522537
" exports = L(cell for cell in nb.cells if cell.source and _re_exps(cell.source))\n",
523538
" trees = nb.cells.map(NbCell.parsed_).concat()\n",
524-
" shown_docs = {t.value.args[0].id for t in _show_docs(trees)}\n",
539+
" shown_docs = {_get_nm(t) for t in _show_docs(trees)}\n",
525540
" for cell in reversed(exports):\n",
526541
" for nm in _def_names(cell, shown_docs):\n",
527542
" code = f'show_doc({nm})'\n",
@@ -541,6 +556,20 @@
541556
"assert \"show_doc(another_func)'\" not in res"
542557
]
543558
},
559+
{
560+
"cell_type": "code",
561+
"execution_count": null,
562+
"id": "9c2783ea-395e-4206-867c-7c467da9738e",
563+
"metadata": {},
564+
"outputs": [],
565+
"source": [
566+
"#|hide\n",
567+
"# this test makes sure @patch works\n",
568+
"_nb = read_nb('../tests/showdoc_test.ipynb')\n",
569+
"add_show_docs(_nb)\n",
570+
"assert r'show_doc(Foo.a_method)' in _nb.cells.attrgot('source')"
571+
]
572+
},
544573
{
545574
"cell_type": "markdown",
546575
"id": "7e50cfe6",

0 commit comments

Comments
 (0)