Skip to content

Commit f1dac48

Browse files
committed
fixes #717
1 parent 587642b commit f1dac48

File tree

5 files changed

+62
-103
lines changed

5 files changed

+62
-103
lines changed

fastcore/_modidx.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@
100100
'fastcore.basics._oper': ('basics.html#_oper', 'fastcore/basics.py'),
101101
'fastcore.basics._risinstance': ('basics.html#_risinstance', 'fastcore/basics.py'),
102102
'fastcore.basics._store_attr': ('basics.html#_store_attr', 'fastcore/basics.py'),
103-
'fastcore.basics._strip_patch_name': ('basics.html#_strip_patch_name', 'fastcore/basics.py'),
104103
'fastcore.basics._typeerr': ('basics.html#_typeerr', 'fastcore/basics.py'),
105104
'fastcore.basics._using_attr': ('basics.html#_using_attr', 'fastcore/basics.py'),
106105
'fastcore.basics.add_props': ('basics.html#add_props', 'fastcore/basics.py'),
@@ -346,7 +345,7 @@
346345
'fastcore.foundation.L.argfirst': ('foundation.html#l.argfirst', 'fastcore/foundation.py'),
347346
'fastcore.foundation.L.argwhere': ('foundation.html#l.argwhere', 'fastcore/foundation.py'),
348347
'fastcore.foundation.L.attrgot': ('foundation.html#l.attrgot', 'fastcore/foundation.py'),
349-
'fastcore.foundation.L.batched__': ('foundation.html#l.batched__', 'fastcore/foundation.py'),
348+
'fastcore.foundation.L.batched': ('foundation.html#l.batched', 'fastcore/foundation.py'),
350349
'fastcore.foundation.L.combinations': ('foundation.html#l.combinations', 'fastcore/foundation.py'),
351350
'fastcore.foundation.L.compress': ('foundation.html#l.compress', 'fastcore/foundation.py'),
352351
'fastcore.foundation.L.concat': ('foundation.html#l.concat', 'fastcore/foundation.py'),
@@ -366,7 +365,7 @@
366365
'fastcore.foundation.L.pairwise': ('foundation.html#l.pairwise', 'fastcore/foundation.py'),
367366
'fastcore.foundation.L.partition': ('foundation.html#l.partition', 'fastcore/foundation.py'),
368367
'fastcore.foundation.L.permutations': ('foundation.html#l.permutations', 'fastcore/foundation.py'),
369-
'fastcore.foundation.L.product__': ('foundation.html#l.product__', 'fastcore/foundation.py'),
368+
'fastcore.foundation.L.product': ('foundation.html#l.product', 'fastcore/foundation.py'),
370369
'fastcore.foundation.L.range': ('foundation.html#l.range', 'fastcore/foundation.py'),
371370
'fastcore.foundation.L.reduce': ('foundation.html#l.reduce', 'fastcore/foundation.py'),
372371
'fastcore.foundation.L.renumerate': ('foundation.html#l.renumerate', 'fastcore/foundation.py'),

fastcore/basics.py

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,31 +1051,25 @@ def __init__(self, f): self.f = f
10511051
def __get__(self, _, f_cls): return MethodType(self.f, f_cls)
10521052

10531053
# %% ../nbs/01_basics.ipynb
1054-
def _strip_patch_name(nm):
1055-
"Strip trailing `__` from `nm` if it doesn't start with `_`"
1056-
return nm[:-2] if nm.endswith('__') and not nm.startswith('_') else nm
1057-
1058-
def patch_to(cls, as_prop=False, cls_method=False, set_prop=False, nm=None):
1054+
def patch_to(cls, as_prop=False, cls_method=False, set_prop=False, nm=None, glb=None):
10591055
"Decorator: add `f` to `cls`"
1060-
if not isinstance(cls, (tuple,list)): cls=(cls,)
1056+
if glb is None: glb = sys._getframe(1).f_globals
10611057
def _inner(f):
1062-
for c_ in cls:
1058+
_nm = nm or f.__name__
1059+
for c_ in tuplify(cls):
10631060
nf = copy_func(f)
1064-
fnm = nm or _strip_patch_name(f.__name__)
1065-
# `functools.update_wrapper` when passing patched function to `Pipeline`, so we do it manually
10661061
for o in functools.WRAPPER_ASSIGNMENTS: setattr(nf, o, getattr(f,o))
1067-
nf.__name__ = fnm
1068-
nf.__qualname__ = f"{c_.__name__}.{fnm}"
1069-
if cls_method: setattr(c_, fnm, _clsmethod(nf))
1062+
nf.__name__ = _nm
1063+
nf.__qualname__ = f"{c_.__name__}.{_nm}"
1064+
if cls_method: attr = _clsmethod(nf)
1065+
elif set_prop: attr = getattr(c_, _nm).setter(nf)
1066+
elif as_prop: attr = property(nf)
10701067
else:
1071-
if set_prop: setattr(c_, fnm, getattr(c_, fnm).setter(nf))
1072-
elif as_prop: setattr(c_, fnm, property(nf))
1073-
else:
1074-
onm = '_orig_'+fnm
1075-
if hasattr(c_, fnm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, fnm))
1076-
setattr(c_, fnm, nf)
1077-
# Avoid clobbering existing functions
1078-
return globals().get(fnm, builtins.__dict__.get(fnm, None))
1068+
onm = '_orig_'+_nm
1069+
if hasattr(c_, _nm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, _nm))
1070+
attr = nf
1071+
setattr(c_, _nm, attr)
1072+
return glb.get(_nm, builtins.__dict__.get(_nm, None))
10791073
return _inner
10801074

