diff --git a/fastcore/_modidx.py b/fastcore/_modidx.py index 9d2cf843..ab96eb72 100644 --- a/fastcore/_modidx.py +++ b/fastcore/_modidx.py @@ -564,6 +564,7 @@ 'fastcore.xml.XT.attrs': ('xml.html#xt.attrs', 'fastcore/xml.py'), 'fastcore.xml.XT.children': ('xml.html#xt.children', 'fastcore/xml.py'), 'fastcore.xml.XT.tag': ('xml.html#xt.tag', 'fastcore/xml.py'), + 'fastcore.xml.__getattr__': ('xml.html#__getattr__', 'fastcore/xml.py'), 'fastcore.xml._attrmap': ('xml.html#_attrmap', 'fastcore/xml.py'), 'fastcore.xml._escape': ('xml.html#_escape', 'fastcore/xml.py'), 'fastcore.xml._to_attr': ('xml.html#_to_attr', 'fastcore/xml.py'), diff --git a/fastcore/xml.py b/fastcore/xml.py index bb9ed2cb..118b6d9f 100644 --- a/fastcore/xml.py +++ b/fastcore/xml.py @@ -1,13 +1,13 @@ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/11_xml.ipynb. # %% auto 0 -__all__ = ['voids', 'XT', 'xt', 'to_xml', 'highlight', 'showtags', 'Html', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', - 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', - 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'A', 'Nav', 'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', - 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption', 'Col', 'Colgroup', 'Form', 'Input', 'Textarea', 'Button', - 'Select', 'Option', 'Label', 'Fieldset', 'Legend', 'Details', 'Summary', 'Main', 'Header', 'Footer', - 'Section', 'Article', 'Aside', 'Figure', 'Figcaption', 'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', - 'Video', 'Audio', 'Source', 'Canvas', 'Svg', 'Math', 'Script', 'Noscript', 'Template', 'Slot'] +__all__ = ['XT', 'xt', 'to_xml', 'highlight', 'showtags', 'Html', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', + 'Div', 'Span', 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', + 'Sup', 'Hr', 'Br', 'Img', 'A', 'Nav', 'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', + 'Tr', 'Th', 'Td', 'Caption', 'Col', 'Colgroup', 'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', + 'Label', 'Fieldset', 'Legend', 'Details', 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', + 'Aside', 'Figure', 'Figcaption', 'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video', 'Audio', + 'Source', 'Canvas', 'Svg', 'Math', 'Script', 'Noscript', 'Template', 'Slot'] # %% ../nbs/11_xml.ipynb 2 from .utils import * @@ -27,7 +27,10 @@ def _attrmap(o): # %% ../nbs/11_xml.ipynb 5 class XT(list): - def __init__(self, tag, cs, attrs=None, **kwargs): super().__init__([tag, cs, {**(attrs or {}), **kwargs}]) + def __init__(self, tag, cs, attrs=None, void_=False, **kwargs): + super().__init__([tag, cs, {**(attrs or {}), **kwargs}]) + self.void_ = void_ + @property def tag(self): return self[0] @property @@ -36,7 +39,7 @@ def children(self): return self[1] def attrs(self): return self[2] def __setattr__(self, k, v): - if k.startswith('__') or k in ('tag','cs','attrs'): return super().__setattr__(k,v) + if k.startswith('__') or k in ('tag','cs','attrs','void_'): return super().__setattr__(k,v) self.attrs[k.lstrip('_').replace('_', '-')] = v def __getattr__(self, k): @@ -44,11 +47,11 @@ def __getattr__(self, k): return self.attrs[k.lstrip('_').replace('_', '-')] # %% ../nbs/11_xml.ipynb 6 -def xt(tag:str, *c, **kw): +def xt(tag:str, *c, void_=False, **kw): "Create an XML tag structure `[tag,children,attrs]` for `toxml()`" if len(c)==1 and isinstance(c[0], types.GeneratorType): c = tuple(c[0]) kw = {_attrmap(k):v for k,v in kw.items() if v is not None} - return XT(tag.lower(),c,kw) + return XT(tag.lower(),c,kw, void_=void_) # %% ../nbs/11_xml.ipynb 7 _g = globals() @@ -65,12 +68,9 @@ def xt(tag:str, *c, **kw): for o in _all_: _g[o] = partial(xt, o.lower()) # %% ../nbs/11_xml.ipynb 14 -voids = set('area base br col command embed hr img input keygen link meta param source track wbr !doctype'.split()) - -# %% ../nbs/11_xml.ipynb 15 def _escape(s): return '' if s is None else escape(s) if isinstance(s, str) else s -# %% ../nbs/11_xml.ipynb 16 +# %% ../nbs/11_xml.ipynb 15 def _to_attr(k,v): if isinstance(v,bool): if v==True : return str(k) @@ -82,7 +82,7 @@ def _to_attr(k,v): if qt in v: qt = "'" return f'{k}={qt}{v}{qt}' -# %% ../nbs/11_xml.ipynb 17 +# %% ../nbs/11_xml.ipynb 16 def to_xml(elm, lvl=0): "Convert `xt` element tree into an XML string" if elm is None: return '' @@ -97,24 +97,31 @@ def to_xml(elm, lvl=0): sattrs = (_to_attr(k,v) for k,v in attrs.items()) stag += ' ' + ' '.join(sattrs) - cltag = '' if tag in voids else f'' + isvoid = getattr(elm, 'void_', False) + cltag = '' if isvoid else f'' if not cs: return f'{sp}<{stag}>{cltag}\n' if len(cs)==1 and not isinstance(cs[0],(list,tuple)) and not hasattr(cs[0],'__xt__'): return f'{sp}<{stag}>{_escape(cs[0])}{cltag}\n' res = f'{sp}<{stag}>\n' res += ''.join(to_xml(c, lvl=lvl+2) for c in cs) - if tag not in voids: res += f'{sp}{cltag}\n' + if not isvoid: res += f'{sp}{cltag}\n' return res -# %% ../nbs/11_xml.ipynb 19 +# %% ../nbs/11_xml.ipynb 18 def highlight(s, lang='xml'): "Markdown to syntax-highlight `s` in language `lang`" return f'```{lang}\n{to_xml(s)}\n```' -# %% ../nbs/11_xml.ipynb 20 +# %% ../nbs/11_xml.ipynb 19 def showtags(s): return f"""
 {escape(to_xml(s))}
 
