Skip to content

Commit 88a5d07

Browse files
committed
add __repr__ to Param for augmented function documentation
1 parent 31df31f commit 88a5d07

File tree

3 files changed

+95
-10
lines changed

3 files changed

+95
-10
lines changed

fastcore/_nbdev.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
"store_true": "08_script.ipynb",
200200
"store_false": "08_script.ipynb",
201201
"bool_arg": "08_script.ipynb",
202+
"clean_type": "08_script.ipynb",
202203
"Param": "08_script.ipynb",
203204
"anno_parser": "08_script.ipynb",
204205
"args_from_prog": "08_script.ipynb",

fastcore/script.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/08_script.ipynb (unless otherwise specified).
22

3-
__all__ = ['store_true', 'store_false', 'bool_arg', 'Param', 'anno_parser', 'args_from_prog', 'call_parse']
3+
__all__ = ['store_true', 'store_false', 'bool_arg', 'clean_type', 'Param', 'anno_parser', 'args_from_prog',
4+
'call_parse']
45

56
# Cell
67
import inspect,functools
@@ -23,6 +24,13 @@ def bool_arg(v):
2324
"Use as `type` for `Param` to get `bool` behavior"
2425
return str2bool(v)
2526

27+
# Cell
28+
def clean_type(x:str):
29+
x = str(x)
30+
x = re.sub("(class|function|__main__\.|\ at.*)", '', x)
31+
x = re.sub("(<|>|'|\ )", '', x) # spl characters
32+
return x
33+
2634
# Cell
2735
class Param:
2836
"A parameter in a function used in `anno_parser` or `call_parse`"
@@ -43,6 +51,11 @@ def pre(self): return '--' if self.opt else ''
4351
@property
4452
def kwargs(self): return {k:v for k,v in self.__dict__.items()
4553
if v is not None and k!='opt' and k[0]!='_'}
54+
def __repr__(self):
55+
if self.help is None and self.type is None: return ""
56+
if self.help is None and self.type is not None: return f"{clean_type(self.type)}"
57+
if self.help is not None and self.type is None: return f"<{self.help}>"
58+
if self.help is not None and self.type is not None: return f"{clean_type(self.type)} <{self.help}>"
4659

4760
# Cell
4861
def anno_parser(func, prog=None, from_name=False):

