Skip to content

Commit 1a5cefa

Browse files
committed
fixes #685
1 parent 2db6ff0 commit 1a5cefa

File tree

3 files changed

+138
-8
lines changed

3 files changed

+138
-8
lines changed

fastcore/_modidx.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@
587587
'fastcore.xtras._is_property': ('xtras.html#_is_property', 'fastcore/xtras.py'),
588588
'fastcore.xtras._property_getter': ('xtras.html#_property_getter', 'fastcore/xtras.py'),
589589
'fastcore.xtras._repr_dict': ('xtras.html#_repr_dict', 'fastcore/xtras.py'),
590+
'fastcore.xtras._save_iter': ('xtras.html#_save_iter', 'fastcore/xtras.py'),
591+
'fastcore.xtras._save_iter.__init__': ('xtras.html#_save_iter.__init__', 'fastcore/xtras.py'),
592+
'fastcore.xtras._save_iter.__iter__': ('xtras.html#_save_iter.__iter__', 'fastcore/xtras.py'),
590593
'fastcore.xtras._sparkchar': ('xtras.html#_sparkchar', 'fastcore/xtras.py'),
591594
'fastcore.xtras._unpack': ('xtras.html#_unpack', 'fastcore/xtras.py'),
592595
'fastcore.xtras._unwrapped_func': ('xtras.html#_unwrapped_func', 'fastcore/xtras.py'),
@@ -632,6 +635,7 @@
632635
'fastcore.xtras.repr_dict': ('xtras.html#repr_dict', 'fastcore/xtras.py'),
633636
'fastcore.xtras.round_multiple': ('xtras.html#round_multiple', 'fastcore/xtras.py'),
634637
'fastcore.xtras.run': ('xtras.html#run', 'fastcore/xtras.py'),
638+
'fastcore.xtras.save_iter': ('xtras.html#save_iter', 'fastcore/xtras.py'),
635639
'fastcore.xtras.save_pickle': ('xtras.html#save_pickle', 'fastcore/xtras.py'),
636640
'fastcore.xtras.set_num_threads': ('xtras.html#set_num_threads', 'fastcore/xtras.py'),
637641
'fastcore.xtras.shufflish': ('xtras.html#shufflish', 'fastcore/xtras.py'),
@@ -640,6 +644,7 @@
640644
'fastcore.xtras.time_policy': ('xtras.html#time_policy', 'fastcore/xtras.py'),
641645
'fastcore.xtras.timed_cache': ('xtras.html#timed_cache', 'fastcore/xtras.py'),
642646
'fastcore.xtras.trace': ('xtras.html#trace', 'fastcore/xtras.py'),
647+
'fastcore.xtras.trim_wraps': ('xtras.html#trim_wraps', 'fastcore/xtras.py'),
643648
'fastcore.xtras.truncstr': ('xtras.html#truncstr', 'fastcore/xtras.py'),
644649
'fastcore.xtras.type2str': ('xtras.html#type2str', 'fastcore/xtras.py'),
645650
'fastcore.xtras.untar_dir': ('xtras.html#untar_dir', 'fastcore/xtras.py'),

fastcore/xtras.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
__all__ = ['spark_chars', 'UNSET', 'walk', 'globtastic', 'maybe_open', 'mkdir', 'image_size', 'bunzip', 'loads', 'loads_multi',
1010
'dumps', 'untar_dir', 'repo_details', 'run', 'open_file', 'save_pickle', 'load_pickle', 'parse_env',
1111
'expand_wildcards', 'dict2obj', 'obj2dict', 'repr_dict', 'is_listy', 'mapped', 'IterLen',
12-
'ReindexCollection', 'exec_eval', 'get_source_link', 'truncstr', 'sparkline', 'modify_exception',
13-
'round_multiple', 'set_num_threads', 'join_path_file', 'autostart', 'EventTimer', 'stringfmt_names',
14-
'PartialFormatter', 'partial_format', 'utc2local', 'local2utc', 'trace', 'modified_env', 'ContextManagers',
15-
'shufflish', 'console_help', 'hl_md', 'type2str', 'dataclass_src', 'Unset', 'nullable_dc', 'make_nullable',
16-
'flexiclass', 'asdict', 'is_typeddict', 'is_namedtuple', 'CachedIter', 'CachedAwaitable', 'reawaitable',
17-
'flexicache', 'time_policy', 'mtime_policy', 'timed_cache']
12+
'ReindexCollection', 'trim_wraps', 'save_iter', 'exec_eval', 'get_source_link', 'truncstr', 'sparkline',
13+
'modify_exception', 'round_multiple', 'set_num_threads', 'join_path_file', 'autostart', 'EventTimer',
14+
'stringfmt_names', 'PartialFormatter', 'partial_format', 'utc2local', 'local2utc', 'trace', 'modified_env',
15+
'ContextManagers', 'shufflish', 'console_help', 'hl_md', 'type2str', 'dataclass_src', 'Unset', 'nullable_dc',
16+
'make_nullable', 'flexiclass', 'asdict', 'is_typeddict', 'is_namedtuple', 'CachedIter', 'CachedAwaitable',
17+
'reawaitable', 'flexicache', 'time_policy', 'mtime_policy', 'timed_cache']
1818

1919
# %% ../nbs/03_xtras.ipynb
2020
from .imports import *
@@ -409,6 +409,28 @@ def __setstate__(self, s): self.coll,self.idxs,self.cache,self.tfm = s['coll'],s
409409
shuffle="Randomly shuffle indices",
410410
cache_clear="Clear LRU cache")
411411

