Skip to content

Commit

Permalink
fixes #664
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Jan 19, 2025
1 parent 62e622c commit 373a91d
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 29 deletions.
20 changes: 12 additions & 8 deletions fastcore/docments.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ def _param_locs(s, returns=True, args_kwargs=False):
if isinstance(defn, (FunctionDef, AsyncFunctionDef)):
res = {arg.lineno:arg.arg for arg in defn.args.args}
# Add *args if present
if defn.args.vararg and args_kwargs: res[defn.args.vararg.lineno] = defn.args.vararg.arg
if defn.args.vararg: res[defn.args.vararg.lineno] = defn.args.vararg.arg
# Add keyword-only args
if args_kwargs: res.update({arg.lineno:arg.arg for arg in defn.args.kwonlyargs})
res.update({arg.lineno:arg.arg for arg in defn.args.kwonlyargs})
# Add **kwargs if present
if defn.args.kwarg and args_kwargs: res[defn.args.kwarg.lineno] = defn.args.kwarg.arg
if returns and defn.returns: res[defn.returns.lineno] = 'return'
Expand All @@ -98,9 +98,12 @@ def _get_comment(line, arg, comments, parms):
line -= 1
return dedent('\n'.join(reversed(res))) if res else None

def _get_full(anno, name, default, docs):
if anno==empty and default!=empty: anno = type(default)
return AttrDict(docment=docs.get(name), anno=anno, default=default)
def _get_full(p, docs):
anno = p.annotation
if anno==empty:
if p.default!=empty: anno = type(p.default)
elif p.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD): anno = p.kind
return AttrDict(docment=docs.get(p.name), anno=anno, default=p.default)

# %% ../nbs/06_docments.ipynb
def _merge_doc(dm, npdoc):
Expand Down Expand Up @@ -148,8 +151,8 @@ def _docments(s, returns=True, eval_str=False, args_kwargs=False):
docs = {arg:_get_comment(line, arg, comments, parms) for line,arg in parms.items()}

sig = signature_ex(s, True)
res = {arg:_get_full(p.annotation, p.name, p.default, docs) for arg,p in sig.parameters.items()}
if returns: res['return'] = _get_full(sig.return_annotation, 'return', empty, docs)
res = {name:_get_full(p, docs) for name,p in sig.parameters.items()}
if returns: res['return'] = AttrDict(docment=docs.get('return'), anno=sig.return_annotation, default=empty)
res = _merge_docs(res, nps)
if eval_str:
hints = type_hints(s)
Expand All @@ -159,8 +162,9 @@ def _docments(s, returns=True, eval_str=False, args_kwargs=False):