10811075
# %% ../nbs/01_basics.ipynb
@@ -1090,7 +1084,7 @@ def patch(f=None, *, as_prop=False, cls_method=False, set_prop=False, nm=None):
10901084
if not ann: raise TypeError(f"@patch requires the first parameter of `{f.__name__}` to have a type annotation")
10911085
cls = next(iter(ann.values()))
10921086
cls = union2tuple(eval_type(cls, glb, loc))
1093-
return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop, nm=nm)(f)
1087+
return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop, nm=nm, glb=sys._getframe(1).f_globals)(f)
10941088

10951089
# %% ../nbs/01_basics.ipynb
10961090
def compile_re(pat):

fastcore/foundation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ def sum(self:L):
409409

410410
# %% ../nbs/02_foundation.ipynb
411411
@patch
412-
def product__(self:L):
412+
def product(self:L):
413413
"Product of the items"
414414
return self.reduce(operator.mul, 1)
415415

@@ -493,7 +493,7 @@ def _batched(iterable, n):
493493

494494
# %% ../nbs/02_foundation.ipynb
495495
@patch
496-
def batched__(self:L, n):
496+
def batched(self:L, n):
497497
"Same as `itertools.batched`"
498498
return self._new(batched(self, n))
499499

nbs/01_basics.ipynb