""" XT._repr_markdown_ = highlight + +# %% ../nbs/11_xml.ipynb 20 +def __getattr__(tag): + if tag.startswith('_') or tag[0].islower(): raise AttributeError + def _f(*c, target_id=None, **kwargs): return xt(tag, *c, target_id=target_id, **kwargs) + return _f diff --git a/nbs/11_xml.ipynb b/nbs/11_xml.ipynb index 15066021..c6232d82 100644 --- a/nbs/11_xml.ipynb +++ b/nbs/11_xml.ipynb @@ -72,7 +72,10 @@ "source": [ "#|export\n", "class XT(list):\n", - " def __init__(self, tag, cs, attrs=None, **kwargs): super().__init__([tag, cs, {**(attrs or {}), **kwargs}])\n", + " def __init__(self, tag, cs, attrs=None, void_=False, **kwargs):\n", + " super().__init__([tag, cs, {**(attrs or {}), **kwargs}])\n", + " self.void_ = void_\n", + "\n", " @property\n", " def tag(self): return self[0]\n", " @property\n", @@ -81,7 +84,7 @@ " def attrs(self): return self[2]\n", "\n", " def __setattr__(self, k, v):\n", - " if k.startswith('__') or k in ('tag','cs','attrs'): return super().__setattr__(k,v)\n", + " if k.startswith('__') or k in ('tag','cs','attrs','void_'): return super().__setattr__(k,v)\n", " self.attrs[k.lstrip('_').replace('_', '-')] = v\n", "\n", " def __getattr__(self, k):\n", @@ -97,11 +100,11 @@ "outputs": [], "source": [ "#| export\n", - "def xt(tag:str, *c, **kw):\n", + "def xt(tag:str, *c, void_=False, **kw):\n", " \"Create an XML tag structure `[tag,children,attrs]` for `toxml()`\"\n", " if len(c)==1 and isinstance(c[0], types.GeneratorType): c = tuple(c[0])\n", " kw = {_attrmap(k):v for k,v in kw.items() if v is not None}\n", - " return XT(tag.lower(),c,kw)" + " return XT(tag.lower(),c,kw, void_=void_)" ] }, { @@ -236,17 +239,6 @@ "elem" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "c7de63a4", - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "voids = set('area base br col command embed hr img input keygen link meta param source track wbr !doctype'.split())" - ] - }, { "cell_type": "code", "execution_count": null, @@ -300,13 +292,14 @@ " sattrs = (_to_attr(k,v) for k,v in attrs.items())\n", " stag += ' ' + ' '.join(sattrs)\n", "\n", - " cltag = '' if tag in voids else f''\n", + " isvoid = getattr(elm, 'void_', False)\n", + " cltag = '' if isvoid else f''\n", " if not cs: return f'{sp}<{stag}>{cltag}\\n'\n", " if len(cs)==1 and not isinstance(cs[0],(list,tuple)) and not hasattr(cs[0],'__xt__'):\n", " return f'{sp}<{stag}>{_escape(cs[0])}{cltag}\\n'\n", " res = f'{sp}<{stag}>\\n'\n", " res += ''.join(to_xml(c, lvl=lvl+2) for c in cs)\n", - " if tag not in voids: res += f'{sp}{cltag}\\n'\n", + " if not isvoid: res += f'{sp}{cltag}\\n'\n", " return res" ] }, @@ -327,8 +320,8 @@ " \n", "
\n", "Some text\n", - " \n", - " \n", + " \n", + " \n", "
\n", " \n", "\n", @@ -370,6 +363,20 @@ "XT._repr_markdown_ = highlight" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "530666f8", + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def __getattr__(tag):\n", + " if tag.startswith('_') or tag[0].islower(): raise AttributeError\n", + " def _f(*c, target_id=None, **kwargs): return xt(tag, *c, target_id=target_id, **kwargs)\n", + " return _f" + ] + }, { "cell_type": "markdown", "id": "df973d4e",