Skip to content

Commit c8aaa6f

Browse files
authored
Merge pull request #674 from galopyz/patch-setter
Add a setter to patch
2 parents 084c537 + 3416b22 commit c8aaa6f

File tree

2 files changed

+89
-36
lines changed

2 files changed

+89
-36
lines changed

fastcore/basics.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ def __init__(self, f): self.f = f
10341034
def __get__(self, _, f_cls): return MethodType(self.f, f_cls)
10351035

10361036
# %% ../nbs/01_basics.ipynb
1037-
def patch_to(cls, as_prop=False, cls_method=False):
1037+
def patch_to(cls, as_prop=False, cls_method=False, set_prop=False):
10381038
"Decorator: add `f` to `cls`"
10391039
if not isinstance(cls, (tuple,list)): cls=(cls,)
10401040
def _inner(f):
@@ -1046,7 +1046,8 @@ def _inner(f):
10461046
nf.__qualname__ = f"{c_.__name__}.{nm}"
10471047
if cls_method: setattr(c_, nm, _clsmethod(nf))
10481048
else:
1049-
if as_prop: setattr(c_, nm, property(nf))
1049+
if set_prop: setattr(c_, nm, getattr(c_, nm).setter(nf))
1050+
elif as_prop: setattr(c_, nm, property(nf))
10501051
else:
10511052
onm = '_orig_'+nm
10521053
if hasattr(c_, nm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, nm))
@@ -1056,12 +1057,12 @@ def _inner(f):
10561057
return _inner
10571058

10581059
# %% ../nbs/01_basics.ipynb
1059-
def patch(f=None, *, as_prop=False, cls_method=False):
1060+
def patch(f=None, *, as_prop=False, cls_method=False, set_prop=False):
10601061
"Decorator: add `f` to the first parameter's class (based on f's type annotations)"
1061-
if f is None: return partial(patch, as_prop=as_prop, cls_method=cls_method)
1062+
if f is None: return partial(patch, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop)
10621063
ann,glb,loc = get_annotations_ex(f)
10631064
cls = union2tuple(eval_type(ann.pop('cls') if cls_method else next(iter(ann.values())), glb, loc))
1064-
return patch_to(cls, as_prop=as_prop, cls_method=cls_method)(f)
1065+
return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop)(f)
10651066

10661067
# %% ../nbs/01_basics.ipynb
10671068
def patch_property(f):

nbs/01_basics.ipynb