Lines changed: 41 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,31 @@
12151215
"execution_count": null,
12161216
"id": "da11467b",
12171217
"metadata": {},
1218-
"outputs": [],
1218+
"outputs": [
1219+
{
1220+
"data": {
1221+
"text/markdown": [
1222+
"---\n",
1223+
"\n",
1224+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L198){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1225+
"\n",
1226+
"### Inf\n",
1227+
"\n",
1228+
"> Inf ()\n",
1229+
"\n",
1230+
"*Infinite lists*"
1231+
],
1232+
"text/plain": [
1233+
"> Inf ()\n",
1234+
"\n",
1235+
"*Infinite lists*"
1236+
]
1237+
},
1238+
"execution_count": null,
1239+
"metadata": {},
1240+
"output_type": "execute_result"
1241+
}
1242+
],
12191243
"source": [
12201244
"show_doc(Inf);"
12211245
]
@@ -6035,36 +6059,30 @@
60356059
{
60366060
"cell_type": "code",
60376061
"execution_count": null,
6038-
"id": "97f2fee5",
6062+
"id": "3f2733ef",
60396063
"metadata": {},
60406064
"outputs": [],
60416065
"source": [
60426066
"#| export\n",
6043-
"def _strip_patch_name(nm):\n",
6044-
" \"Strip trailing `__` from `nm` if it doesn't start with `_`\"\n",
6045-
" return nm[:-2] if nm.endswith('__') and not nm.startswith('_') else nm\n",
6046-
"\n",
6047-
"def patch_to(cls, as_prop=False, cls_method=False, set_prop=False, nm=None):\n",
6067+
"def patch_to(cls, as_prop=False, cls_method=False, set_prop=False, nm=None, glb=None):\n",
60486068
" \"Decorator: add `f` to `cls`\"\n",
6049-
" if not isinstance(cls, (tuple,list)): cls=(cls,)\n",
6069+
" if glb is None: glb = sys._getframe(1).f_globals\n",
60506070
" def _inner(f):\n",
6051-
" for c_ in cls:\n",
6071+
" _nm = nm or f.__name__\n",
6072+
" for c_ in tuplify(cls):\n",
60526073
" nf = copy_func(f)\n",
6053-
" fnm = nm or _strip_patch_name(f.__name__)\n",
6054-
" # `functools.update_wrapper` when passing patched function to `Pipeline`, so we do it manually\n",
60556074
" for o in functools.WRAPPER_ASSIGNMENTS: setattr(nf, o, getattr(f,o))\n",
6056-
" nf.__name__ = fnm\n",
6057-
" nf.__qualname__ = f\"{c_.__name__}.{fnm}\"\n",
6058-
" if cls_method: setattr(c_, fnm, _clsmethod(nf))\n",
6075+
" nf.__name__ = _nm\n",
6076+
" nf.__qualname__ = f\"{c_.__name__}.{_nm}\"\n",
6077+
" if cls_method: attr = _clsmethod(nf)\n",
6078+
" elif set_prop: attr = getattr(c_, _nm).setter(nf)\n",
6079+
" elif as_prop: attr = property(nf)\n",
60596080
" else:\n",
6060-
" if set_prop: setattr(c_, fnm, getattr(c_, fnm).setter(nf))\n",
6061-
" elif as_prop: setattr(c_, fnm, property(nf))\n",
6062-
" else:\n",
6063-
" onm = '_orig_'+fnm\n",
6064-
" if hasattr(c_, fnm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, fnm))\n",
6065-
" setattr(c_, fnm, nf)\n",
6066-
" # Avoid clobbering existing functions\n",
6067-
" return globals().get(fnm, builtins.__dict__.get(fnm, None))\n",
6081+
" onm = '_orig_'+_nm\n",
6082+
" if hasattr(c_, _nm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, _nm))\n",
6083+
" attr = nf\n",
6084+
" setattr(c_, _nm, attr)\n",
6085+
" return glb.get(_nm, builtins.__dict__.get(_nm, None))\n",
60686086
" return _inner"
60696087
]
60706088
},
@@ -6246,32 +6264,6 @@
62466264
"assert not hasattr(t, 'func2')"
62476265
]
62486266
},
6249-
{
6250-
"cell_type": "markdown",
6251-
"id": "81877f71",
6252-
"metadata": {},
6253-
"source": [
6254-
"A `__` suffix is stripped (unless there's also a `_` prefix):"
6255-
]
6256-
},
6257-
{
6258-
"cell_type": "code",
6259-
"execution_count": null,
6260-
"id": "cdd9dedb",
6261-
"metadata": {},
6262-
"outputs": [],
6263-
"source": [
6264-
"class _T9(int): pass \n",
6265-
"\n",
6266-
"@patch_to(_T9)\n",
6267-
"def func__(self, a): return self+a\n",
6268-
"\n",
6269-
"t = _T9(1)\n",
6270-
"test_eq(t.func(2), 3)\n",
6271-
"test_eq(_T9.func.__name__, 'func')\n",
6272-
"assert not hasattr(t, 'func__')"
6273-
]
6274-
},
62756267
{
62766268
"cell_type": "code",
62776269
"execution_count": null,
@@ -6291,7 +6283,7 @@
62916283
" if not ann: raise TypeError(f\"@patch requires the first parameter of `{f.__name__}` to have a type annotation\")\n",
62926284
" cls = next(iter(ann.values()))\n",
62936285
" cls = union2tuple(eval_type(cls, glb, loc))\n",
6294-
" return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop, nm=nm)(f)"
6286+
" return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop, nm=nm, glb=sys._getframe(1).f_globals)(f)"
62956287
]
62966288
},
62976289
{
@@ -6426,24 +6418,6 @@
64266418
"assert not hasattr(t, 'func2')"
64276419
]
64286420
},
6429-
{
6430-
"cell_type": "code",
6431-
"execution_count": null,
6432-
"id": "fdbfff66",
6433-
"metadata": {},
6434-
"outputs": [],
6435-
"source": [
6436-
"class _T9(int): pass \n",
6437-
"\n",
6438-
"@patch\n",
6439-
"def func__(self:_T9, a): return self+a\n",
6440-
"\n",
6441-
"t = _T9(1)\n",
6442-
"test_eq(t.func(2), 3)\n",
6443-
"test_eq(_T9.func.__name__, 'func')\n",
6444-
"assert not hasattr(t, 'func__')"
6445-
]
6446-
},
64476421
{
64486422
"cell_type": "markdown",
64496423
"id": "d9310d77",

nbs/02_foundation.ipynb

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,7 +2297,7 @@
22972297
"source": [
22982298
"#| export\n",
22992299
"@patch\n",
2300-
"def product__(self:L):\n",
2300+
"def product(self:L):\n",
23012301
" \"Product of the items\"\n",
23022302
" return self.reduce(operator.mul, 1)"
23032303
]
@@ -2706,7 +2706,7 @@
27062706
"source": [
27072707
"#| export\n",
27082708
"@patch\n",
2709-
"def batched__(self:L, n):\n",
2709+
"def batched(self:L, n):\n",
27102710
" \"Same as `itertools.batched`\"\n",
27112711
" return self._new(batched(self, n))"
27122712
]
@@ -2980,14 +2980,6 @@
29802980
"test_eq(L([1,2,3]).flatten(), [1,2,3]) # already flat"
29812981
]
29822982
},
2983-
{
2984-
"cell_type": "markdown",
2985-
"id": "88fa0ef8",
2986-
"metadata": {},
2987-
"source": [
2988-
"##### User"
2989-
]
2990-
},
29912983
{
29922984
"cell_type": "markdown",
29932985
"id": "8cf19e29",

0 commit comments

Comments
 (0)