Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion fastcore/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ def _f(f):
# %% ../nbs/07_meta.ipynb
def delegates(to:FunctionType=None, # Delegatee
keep=False, # Keep `kwargs` in decorated function?
but:list=None): # Exclude these parameters from signature
but:list=None, # Exclude these parameters from signature
sort_args=False): # Sort arguments alphabetically, doesn't work with call_parse
"Decorator: replace `**kwargs` in signature with params from `to`"
if but is None: but = []
def _f(f):
Expand All @@ -124,6 +125,7 @@ def _f(f):
k = sigd.pop('kwargs')
s2 = {k:v.replace(kind=inspect.Parameter.KEYWORD_ONLY) for k,v in inspect.signature(to_f).parameters.items()
if v.default != inspect.Parameter.empty and k not in sigd and k not in but}
if sort_args: s2 = dict(sorted(s2.items()))
anno = {k:v for k,v in getattr(to_f, "__annotations__", {}).items() if k not in sigd and k not in but}
sigd.update(s2)
if keep: sigd['kwargs'] = k
Expand Down
94 changes: 85 additions & 9 deletions nbs/07_meta.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,24 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L28){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### FixSigMeta\n",
"\n",
"> FixSigMeta (name, bases, dict)\n",
"\n",
"A metaclass that fixes the signature on classes that override `__new__`"
"*A metaclass that fixes the signature on classes that override `__new__`*"
],
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L28){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### FixSigMeta\n",
"\n",
"> FixSigMeta (name, bases, dict)\n",
"\n",
"A metaclass that fixes the signature on classes that override `__new__`"
"*A metaclass that fixes the signature on classes that override `__new__`*"
]
},
"execution_count": null,
Expand Down Expand Up @@ -343,20 +347,24 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### PrePostInitMeta\n",
"\n",
"> PrePostInitMeta (name, bases, dict)\n",
"\n",
"A metaclass that calls optional `__pre_init__` and `__post_init__` methods"
"*A metaclass that calls optional `__pre_init__` and `__post_init__` methods*"
],
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### PrePostInitMeta\n",
"\n",
"> PrePostInitMeta (name, bases, dict)\n",
"\n",
"A metaclass that calls optional `__pre_init__` and `__post_init__` methods"
"*A metaclass that calls optional `__pre_init__` and `__post_init__` methods*"
]
},
"execution_count": null,
Expand Down Expand Up @@ -460,20 +468,24 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NewChkMeta\n",
"\n",
"> NewChkMeta (name, bases, dict)\n",
"\n",
"Metaclass to avoid recreating object passed to constructor"
"*Metaclass to avoid recreating object passed to constructor*"
],
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NewChkMeta\n",
"\n",
"> NewChkMeta (name, bases, dict)\n",
"\n",
"Metaclass to avoid recreating object passed to constructor"
"*Metaclass to avoid recreating object passed to constructor*"
]
},
"execution_count": null,
Expand Down Expand Up @@ -630,20 +642,24 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L60){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### BypassNewMeta\n",
"\n",
"> BypassNewMeta (name, bases, dict)\n",
"\n",
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
"*Metaclass: casts `x` to this class if it's of type `cls._bypass_type`*"
],
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L60){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### BypassNewMeta\n",
"\n",
"> BypassNewMeta (name, bases, dict)\n",
"\n",
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
"*Metaclass: casts `x` to this class if it's of type `cls._bypass_type`*"
]
},
"execution_count": null,
Expand Down Expand Up @@ -904,7 +920,8 @@
"#|export\n",
"def delegates(to:FunctionType=None, # Delegatee\n",
" keep=False, # Keep `kwargs` in decorated function?\n",
" but:list=None): # Exclude these parameters from signature\n",
" but:list=None, # Exclude these parameters from signature\n",
" sort_args=False): # Sort arguments alphabetically, doesn't work with call_parse\n",
" \"Decorator: replace `**kwargs` in signature with params from `to`\"\n",
" if but is None: but = []\n",
" def _f(f):\n",
Expand All @@ -918,6 +935,7 @@
" k = sigd.pop('kwargs')\n",
" s2 = {k:v.replace(kind=inspect.Parameter.KEYWORD_ONLY) for k,v in inspect.signature(to_f).parameters.items()\n",
" if v.default != inspect.Parameter.empty and k not in sigd and k not in but}\n",
" if sort_args: s2 = dict(sorted(s2.items()))\n",
" anno = {k:v for k,v in getattr(to_f, \"__annotations__\", {}).items() if k not in sigd and k not in but}\n",
" sigd.update(s2)\n",
" if keep: sigd['kwargs'] = k\n",
Expand Down Expand Up @@ -1216,6 +1234,64 @@
"assert type(a).__name__ == 'method'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also sort the arguments by setting the `sort_args` parameter to `True`. Here's a function with arguments not in alphabetical order."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function __main__.unsortedfunc(c=3, a=1, b=2)>"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def unsortedfunc(c=3,a=1,b=2): pass\n",
"unsortedfunc"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can sort them using the `sort_args` parameter:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function __main__.sortedfunc(*, a=1, b=2, c=3)>"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@delegates(unsortedfunc, sort_args=True)\n",
"def sortedfunc(**kwargs): pass\n",
"test_sig(sortedfunc, '(*, a=1, b=2, c=3)')\n",
"sortedfunc"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down