nbs/08_script.ipynb

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,35 @@
189189
" return str2bool(v)"
190190
]
191191
},
192+
{
193+
"cell_type": "code",
194+
"execution_count": null,
195+
"metadata": {},
196+
"outputs": [],
197+
"source": [
198+
"#export\n",
199+
"def clean_type_str(x:str):\n",
200+
" x = str(x)\n",
201+
" x = re.sub(\"(class|function|__main__\\.|\\ at.*)\", '', x)\n",
202+
" x = re.sub(\"(<|>|'|\\ )\", '', x) # spl characters\n",
203+
" return x"
204+
]
205+
},
206+
{
207+
"cell_type": "code",
208+
"execution_count": null,
209+
"metadata": {},
210+
"outputs": [],
211+
"source": [
212+
"class Test: pass\n",
213+
"\n",
214+
"test_eq(clean_type_str(argparse.ArgumentParser), 'argparse.ArgumentParser')\n",
215+
"test_eq(clean_type_str(Test), 'Test')\n",
216+
"test_eq(clean_type_str(int), 'int')\n",
217+
"test_eq(clean_type_str(float), 'float')\n",
218+
"test_eq(clean_type_str(store_false), 'store_false')"
219+
]
220+
},
192221
{
193222
"cell_type": "code",
194223
"execution_count": null,
@@ -214,7 +243,24 @@
214243
" def pre(self): return '--' if self.opt else ''\n",
215244
" @property\n",
216245
" def kwargs(self): return {k:v for k,v in self.__dict__.items()\n",
217-
" if v is not None and k!='opt' and k[0]!='_'}"
246+
" if v is not None and k!='opt' and k[0]!='_'}\n",
247+
" def __repr__(self):\n",
248+
" if self.help is None and self.type is None: return \"\"\n",
249+
" if self.help is None and self.type is not None: return f\"{clean_type_str(self.type)}\"\n",
250+
" if self.help is not None and self.type is None: return f\"<{self.help}>\"\n",
251+
" if self.help is not None and self.type is not None: return f\"{clean_type_str(self.type)} <{self.help}>\""
252+
]
253+
},
254+
{
255+
"cell_type": "code",
256+
"execution_count": null,
257+
"metadata": {},
258+
"outputs": [],
259+
"source": [
260+
"test_eq(repr(Param(\"Help goes here\")), '<Help goes here>')\n",
261+
"test_eq(repr(Param(\"Help\", int)), 'int <Help>')\n",
262+
"test_eq(repr(Param(help=None, type=int)), 'int')\n",
263+
"test_eq(repr(Param(help=None, type=None)), '')"
218264
]
219265
},
220266
{
@@ -223,7 +269,31 @@
223269
"source": [
224270
"Each parameter in your function should have an annotation `Param(...)`. You can pass the following when calling `Param`: `help`,`type`,`opt`,`action`,`nargs`,`const`,`choices`,`required` (i.e. it takes the same parameters as `argparse.ArgumentParser.add_argument`, plus `opt`). Except for `opt`, all of these are just passed directly to `argparse`, so you have all the power of that module at your disposal. Generally you'll want to pass at least `help` (since this is provided as the help string for that parameter) and `type` (to ensure that you get the type of data you expect).\n",
225271
"\n",
226-
"`opt` is a bool that defines whether a param is optional or required (positional) - but you'll generally not need to set this manually, because fastcore.script will set it for you automatically based on *default* values. You should provide a default (after the `=`) for any *optional* parameters. If you don't provide a default for a parameter, then it will be a *positional* parameter."
272+
"`opt` is a bool that defines whether a param is optional or required (positional) - but you'll generally not need to set this manually, because fastcore.script will set it for you automatically based on *default* values. You should provide a default (after the `=`) for any *optional* parameters. If you don't provide a default for a parameter, then it will be a *positional* parameter.\n",
273+
"\n",
274+
"Param's `__repr__` also allows for more informative function annotation when looking up the function's doc using shift+tab. You see the type annotation (if there is one) and the accompanying help documentation with it."
275+
]
276+
},
277+
{
278+
"cell_type": "code",
279+
"execution_count": null,
280+
"metadata": {},
281+
"outputs": [],
282+
"source": [
283+
"def f(required:Param(\"Required param\", int),\n",
284+
" a:Param(\"param 1\", bool_arg),\n",
285+
" b:Param(\"param 2\", str)=\"test\"):\n",
286+
" \"my docs\"\n",
287+
" ..."
288+
]
289+
},
290+
{
291+
"cell_type": "code",
292+
"execution_count": null,
293+
"metadata": {},
294+
"outputs": [],
295+
"source": [
296+
"f?"
227297
]
228298
},
229299
{
@@ -414,13 +484,14 @@
414484
"output_type": "stream",
415485
"text": [
416486
"Converted 00_test.ipynb.\n",
417-
"Converted 01_foundation.ipynb.\n",
418-
"Converted 02_utils.ipynb.\n",
419-
"Converted 03_dispatch.ipynb.\n",
420-
"Converted 04_transform.ipynb.\n",
421-
"Converted 05_logargs.ipynb.\n",
422-
"Converted 06_meta.ipynb.\n",
423-
"Converted 07_script.ipynb.\n",
487+
"Converted 01_basics.ipynb.\n",
488+
"Converted 02_foundation.ipynb.\n",
489+
"Converted 03_xtras.ipynb.\n",
490+
"Converted 04_dispatch.ipynb.\n",
491+
"Converted 05_transform.ipynb.\n",
492+
"Converted 06_logargs.ipynb.\n",
493+
"Converted 07_meta.ipynb.\n",
494+
"Converted 08_script.ipynb.\n",
424495
"Converted index.ipynb.\n"
425496
]
426497
}

0 commit comments

Comments
 (0)