Source code for pymarkup.builder

# from __future__ import annotations
# from unittest.mock import patch
from io import StringIO
from typing import Dict
from dataclasses import dataclass, field


[docs]@dataclass class MarkupBuilder: """ Build basic XML-style markup from context managers. Instances of this class are individual tags with their own attributes. They can be used in context managers\ multiple times. Attributes ---------- element : str The element name to use this tag as (default 'html') text : File-like object The cumulative text generated by this instance. It is automatically passed down to children, and is created by \ default, so it is not necessary to pass it in most of the time. attrs : dict The attributes to put in the opening tag """ element: str = "html" text: StringIO = field(default_factory=StringIO) attrs: Dict = field(default_factory=dict)
[docs] def self_closing(self): """Add self-closing tag, e.g. <img src="image.png"/>""" self.text.write(f'<{self.element}{self._attr_string()}/>')
[docs] def __enter__(self): """Add opening tag, e.g. <html>""" self.text.write(f'\n<{self.element }{self._attr_string()}>')
[docs] def __exit__(self, exc_type, exc_val, exc_tb): """Add closing tag, e.g. </html>""" self.text.write(f'\n</{self.element}>')
[docs] def __add__(self, other): """ Add ``other`` to current text. If ``other`` is a :ref:`MarkupBuilder` just run :ref:`MarkupBuilder.self_closing()` on it, otherwise add \ ``str(other)`` to ``self.text``. Parameters ---------- other : Union[str,MarkupBuilder] The other object to add. """ if isinstance(other, MarkupBuilder): other.self_closing() return self.text.write(f'\n{str(other)}')
[docs] def __getattr__(self, item): """Return a child of this :ref:`MarkupBuilder` with ``item`` as the :ref:`MarkupBuilder.element`""" return MarkupBuilder(item, self.text)
[docs] def __call__(self, **kwargs): """Change this instance's :ref:`attrs` to ``kwargs``.""" self.attrs = kwargs return self
[docs] def __repr__(self): """Get the final XML for this :ref:`MarkupBuilder`""" return self.text.getvalue()[1:]
def _attr_string(self): val = ' '.join(f'{key}="{value}"' for key, value in self.attrs.items()) val = ' ' + val if val else '' return val