Skip to content

Commit 5ba0af3

Browse files
committed
fixes #791
1 parent 4902e44 commit 5ba0af3

3 files changed

Lines changed: 82 additions & 39 deletions

File tree

fastcore/docments.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def docstring(sym):
2828
if isinstance(sym, str): return sym
2929
res = getdoc(sym)
3030
if not res and isclass(sym): res = getdoc(sym.__init__)
31+
if not res and callable(sym) and not isclass(sym): res = getdoc(sym.__call__)
3132
return res or ""
3233

3334
# %% ../nbs/04_docments.ipynb #1e0cf854
@@ -140,8 +141,10 @@ def get_name(obj):
140141
elif getattr(obj, '_name', False): return obj._name
141142
elif hasattr(obj,'__origin__'): return str(obj.__origin__).split('.')[-1]
142143
elif type(obj)==property: return _get_property_name(obj)
144+
elif callable(obj): return type(obj).__name__
143145
else: return str(obj).split('.')[-1]
144146

147+
145148
# %% ../nbs/04_docments.ipynb #5e273f22
146149
def qual_name(obj):
147150
"Get the qualified name of `obj`"
@@ -364,10 +367,14 @@ def _ret_str(self):
364367
def params(self): return [(self._fmt_param(k,v), v.get('docment','')) for k,v in self.dm.items() if k != 'return']
365368

366369
def __str__(self):
367-
prefix = 'async def' if inspect.iscoroutinefunction(self.obj) else 'def'
368-
if (sig := _clean_text_sig(self.obj)) and not self.params: sig_str = f"{prefix} {sig}"
369-
else: sig_str = _fmt_sig(get_name(self.obj), self.params, self._ret_str, self.maxline, prefix=prefix)
370-
docstr = f' "{self.obj.__doc__}"' if self.docstring and self.obj.__doc__ else ''
370+
o = self.obj
371+
is_inst = callable(o) and not (isfunction(o) or isclass(o) or inspect.isbuiltin(o) or ismethod(o))
372+
prefix = 'async def' if inspect.iscoroutinefunction(o) else 'def'
373+
nm = f'{type(o).__name__}.__call__' if is_inst else get_name(o)
374+
if (sig := _clean_text_sig(o)) and not self.params: sig_str = f"{prefix} {sig}"
375+
else: sig_str = _fmt_sig(nm, self.params, self._ret_str, self.maxline, prefix=prefix)
376+
doc = getattr(o.__call__, '__doc__', None) if is_inst else o.__doc__
377+
docstr = f' "{doc}"' if self.docstring and doc else ''
371378
return f"{sig_str}\n{docstr}"
372379

373380
__repr__ = __str__

nbs/02_foundation.ipynb

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4473,13 +4473,7 @@
44734473
]
44744474
}
44754475
],
4476-
"metadata": {
4477-
"kernelspec": {
4478-
"display_name": "python3",
4479-
"language": "python",
4480-
"name": "python3"
4481-
}
4482-
},
4476+
"metadata": {},
44834477
"nbformat": 4,
44844478
"nbformat_minor": 5
44854479
}

