|
17 | 17 | from types import FunctionType |
18 | 18 |
|
19 | 19 | # %% auto 0 |
20 | | -__all__ = ['DocmentTbl', 'ShowDocRenderer', 'BasicMarkdownRenderer', 'show_doc', 'BasicHtmlRenderer', 'doc', 'showdoc_nm', |
21 | | - 'colab_link'] |
22 | | - |
23 | | -# %% ../nbs/api/08_showdoc.ipynb |
24 | | -def _non_empty_keys(d:dict): return L([k for k,v in d.items() if v != inspect._empty]) |
25 | | -def _bold(s): return f'**{s}**' if s.strip() else s |
26 | | - |
27 | | -# %% ../nbs/api/08_showdoc.ipynb |
28 | | -def _escape_markdown(s): |
29 | | - for c in '|^': s = re.sub(rf'\\?\{c}', rf'\{c}', s) |
30 | | - return s.replace('\n', '<br>') |
31 | | - |
32 | | -# %% ../nbs/api/08_showdoc.ipynb |
33 | | -def _maybe_nm(o): |
34 | | - if (o == inspect._empty): return '' |
35 | | - else: return o.__name__ if hasattr(o, '__name__') else _escape_markdown(str(o)) |
36 | | - |
37 | | -# %% ../nbs/api/08_showdoc.ipynb |
38 | | -def _list2row(l:list): return '| '+' | '.join([_maybe_nm(o) for o in l]) + ' |' |
39 | | - |
40 | | -# %% ../nbs/api/08_showdoc.ipynb |
41 | | -class DocmentTbl: |
42 | | - # this is the column order we want these items to appear |
43 | | - _map = OrderedDict({'anno':'Type', 'default':'Default', 'docment':'Details'}) |
44 | | - |
45 | | - def __init__(self, obj, verbose=True, returns=True): |
46 | | - "Compute the docment table string" |
47 | | - self.verbose = verbose |
48 | | - self.returns = False if isdataclass(obj) else returns |
49 | | - try: self.params = L(signature_ex(obj, eval_str=True).parameters.keys()) |
50 | | - except (ValueError,TypeError): self.params=[] |
51 | | - try: _dm = docments(obj, full=True, returns=returns) |
52 | | - except: _dm = {} |
53 | | - if 'self' in _dm: del _dm['self'] |
54 | | - for d in _dm.values(): d['docment'] = ifnone(d['docment'], inspect._empty) |
55 | | - self.dm = _dm |
56 | | - |
57 | | - @property |
58 | | - def _columns(self): |
59 | | - "Compute the set of fields that have at least one non-empty value so we don't show tables empty columns" |
60 | | - cols = set(flatten(L(self.dm.values()).filter().map(_non_empty_keys))) |
61 | | - candidates = self._map if self.verbose else {'docment': 'Details'} |
62 | | - return OrderedDict({k:v for k,v in candidates.items() if k in cols}) |
63 | | - |
64 | | - @property |
65 | | - def has_docment(self): return 'docment' in self._columns and self._row_list |
66 | | - |
67 | | - @property |
68 | | - def has_return(self): return self.returns and bool(_non_empty_keys(self.dm.get('return', {}))) |
69 | | - |
70 | | - def _row(self, nm, props): |
71 | | - "unpack data for single row to correspond with column names." |
72 | | - return [nm] + [props[c] for c in self._columns] |
73 | | - |
74 | | - @property |
75 | | - def _row_list(self): |
76 | | - "unpack data for all rows." |
77 | | - ordered_params = [(p, self.dm[p]) for p in self.params if p != 'self' and p in self.dm] |
78 | | - return L([self._row(nm, props) for nm,props in ordered_params]) |
79 | | - |
80 | | - @property |
81 | | - def _hdr_list(self): return [' '] + [_bold(l) for l in L(self._columns.values())] |
82 | | - |
83 | | - @property |
84 | | - def hdr_str(self): |
85 | | - "The markdown string for the header portion of the table" |
86 | | - md = _list2row(self._hdr_list) |
87 | | - return md + '\n' + _list2row(['-' * len(l) for l in self._hdr_list]) |
88 | | - |
89 | | - @property |
90 | | - def params_str(self): |
91 | | - "The markdown string for the parameters portion of the table." |
92 | | - return '\n'.join(self._row_list.map(_list2row)) |
93 | | - |
94 | | - @property |
95 | | - def return_str(self): |
96 | | - "The markdown string for the returns portion of the table." |
97 | | - return _list2row(['**Returns**']+[_bold(_maybe_nm(self.dm['return'][c])) for c in self._columns]) |
98 | | - |
99 | | - def _repr_markdown_(self): |
100 | | - if not self.has_docment: return '' |
101 | | - _tbl = [self.hdr_str, self.params_str] |
102 | | - if self.has_return: _tbl.append(self.return_str) |
103 | | - return '\n'.join(_tbl) |
104 | | - |
105 | | - def __eq__(self,other): return self.__str__() == str(other).strip() |
106 | | - |
107 | | - __str__ = _repr_markdown_ |
108 | | - __repr__ = basic_repr() |
109 | | - |
110 | | -# %% ../nbs/api/08_showdoc.ipynb |
111 | | -def _docstring(sym): |
112 | | - npdoc = parse_docstring(sym) |
113 | | - return '\n\n'.join([npdoc['Summary'], npdoc['Extended']]).strip() |
114 | | - |
115 | | -# %% ../nbs/api/08_showdoc.ipynb |
116 | | -def _fullname(o): |
117 | | - module,name = getattr(o, "__module__", None),qual_name(o) |
118 | | - return name if module is None or module in ('__main__','builtins') else module + '.' + name |
119 | | - |
120 | | -class ShowDocRenderer: |
121 | | - def __init__(self, sym, name:str|None=None, title_level:int=3): |
122 | | - "Show documentation for `sym`" |
123 | | - sym = getattr(sym, '__wrapped__', sym) |
124 | | - sym = getattr(sym, 'fget', None) or getattr(sym, 'fset', None) or sym |
125 | | - store_attr() |
126 | | - self.nm = name or qual_name(sym) |
127 | | - self.isfunc = inspect.isfunction(sym) |
128 | | - try: self.sig = signature_ex(sym, eval_str=True) |
129 | | - except (ValueError,TypeError): self.sig = None |
130 | | - self.docs = _docstring(sym) |
131 | | - self.dm = DocmentTbl(sym) |
132 | | - self.fn = _fullname(sym) |
133 | | - |
134 | | - __repr__ = basic_repr() |
135 | | - |
136 | | -# %% ../nbs/api/08_showdoc.ipynb |
137 | | -def _f_name(o): return f'<function {o.__name__}>' if isinstance(o, FunctionType) else None |
138 | | -def _fmt_anno(o): return inspect.formatannotation(o).strip("'").replace(' ','') |
139 | | - |
140 | | -def _show_param(param): |
141 | | - "Like `Parameter.__str__` except removes: quotes in annos, spaces, ids in reprs" |
142 | | - kind,res,anno,default = param.kind,param._name,param._annotation,param._default |
143 | | - kind = '*' if kind==inspect._VAR_POSITIONAL else '**' if kind==inspect._VAR_KEYWORD else '' |
144 | | - res = kind+res |
145 | | - if anno is not inspect._empty: res += f':{_f_name(anno) or _fmt_anno(anno)}' |
146 | | - if default is not inspect._empty: res += f'={_f_name(default) or repr(default)}' |
147 | | - return res |
148 | | - |
149 | | -# %% ../nbs/api/08_showdoc.ipynb |
150 | | -def _fmt_sig(sig): |
151 | | - if sig is None: return '' |
152 | | - p = {k:v for k,v in sig.parameters.items()} |
153 | | - _params = [_show_param(p[k]) for k in p.keys() if k != 'self'] |
154 | | - return "(" + ', '.join(_params) + ")" |
155 | | - |
156 | | -def _wrap_sig(s): |
157 | | - "wrap a signature to appear on multiple lines if necessary." |
158 | | - pad = '> ' + ' ' * 5 |
159 | | - indent = pad + ' ' * (s.find('(') + 1) |
160 | | - return fill(s, width=80, initial_indent=pad, subsequent_indent=indent) |
| 20 | +__all__ = ['BasicMarkdownRenderer', 'show_doc', 'BasicHtmlRenderer', 'doc', 'showdoc_nm', 'colab_link'] |
161 | 21 |
|
162 | 22 | # %% ../nbs/api/08_showdoc.ipynb |
163 | 23 | def _ext_link(url, txt, xtra=""): return f'[{txt}]({url}){{target="_blank" {xtra}}}' |
164 | 24 |
|
165 | | -class BasicMarkdownRenderer(ShowDocRenderer): |
| 25 | +class BasicMarkdownRenderer(MarkdownRenderer): |
166 | 26 | "Markdown renderer for `show_doc`" |
167 | 27 | def _repr_markdown_(self): |
168 | 28 | doc = '---\n\n' |
169 | 29 | src = NbdevLookup().code(self.fn) |
170 | 30 | if src: doc += _ext_link(src, 'source', 'style="float:right; font-size:smaller"') + '\n\n' |
171 | 31 | h = '#'*self.title_level |
172 | 32 | doc += f'{h} {self.nm}\n\n' |
173 | | - sig = _wrap_sig(f"{self.nm} {_fmt_sig(self.sig)}") if self.sig else '' |
174 | | - doc += f'{sig}' |
175 | | - if self.docs: doc += f"\n\n*{self.docs}*" |
176 | | - if self.dm.has_docment: doc += f"\n\n{self.dm}" |
177 | | - return doc |
178 | | - __repr__=__str__=_repr_markdown_ |
| 33 | + return doc+super()._repr_markdown_() |
179 | 34 |
|
180 | 35 | # %% ../nbs/api/08_showdoc.ipynb |
181 | 36 | def show_doc(sym, # Symbol to document |
@@ -212,6 +67,9 @@ def unescape_cell(cell): |
212 | 67 | # %% ../nbs/api/08_showdoc.ipynb |
213 | 68 | def _html_link(url, txt): return f'<a href="{url}" target="_blank" rel="noreferrer noopener">{txt}</a>' |
214 | 69 |
|
| 70 | +# %% ../nbs/api/08_showdoc.ipynb |
| 71 | +from fastcore.docments import _fmt_sig |
| 72 | + |
215 | 73 | # %% ../nbs/api/08_showdoc.ipynb |
216 | 74 | class BasicHtmlRenderer(ShowDocRenderer): |
217 | 75 | "HTML renderer for `show_doc`" |
|
0 commit comments