412+
# %% ../nbs/03_xtras.ipynb
413+
def trim_wraps(f, n=1):
414+
"Like wraps, but removes the first n parameters from the signature"
415+
import inspect
416+
def _(g):
417+
g = wraps(f)(g)
418+
sig = inspect.signature(f)
419+
params = list(sig.parameters.values())[n:]
420+
g.__signature__ = sig.replace(parameters=params)
421+
return g
422+
return _
423+
424+
# %% ../nbs/03_xtras.ipynb
425+
class _save_iter:
426+
def __init__(self, g, *args, **kw): self.g,self.args,self.kw = g,args,kw
427+
def __iter__(self): yield from self.g(self, *self.args, **self.kw)
428+
429+
def save_iter(g):
430+
@trim_wraps(g)
431+
def _(*args, **kwargs): return _save_iter(g, *args, **kwargs)
432+
return _
433+
412434
# %% ../nbs/03_xtras.ipynb
413435
def exec_eval(code, # Code to exec/eval
414436
g=None, # Globals namespace dict

nbs/03_xtras.ipynb

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"from typing import TypedDict\n",
5454
"from collections import namedtuple\n",
5555
"\n",
56-
"import shutil,tempfile,pickle,random,asyncio"
56+
"import shutil,tempfile,pickle,random,asyncio,inspect"
5757
]
5858
},
5959
{
@@ -1732,7 +1732,7 @@
17321732
{
17331733
"data": {
17341734
"text/plain": [
1735-
"['e', 'h', 'g', 'c', 'b', 'f', 'd', 'a']"
1735+
"['c', 'h', 'b', 'a', 'f', 'g', 'd', 'e']"
17361736
]
17371737
},
17381738
"execution_count": null,
@@ -1785,6 +1785,109 @@
17851785
"## Other Helpers"
17861786
]
17871787
},
1788+
{
1789+
"cell_type": "code",
1790+
"execution_count": null,
1791+
"metadata": {},
1792+
"outputs": [],
1793+
"source": [
1794+
"#| exports\n",
1795+
"def trim_wraps(f, n=1):\n",
1796+
" \"Like wraps, but removes the first n parameters from the signature\"\n",
1797+
" import inspect\n",
1798+
" def _(g):\n",
1799+
" g = wraps(f)(g)\n",
1800+
" sig = inspect.signature(f)\n",
1801+
" params = list(sig.parameters.values())[n:]\n",
1802+
" g.__signature__ = sig.replace(parameters=params)\n",
1803+
" return g\n",
1804+
" return _"
1805+
]
1806+
},
1807+
{
1808+
"cell_type": "markdown",
1809+
"metadata": {},
1810+
"source": [
1811+
"`trim_wraps` is a decorator factory that works like `functools.wraps`, but removes the first `n` parameters from the wrapped function's signature. This is useful when creating wrapper functions that consume some parameters internally and shouldn't expose them in the public API."
1812+
]
1813+
},
1814+
{
1815+
"cell_type": "code",
1816+
"execution_count": null,
1817+
"metadata": {},
1818+
"outputs": [
1819+
{
1820+
"name": "stdout",
1821+
"output_type": "stream",
1822+
"text": [
1823+
"adder(x, y)\n"
1824+
]
1825+
}
1826+
],
1827+
"source": [
1828+
"def adder(base, x, y): return base + x + y\n",
1829+
"\n",
1830+
"def make_adder(base_value):\n",
1831+
" @trim_wraps(adder)\n",
1832+
" def _(x, y): return adder(base_value, x, y)\n",
1833+
" return _\n",
1834+
"\n",
1835+
"add_10 = make_adder(10)\n",
1836+
"print(f\"{add_10.__name__}{inspect.signature(add_10)}\")"
1837+
]
1838+
},
1839+
{
1840+
"cell_type": "code",
1841+
"execution_count": null,
1842+
"metadata": {},
1843+
"outputs": [],
1844+
"source": [
1845+
"#| exports\n",
1846+
"class _save_iter:\n",
1847+
" def __init__(self, g, *args, **kw): self.g,self.args,self.kw = g,args,kw\n",
1848+
" def __iter__(self): yield from self.g(self, *self.args, **self.kw)\n",
1849+
"\n",
1850+
"def save_iter(g):\n",
1851+
" @trim_wraps(g)\n",
1852+
" def _(*args, **kwargs): return _save_iter(g, *args, **kwargs)\n",
1853+
" return _"
1854+
]
1855+
},
1856+
{
1857+
"cell_type": "markdown",
1858+
"metadata": {},
1859+
"source": [
1860+
"`save_iter` is a decorator that allows a generator function to store values in the returned iterator object. The generator receives an object as its first parameter, which it can use to store attributes."
1861+
]
1862+
},
1863+
{
1864+
"cell_type": "code",
1865+
"execution_count": null,
1866+
"metadata": {},
1867+
"outputs": [
1868+
{
1869+
"name": "stdout",
1870+
"output_type": "stream",
1871+
"text": [
1872+
"Values: [0, 1, 2, 3, 4]\n",
1873+
"Sum stored: 10\n"
1874+
]
1875+
}
1876+
],
1877+
"source": [
1878+
"@save_iter\n",
1879+
"def sum_range(self, n):\n",
1880+
" total = 0\n",
1881+
" for i in range(n):\n",
1882+
" total += i\n",
1883+
" yield i\n",
1884+
" self.value = total\n",
1885+
"\n",
1886+
"sr = sum_range(5)\n",
1887+
"print(f\"Values: {list(sr)}\")\n",
1888+
"print(f\"Sum stored: {sr.value}\") # Sum stored: 10"
1889+
]
1890+
},
17881891
{
17891892
"cell_type": "code",
17901893
"execution_count": null,

0 commit comments

Comments
 (0)