nbs/04_docments.ipynb

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
" if isinstance(sym, str): return sym\n",
160160
" res = getdoc(sym)\n",
161161
" if not res and isclass(sym): res = getdoc(sym.__init__)\n",
162+
" if not res and callable(sym) and not isclass(sym): res = getdoc(sym.__call__)\n",
162163
" return res or \"\""
163164
]
164165
},
@@ -414,7 +415,8 @@
414415
" elif getattr(obj, '_name', False): return obj._name\n",
415416
" elif hasattr(obj,'__origin__'): return str(obj.__origin__).split('.')[-1]\n",
416417
" elif type(obj)==property: return _get_property_name(obj)\n",
417-
" else: return str(obj).split('.')[-1]"
418+
" elif callable(obj): return type(obj).__name__\n",
419+
" else: return str(obj).split('.')[-1]\n"
418420
]
419421
},
420422
{
@@ -2187,10 +2189,14 @@
21872189
" def params(self): return [(self._fmt_param(k,v), v.get('docment','')) for k,v in self.dm.items() if k != 'return']\n",
21882190
"\n",
21892191
" def __str__(self):\n",
2190-
" prefix = 'async def' if inspect.iscoroutinefunction(self.obj) else 'def'\n",
2191-
" if (sig := _clean_text_sig(self.obj)) and not self.params: sig_str = f\"{prefix} {sig}\"\n",
2192-
" else: sig_str = _fmt_sig(get_name(self.obj), self.params, self._ret_str, self.maxline, prefix=prefix)\n",
2193-
" docstr = f' \"{self.obj.__doc__}\"' if self.docstring and self.obj.__doc__ else ''\n",
2192+
" o = self.obj\n",
2193+
" is_inst = callable(o) and not (isfunction(o) or isclass(o) or inspect.isbuiltin(o) or ismethod(o))\n",
2194+
" prefix = 'async def' if inspect.iscoroutinefunction(o) else 'def'\n",
2195+
" nm = f'{type(o).__name__}.__call__' if is_inst else get_name(o)\n",
2196+
" if (sig := _clean_text_sig(o)) and not self.params: sig_str = f\"{prefix} {sig}\"\n",
2197+
" else: sig_str = _fmt_sig(nm, self.params, self._ret_str, self.maxline, prefix=prefix)\n",
2198+
" doc = getattr(o.__call__, '__doc__', None) if is_inst else o.__doc__\n",
2199+
" docstr = f' \"{doc}\"' if self.docstring and doc else ''\n",
21942200
" return f\"{sig_str}\\n{docstr}\"\n",
21952201
" \n",
21962202
" __repr__ = __str__\n",
@@ -2303,7 +2309,7 @@
23032309
"data": {
23042310
"text/markdown": [
23052311
"```python\n",
2306-
"def _g[partial: 1](\n",
2312+
"def partial.__call__(\n",
23072313
" b:int, cccccccccccccccccccc:int, ccccccccdccccccccccc:int,\n",
23082314
" cccccccccccecccccccc:int, cccccccfcccccccccc:int, ccccccccccccgccccc:int,\n",
23092315
" c:str='foo'\n",
@@ -2312,7 +2318,7 @@
23122318
"```"
23132319
],
23142320
"text/plain": [
2315-
"def _g[partial: 1](\n",
2321+
"def partial.__call__(\n",
23162322
" b:int, cccccccccccccccccccc:int, ccccccccdccccccccccc:int,\n",
23172323
" cccccccccccecccccccc:int, cccccccfcccccccccc:int, ccccccccccccgccccc:int,\n",
23182324
" c:str='foo'\n",
@@ -2598,18 +2604,18 @@
25982604
"):\n",
25992605
"\n",
26002606
"\n",
2601-
"```"
2607+
"```\n",
2608+
"\n",
2609+
"*Call self as a function.*"
26022610
],
26032611
"text/plain": [
2604-
"```python\n",
2605-
"\n",
26062612
"def g(\n",
26072613
" b:int | str, # bb\n",
26082614
" a:int=0, # aa\n",
26092615
"):\n",
2610-
"\n",
2611-
"\n",
2612-
"```"
2616+
"\"\"\"\n",
2617+
"Call self as a function.\n",
2618+
"\"\"\""
26132619
]
26142620
},
26152621
"execution_count": null,
@@ -2644,18 +2650,14 @@
26442650
"*Add `a` to `b`*"
26452651
],
26462652
"text/plain": [
2647-
"```python\n",
2648-
"\n",
26492653
"async def add_async(\n",
26502654
" a:int, # The first operand\n",
26512655
" b:int, # This is the second of the operands to the *addition* operator.\n",
26522656
"Note that passing a negative value here is the equivalent of the *subtraction* operator.\n",
26532657
")->int: # The result is calculated using Python's builtin `+` operator.\n",
2654-
"\n",
2655-
"\n",
2656-
"```\n",
2657-
"\n",
2658-
"*Add `a` to `b`*"
2658+
"\"\"\"\n",
2659+
"Add `a` to `b`\n",
2660+
"\"\"\""
26592661
]
26602662
},
26612663
"execution_count": null,
@@ -2689,17 +2691,13 @@
26892691
"it is returned instead of raising StopIteration."
26902692
],
26912693
"text/plain": [
2692-
"```python\n",
2693-
"\n",
26942694
"def next(iterator, default=..., /)\n",
2695-
"\n",
2696-
"\n",
2697-
"```\n",
2698-
"\n",
2699-
"*Return the next item from the iterator.*\n",
2695+
"\"\"\"\n",
2696+
"Return the next item from the iterator.\n",
27002697
"\n",
27012698
"If default is given and the iterator is exhausted,\n",
2702-
"it is returned instead of raising StopIteration."
2699+
"it is returned instead of raising StopIteration.\n",
2700+
"\"\"\""
27032701
]
27042702
},
27052703
"execution_count": null,
@@ -2782,6 +2780,50 @@
27822780
"assert 'x:int' not in str(_r3.dm), \"Original params should not leak through\""
27832781
]
27842782
},
2783+
{
2784+
"cell_type": "code",
2785+
"execution_count": null,
2786+
"id": "e7eaff97",
2787+
"metadata": {},
2788+
"outputs": [
2789+
{
2790+
"data": {
2791+
"text/markdown": [
2792+
"```python\n",
2793+
"\n",
2794+
"def Foo.__call__(\n",
2795+
" x\n",
2796+
"):\n",
2797+
"\n",
2798+
"\n",
2799+
"```\n",
2800+
"\n",
2801+
"*Call foo*"
2802+
],
2803+
"text/plain": [
2804+
"def Foo.__call__(\n",
2805+
" x\n",
2806+
"):\n",
2807+
"\"\"\"\n",
2808+
"Call foo\n",
2809+
"\"\"\""
2810+
]
2811+
},
2812+
"execution_count": null,
2813+
"metadata": {},
2814+
"output_type": "execute_result"
2815+
}
2816+
],
2817+
"source": [
2818+
"class Foo:\n",
2819+
" def __call__(self, x):\n",
2820+
" \"Call foo\"\n",
2821+
" return x\n",
2822+
"\n",
2823+
"foo = Foo()\n",
2824+
"MarkdownRenderer(foo)"
2825+
]
2826+
},
27852827
{
27862828
"cell_type": "markdown",
27872829
"id": "51a04f95",

0 commit comments

Comments
 (0)