# %% ../nbs/06_docments.ipynb
@delegates(_docments)
def docments(elt, full=False, **kwargs):
def docments(elt, full=False, args_kwargs=False, **kwargs):
"Generates a `docment`"
if full: args_kwargs=True
r = {}
params = set(signature(elt).parameters)
params.add('return')
Expand Down
117 changes: 96 additions & 21 deletions nbs/06_docments.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@
" if isinstance(defn, (FunctionDef, AsyncFunctionDef)):\n",
" res = {arg.lineno:arg.arg for arg in defn.args.args}\n",
" # Add *args if present\n",
" if defn.args.vararg and args_kwargs: res[defn.args.vararg.lineno] = defn.args.vararg.arg\n",
" if defn.args.vararg: res[defn.args.vararg.lineno] = defn.args.vararg.arg\n",
" # Add keyword-only args\n",
" if args_kwargs: res.update({arg.lineno:arg.arg for arg in defn.args.kwonlyargs})\n",
" res.update({arg.lineno:arg.arg for arg in defn.args.kwonlyargs})\n",
" # Add **kwargs if present\n",
" if defn.args.kwarg and args_kwargs: res[defn.args.kwarg.lineno] = defn.args.kwarg.arg\n",
" if returns and defn.returns: res[defn.returns.lineno] = 'return'\n",
Expand All @@ -258,6 +258,27 @@
" return None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{2: 'a', 3: 'b', 4: 'return'}"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"parms = _param_locs(add)\n",
"parms"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -284,9 +305,32 @@
" line -= 1\n",
" return dedent('\\n'.join(reversed(res))) if res else None\n",
"\n",
"def _get_full(anno, name, default, docs):\n",
" if anno==empty and default!=empty: anno = type(default)\n",
" return AttrDict(docment=docs.get(name), anno=anno, default=default)"
"def _get_full(p, docs):\n",
" anno = p.annotation\n",
" if anno==empty:\n",
" if p.default!=empty: anno = type(p.default)\n",
" elif p.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD): anno = p.kind\n",
" return AttrDict(docment=docs.get(p.name), anno=anno, default=p.default)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'the 1st number to add'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"_get_comment(2, 'a', {2: ' the 1st number to add'}, parms)"
]
},
{
Expand Down Expand Up @@ -395,8 +439,8 @@
" docs = {arg:_get_comment(line, arg, comments, parms) for line,arg in parms.items()}\n",
"\n",
" sig = signature_ex(s, True)\n",
" res = {arg:_get_full(p.annotation, p.name, p.default, docs) for arg,p in sig.parameters.items()}\n",
" if returns: res['return'] = _get_full(sig.return_annotation, 'return', empty, docs)\n",
" res = {name:_get_full(p, docs) for name,p in sig.parameters.items()}\n",
" if returns: res['return'] = AttrDict(docment=docs.get('return'), anno=sig.return_annotation, default=empty)\n",
" res = _merge_docs(res, nps)\n",
" if eval_str:\n",
" hints = type_hints(s)\n",
Expand All @@ -413,8 +457,9 @@
"source": [
"#|export\n",
"@delegates(_docments)\n",
"def docments(elt, full=False, **kwargs):\n",
"def docments(elt, full=False, args_kwargs=False, **kwargs):\n",
" \"Generates a `docment`\"\n",
" if full: args_kwargs=True\n",
" r = {}\n",
" params = set(signature(elt).parameters)\n",
" params.add('return')\n",
Expand Down Expand Up @@ -472,6 +517,13 @@
"docments(add)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`args_kwargs=True` adds args and kwargs docs too:"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -484,15 +536,15 @@
"{ 'a': 'the 1st number to add',\n",
" 'args': 'some args',\n",
" 'b': 'the 2nd number to add',\n",
" 'kwargs': 'Passed to the `example` function',\n",
" 'kwargs': None,\n",
" 'return': 'the result of adding `a` to `b`'}\n",
"```"
],
"text/plain": [
"{'args': 'some args',\n",
" 'a': 'the 1st number to add',\n",
" 'b': 'the 2nd number to add',\n",
" 'kwargs': 'Passed to the `example` function',\n",
" 'kwargs': None,\n",
" 'return': 'the result of adding `a` to `b`'}"
]
},
Expand All @@ -517,7 +569,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"If you pass `full=True`, the values are `dict` of defaults, types, and docments as values. Note that the type annotation is inferred from the default value, if the annotation is empty and a default is supplied."
"If you pass `full=True`, the values are `dict` of defaults, types, and docments as values. Note that the type annotation is inferred from the default value, if the annotation is empty and a default is supplied. (Note that for `full`, `args_kwargs=True` is always set too.)"
]
},
{
Expand All @@ -532,19 +584,31 @@
"{ 'a': { 'anno': <class 'int'>,\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': 'the 1st number to add'},\n",
" 'args': { 'anno': <_ParameterKind.VAR_POSITIONAL: 2>,\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': 'some args'},\n",
" 'b': { 'anno': <class 'int'>,\n",
" 'default': 0,\n",
" 'docment': 'the 2nd number to add'},\n",
" 'kwargs': { 'anno': <_ParameterKind.VAR_KEYWORD: 4>,\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': None},\n",
" 'return': { 'anno': <class 'int'>,\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': 'the result of adding `a` to `b`'}}\n",
"```"
],
"text/plain": [
"{'a': {'docment': 'the 1st number to add',\n",
"{'args': {'docment': 'some args',\n",
" 'anno': <_ParameterKind.VAR_POSITIONAL: 2>,\n",
" 'default': inspect._empty},\n",
" 'a': {'docment': 'the 1st number to add',\n",
" 'anno': int,\n",
" 'default': inspect._empty},\n",
" 'b': {'docment': 'the 2nd number to add', 'anno': int, 'default': 0},\n",
" 'kwargs': {'docment': None,\n",
" 'anno': <_ParameterKind.VAR_KEYWORD: 4>,\n",
" 'default': inspect._empty},\n",
" 'return': {'docment': 'the result of adding `a` to `b`',\n",
" 'anno': int,\n",
" 'default': inspect._empty}}"
Expand Down Expand Up @@ -968,11 +1032,21 @@
"data": {
"text/markdown": [
"```json\n",
"{'a': 'First', 'b': 'Second', 'return': None}\n",
"{ 'a': {'anno': <class 'int'>, 'default': 2, 'docment': 'First'},\n",
" 'b': { 'anno': 'str',\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': 'Second'},\n",
" 'return': { 'anno': <class 'inspect._empty'>,\n",
" 'default': <class 'inspect._empty'>,\n",
" 'docment': None}}\n",
"```"
],
"text/plain": [
"{'a': 'First', 'return': None, 'b': 'Second'}"
"{'a': {'docment': 'First', 'anno': int, 'default': 2},\n",
" 'return': {'docment': None,\n",
" 'anno': inspect._empty,\n",
" 'default': inspect._empty},\n",
" 'b': {'docment': 'Second', 'anno': 'str', 'default': inspect._empty}}"
]
},
"execution_count": null,
Expand All @@ -981,13 +1055,7 @@
}
],
"source": [
"def _a(a:int=2): return a # First\n",
"\n",
"@delegates(_a)\n",
"def _b(b:str, # Second\n",
" **kwargs): \n",
" return b, (_a(**kwargs)) \n",
"docments(_b)"
"docments(_b, full=True)"
]
},
{
Expand Down Expand Up @@ -1142,6 +1210,13 @@
"#|hide\n",
"import nbdev; nbdev.nbdev_export()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down

0 comments on commit 373a91d

Please sign in to comment.