Lines changed: 83 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4700,7 +4700,7 @@
47004700
"text/markdown": [
47014701
"---\n",
47024702
"\n",
4703-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L829){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4703+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L861){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
47044704
"\n",
47054705
"#### fastuple\n",
47064706
"\n",
@@ -4711,7 +4711,7 @@
47114711
"text/plain": [
47124712
"---\n",
47134713
"\n",
4714-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L829){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4714+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L861){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
47154715
"\n",
47164716
"#### fastuple\n",
47174717
"\n",
@@ -4785,7 +4785,7 @@
47854785
"text/markdown": [
47864786
"---\n",
47874787
"\n",
4788-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L848){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4788+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L880){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
47894789
"\n",
47904790
"##### fastuple.add\n",
47914791
"\n",
@@ -4796,7 +4796,7 @@
47964796
"text/plain": [
47974797
"---\n",
47984798
"\n",
4799-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L848){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4799+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L880){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
48004800
"\n",
48014801
"##### fastuple.add\n",
48024802
"\n",
@@ -4835,7 +4835,7 @@
48354835
"text/markdown": [
48364836
"---\n",
48374837
"\n",
4838-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L844){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4838+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L876){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
48394839
"\n",
48404840
"##### fastuple.mul\n",
48414841
"\n",
@@ -4846,7 +4846,7 @@
48464846
"text/plain": [
48474847
"---\n",
48484848
"\n",
4849-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L844){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4849+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L876){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
48504850
"\n",
48514851
"##### fastuple.mul\n",
48524852
"\n",
@@ -4996,7 +4996,7 @@
49964996
"text/markdown": [
49974997
"---\n",
49984998
"\n",
4999-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L875){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
4999+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L907){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
50005000
"\n",
50015001
"### bind\n",
50025002
"\n",
@@ -5007,7 +5007,7 @@
50075007
"text/plain": [
50085008
"---\n",
50095009
"\n",
5010-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L875){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
5010+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L907){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
50115011
"\n",
50125012
"### bind\n",
50135013
"\n",
@@ -5645,7 +5645,7 @@
56455645
"outputs": [],
56465646
"source": [
56475647
"#|export\n",
5648-
"def patch_to(cls, as_prop=False, cls_method=False):\n",
5648+
"def patch_to(cls, as_prop=False, cls_method=False, set_prop=False):\n",
56495649
" \"Decorator: add `f` to `cls`\"\n",
56505650
" if not isinstance(cls, (tuple,list)): cls=(cls,)\n",
56515651
" def _inner(f):\n",
@@ -5657,7 +5657,8 @@
56575657
" nf.__qualname__ = f\"{c_.__name__}.{nm}\"\n",
56585658
" if cls_method: setattr(c_, nm, _clsmethod(nf))\n",
56595659
" else:\n",
5660-
" if as_prop: setattr(c_, nm, property(nf))\n",
5660+
" if set_prop: setattr(c_, nm, getattr(c_, nm).setter(nf))\n",
5661+
" elif as_prop: setattr(c_, nm, property(nf))\n",
56615662
" else:\n",
56625663
" onm = '_orig_'+nm\n",
56635664
" if hasattr(c_, nm) and not hasattr(c_, onm): setattr(c_, onm, getattr(c_, nm))\n",
@@ -5753,6 +5754,35 @@
57535754
"test_eq(t.add_ten, 14)"
57545755
]
57555756
},
5757+
{
5758+
"cell_type": "markdown",
5759+
"metadata": {},
5760+
"source": [
5761+
"Once you have a property, you can assign a setter with `set_prop=True`:"
5762+
]
5763+
},
5764+
{
5765+
"cell_type": "code",
5766+
"execution_count": null,
5767+
"metadata": {},
5768+
"outputs": [],
5769+
"source": [
5770+
"class _T2():\n",
5771+
" def __init__(self, val): self._val = val\n",
5772+
"\n",
5773+
"@patch_to(_T2, as_prop=True)\n",
5774+
"def val(self): return self._val\n",
5775+
"\n",
5776+
"t = _T2(2)\n",
5777+
"test_eq(t.val, 2)\n",
5778+
"\n",
5779+
"@patch_to(_T2, set_prop=True)\n",
5780+
"def val(self, val): self._val = val\n",
5781+
"\n",
5782+
"t.val = 3\n",
5783+
"test_eq(t.val, 3)"
5784+
]
5785+
},
57565786
{
57575787
"cell_type": "markdown",
57585788
"metadata": {},
@@ -5785,12 +5815,12 @@
57855815
"outputs": [],
57865816
"source": [
57875817
"#|export\n",
5788-
"def patch(f=None, *, as_prop=False, cls_method=False):\n",
5818+
"def patch(f=None, *, as_prop=False, cls_method=False, set_prop=False):\n",
57895819
" \"Decorator: add `f` to the first parameter's class (based on f's type annotations)\"\n",
5790-
" if f is None: return partial(patch, as_prop=as_prop, cls_method=cls_method)\n",
5820+
" if f is None: return partial(patch, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop)\n",
57915821
" ann,glb,loc = get_annotations_ex(f)\n",
57925822
" cls = union2tuple(eval_type(ann.pop('cls') if cls_method else next(iter(ann.values())), glb, loc))\n",
5793-
" return patch_to(cls, as_prop=as_prop, cls_method=cls_method)(f)"
5823+
" return patch_to(cls, as_prop=as_prop, cls_method=cls_method, set_prop=set_prop)(f)"
57945824
]
57955825
},
57965826
{
@@ -5847,7 +5877,7 @@
58475877
"cell_type": "markdown",
58485878
"metadata": {},
58495879
"source": [
5850-
"Just like `patch_to` decorator you can use `as_prop` and `cls_method` parameters with `patch` decorator:"
5880+
"Just like `patch_to` decorator you can use `as_prop`, `set_prop`, and `cls_method` parameters with `patch` decorator:"
58515881
]
58525882
},
58535883
{
@@ -5863,6 +5893,28 @@
58635893
"test_eq(t.add_ten, 14)"
58645894
]
58655895
},
5896+
{
5897+
"cell_type": "code",
5898+
"execution_count": null,
5899+
"metadata": {},
5900+
"outputs": [],
5901+
"source": [
5902+
"class _T2():\n",
5903+
" def __init__(self, val): self._val = val\n",
5904+
"\n",
5905+
"@patch(as_prop=True)\n",
5906+
"def val(self:_T2): return self._val\n",
5907+
"\n",
5908+
"t = _T2(2)\n",
5909+
"test_eq(t.val, 2)\n",
5910+
"\n",
5911+
"@patch(set_prop=True)\n",
5912+
"def val(self:_T2, val): self._val = val\n",
5913+
"\n",
5914+
"t.val = 3\n",
5915+
"test_eq(t.val, 3)"
5916+
]
5917+
},
58665918
{
58675919
"cell_type": "code",
58685920
"execution_count": null,
@@ -5972,23 +6024,23 @@
59726024
"text/markdown": [
59736025
"---\n",
59746026
"\n",
5975-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1047){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6027+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1080){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
59766028
"\n",
59776029
"#### ImportEnum\n",
59786030
"\n",
5979-
"> ImportEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6031+
"> ImportEnum (value, names=None, module=None, qualname=None, type=None,\n",
59806032
"> start=1, boundary=None)\n",
59816033
"\n",
59826034
"*An `Enum` that can have its values imported*"
59836035
],
59846036
"text/plain": [
59856037
"---\n",
59866038
"\n",
5987-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1047){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6039+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1080){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
59886040
"\n",
59896041
"#### ImportEnum\n",
59906042
"\n",
5991-
"> ImportEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6043+
"> ImportEnum (value, names=None, module=None, qualname=None, type=None,\n",
59926044
"> start=1, boundary=None)\n",
59936045
"\n",
59946046
"*An `Enum` that can have its values imported*"
@@ -6037,23 +6089,23 @@
60376089
"text/markdown": [
60386090
"---\n",
60396091
"\n",
6040-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1055){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6092+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1088){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
60416093
"\n",
60426094
"#### StrEnum\n",
60436095
"\n",
6044-
"> StrEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6096+
"> StrEnum (value, names=None, module=None, qualname=None, type=None,\n",
60456097
"> start=1, boundary=None)\n",
60466098
"\n",
60476099
"*An `ImportEnum` that behaves like a `str`*"
60486100
],
60496101
"text/plain": [
60506102
"---\n",
60516103
"\n",
6052-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1055){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6104+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1088){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
60536105
"\n",
60546106
"#### StrEnum\n",
60556107
"\n",
6056-
"> StrEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6108+
"> StrEnum (value, names=None, module=None, qualname=None, type=None,\n",
60576109
"> start=1, boundary=None)\n",
60586110
"\n",
60596111
"*An `ImportEnum` that behaves like a `str`*"
@@ -6102,23 +6154,23 @@
61026154
"text/markdown": [
61036155
"---\n",
61046156
"\n",
6105-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1065){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6157+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1098){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
61066158
"\n",
61076159
"#### ValEnum\n",
61086160
"\n",
6109-
"> ValEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6161+
"> ValEnum (value, names=None, module=None, qualname=None, type=None,\n",
61106162
"> start=1, boundary=None)\n",
61116163
"\n",
61126164
"*An `ImportEnum` that stringifies using values*"
61136165
],
61146166
"text/plain": [
61156167
"---\n",
61166168
"\n",
6117-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1065){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6169+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1098){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
61186170
"\n",
61196171
"#### ValEnum\n",
61206172
"\n",
6121-
"> ValEnum (new_class_name, names, module=None, qualname=None, type=None,\n",
6173+
"> ValEnum (value, names=None, module=None, qualname=None, type=None,\n",
61226174
"> start=1, boundary=None)\n",
61236175
"\n",
61246176
"*An `ImportEnum` that stringifies using values*"
@@ -6191,7 +6243,7 @@
61916243
"text/markdown": [
61926244
"---\n",
61936245
"\n",
6194-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1070){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6246+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1103){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
61956247
"\n",
61966248
"#### Stateful\n",
61976249
"\n",
@@ -6202,7 +6254,7 @@
62026254
"text/plain": [
62036255
"---\n",
62046256
"\n",
6205-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1070){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6257+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1103){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
62066258
"\n",
62076259
"#### Stateful\n",
62086260
"\n",
@@ -6353,7 +6405,7 @@
63536405
"text/markdown": [
63546406
"---\n",
63556407
"\n",
6356-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1107){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6408+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1140){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
63576409
"\n",
63586410
"#### PrettyString\n",
63596411
"\n",
@@ -6364,7 +6416,7 @@
63646416
"text/plain": [
63656417
"---\n",
63666418
"\n",
6367-
"[source](https://github.com/fastai/fastcore/blob/master/fastcore/basics.py#L1107){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
6419+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L1140){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
63686420
"\n",
63696421
"#### PrettyString\n",
63706422
"\n",
@@ -6489,7 +6541,7 @@
64896541
{
64906542
"data": {
64916543
"text/plain": [
6492-
"10"
6544+
"22"
64936545
]
64946546
},
64956547
"execution_count": null,

0 commit comments

Comments
 (0)