From 85b96ca0795fa5e304387eefaf9a10199d5bef01 Mon Sep 17 00:00:00 2001 From: Jeremy Howard Date: Wed, 16 Oct 2024 15:40:34 +1000 Subject: [PATCH] fixes #640 --- fastcore/__init__.py | 2 +- fastcore/_modidx.py | 3 +- fastcore/xml.py | 38 ++++++++++++--------- nbs/11_xml.ipynb | 81 ++++++++++++-------------------------------- settings.ini | 2 +- 5 files changed, 48 insertions(+), 78 deletions(-) diff --git a/fastcore/__init__.py b/fastcore/__init__.py index 29367f24..69ced6ed 100644 --- a/fastcore/__init__.py +++ b/fastcore/__init__.py @@ -1 +1 @@ -__version__ = "1.7.16" +__version__ = "1.7.17" diff --git a/fastcore/_modidx.py b/fastcore/_modidx.py index 5aedfc31..41e380d5 100644 --- a/fastcore/_modidx.py +++ b/fastcore/_modidx.py @@ -595,7 +595,6 @@ 'fastcore.xdg.xdg_runtime_dir': ('xdg.html#xdg_runtime_dir', 'fastcore/xdg.py'), 'fastcore.xdg.xdg_state_home': ('xdg.html#xdg_state_home', 'fastcore/xdg.py')}, 'fastcore.xml': { 'fastcore.xml.FT': ('xml.html#ft', 'fastcore/xml.py'), - 'fastcore.xml.FT.__add__': ('xml.html#ft.__add__', 'fastcore/xml.py'), 'fastcore.xml.FT.__call__': ('xml.html#ft.__call__', 'fastcore/xml.py'), 'fastcore.xml.FT.__getattr__': ('xml.html#ft.__getattr__', 'fastcore/xml.py'), 'fastcore.xml.FT.__getitem__': ('xml.html#ft.__getitem__', 'fastcore/xml.py'), @@ -604,8 +603,10 @@ 'fastcore.xml.FT.__repr__': ('xml.html#ft.__repr__', 'fastcore/xml.py'), 'fastcore.xml.FT.__setattr__': ('xml.html#ft.__setattr__', 'fastcore/xml.py'), 'fastcore.xml.FT.__setitem__': ('xml.html#ft.__setitem__', 'fastcore/xml.py'), + 'fastcore.xml.FT.changed': ('xml.html#ft.changed', 'fastcore/xml.py'), 'fastcore.xml.FT.get': ('xml.html#ft.get', 'fastcore/xml.py'), 'fastcore.xml.FT.list': ('xml.html#ft.list', 'fastcore/xml.py'), + 'fastcore.xml.FT.on': ('xml.html#ft.on', 'fastcore/xml.py'), 'fastcore.xml.FT.set': ('xml.html#ft.set', 'fastcore/xml.py'), 'fastcore.xml.Html': ('xml.html#html', 'fastcore/xml.py'), 'fastcore.xml.Safe': ('xml.html#safe', 'fastcore/xml.py'), diff --git a/fastcore/xml.py b/fastcore/xml.py index acf73207..830d20d3 100644 --- a/fastcore/xml.py +++ b/fastcore/xml.py @@ -58,10 +58,17 @@ class FT: def __init__(self, tag:str, cs:tuple, attrs:dict=None, void_=False, **kwargs): assert isinstance(cs, tuple) self.tag,self.children,self.attrs,self.void_ = tag,cs,attrs,void_ + self.listeners_ = [] + + def on(self, f): self.listeners_.append(f) + def changed(self): + [f(self) for f in self.listeners_] + return self def __setattr__(self, k, v): - if k.startswith('__') or k in ('tag','children','attrs','void_'): return super().__setattr__(k,v) + if k.startswith('__') or k[-1]=='_' or k in ('tag','children','attrs','void_'): return super().__setattr__(k,v) self.attrs[k.lstrip('_').replace('_', '-')] = v + self.changed() def __getattr__(self, k): if k.startswith('__'): raise AttributeError(k) @@ -71,28 +78,27 @@ def __getattr__(self, k): def list(self): return [self.tag,self.children,self.attrs] def get(self, k, default=None): return self.attrs.get(k.lstrip('_').replace('_', '-'), default) def __repr__(self): return f'{self.tag}({self.children},{self.attrs})' - - def __add__(self, b): - self.children = self.children + tuplify(b) - return self + def __iter__(self): return iter(self.children) + def __getitem__(self, idx): return self.children[idx] def __setitem__(self, i, o): self.children = self.children[:i] + (o,) + self.children[i+1:] - - def __getitem__(self, idx): return self.children[idx] - def __iter__(self): return iter(self.children) + self.changed() def __call__(self, *c, **kw): c,kw = _preproc(c,kw) - if c: self = self+c + if c: self.children = self.children+c if kw: self.attrs = {**self.attrs, **kw} - return self + return self.changed() - def set(self, *o, **k): - "Set children and/or attributes—chainable" - if o: self.children = o - for k,v in k.items(): setattr(self,k,v) - return self + def set(self, *c, **kw): + "Set children and/or attributes (chainable)" + c,kw = _preproc(c,kw) + if c: self.children = c + if kw: + self.attrs = {k:v for k,v in self.attrs.items() if k in ('id','name')} + self.attrs = {**self.attrs, **kw} + return self.changed() # %% ../nbs/11_xml.ipynb def ft(tag:str, *c, void_:bool=False, attrmap:callable=attrmap, valmap:callable=valmap, ft_cls=FT, **kw): @@ -175,7 +181,7 @@ def _to_xml(elm, lvl=0, indent=True, do_escape=True): stag = tag if attrs: - sattrs = ' '.join(_to_attr(k, v) for k, v in attrs.items() if v not in (False, None, '')) + sattrs = ' '.join(_to_attr(k, v) for k, v in attrs.items() if v not in (False, None, '') and k[-1]!='_') if sattrs: stag += f' {sattrs}' cltag = '' if is_void else f'' diff --git a/nbs/11_xml.ipynb b/nbs/11_xml.ipynb index d0251c90..51651634 100644 --- a/nbs/11_xml.ipynb +++ b/nbs/11_xml.ipynb @@ -134,10 +134,17 @@ " def __init__(self, tag:str, cs:tuple, attrs:dict=None, void_=False, **kwargs):\n", " assert isinstance(cs, tuple)\n", " self.tag,self.children,self.attrs,self.void_ = tag,cs,attrs,void_\n", + " self.listeners_ = []\n", + " \n", + " def on(self, f): self.listeners_.append(f)\n", + " def changed(self):\n", + " [f(self) for f in self.listeners_]\n", + " return self\n", "\n", " def __setattr__(self, k, v):\n", - " if k.startswith('__') or k in ('tag','children','attrs','void_'): return super().__setattr__(k,v)\n", + " if k.startswith('__') or k[-1]=='_' or k in ('tag','children','attrs','void_'): return super().__setattr__(k,v)\n", " self.attrs[k.lstrip('_').replace('_', '-')] = v\n", + " self.changed()\n", "\n", " def __getattr__(self, k):\n", " if k.startswith('__'): raise AttributeError(k)\n", @@ -147,28 +154,27 @@ " def list(self): return [self.tag,self.children,self.attrs]\n", " def get(self, k, default=None): return self.attrs.get(k.lstrip('_').replace('_', '-'), default)\n", " def __repr__(self): return f'{self.tag}({self.children},{self.attrs})'\n", - "\n", - " def __add__(self, b):\n", - " self.children = self.children + tuplify(b)\n", - " return self\n", + " def __iter__(self): return iter(self.children)\n", + " def __getitem__(self, idx): return self.children[idx]\n", " \n", " def __setitem__(self, i, o):\n", " self.children = self.children[:i] + (o,) + self.children[i+1:]\n", - "\n", - " def __getitem__(self, idx): return self.children[idx]\n", - " def __iter__(self): return iter(self.children)\n", + " self.changed()\n", "\n", " def __call__(self, *c, **kw):\n", " c,kw = _preproc(c,kw)\n", - " if c: self = self+c\n", + " if c: self.children = self.children+c\n", " if kw: self.attrs = {**self.attrs, **kw}\n", - " return self\n", + " return self.changed()\n", "\n", - " def set(self, *o, **k):\n", - " \"Set children and/or attributes—chainable\"\n", - " if o: self.children = o\n", - " for k,v in k.items(): setattr(self,k,v)\n", - " return self" + " def set(self, *c, **kw):\n", + " \"Set children and/or attributes (chainable)\"\n", + " c,kw = _preproc(c,kw)\n", + " if c: self.children = c\n", + " if kw:\n", + " self.attrs = {k:v for k,v in self.attrs.items() if k in ('id','name')}\n", + " self.attrs = {**self.attrs, **kw}\n", + " return self.changed()" ] }, { @@ -207,49 +213,6 @@ "for o in _all_: _g[o] = partial(ft, o.lower(), void_=o.lower() in voids)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "306844ba", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "body((div(('hi',),{'a': 1, 'b': True, 'class': None}), p(('hi',),{'class': 'a 1', 'style': 'a:1; b:2'})),{})" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = Body(Div('hi', a=1, b=True, cls=()), P('hi', cls=['a',1], style=dict(a=1,b=2)))\n", - "a" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "500f358a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "body((div(('hi',),{'a': 1, 'b': True, 'class': None}), p(('hi',),{'class': 'a 1', 'style': 'a:1; b:2'}), p(('a',),{}), p(('b',),{})),{})" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a + (P('a'),P('b'))" - ] - }, { "cell_type": "markdown", "id": "732e44ab", @@ -462,7 +425,7 @@ "\n", " stag = tag\n", " if attrs:\n", - " sattrs = ' '.join(_to_attr(k, v) for k, v in attrs.items() if v not in (False, None, ''))\n", + " sattrs = ' '.join(_to_attr(k, v) for k, v in attrs.items() if v not in (False, None, '') and k[-1]!='_')\n", " if sattrs: stag += f' {sattrs}'\n", "\n", " cltag = '' if is_void else f''\n", diff --git a/settings.ini b/settings.ini index c47fcc97..53fac6a4 100644 --- a/settings.ini +++ b/settings.ini @@ -8,7 +8,7 @@ author = Jeremy Howard and Sylvain Gugger author_email = infos@fast.ai copyright = fast.ai branch = master -version = 1.7.16 +version = 1.7.17 min_python = 3.8 audience = Developers language = English