47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
from typing import Callable, Iterable, Self
|
|
from bs4 import BeautifulSoup, Tag
|
|
|
|
from .elements import IdAttr, Template, Node
|
|
from .renderer import Renderable, Renderer
|
|
from .puppytype import Parsable, ParsableIterable, Parsable, Templates
|
|
|
|
class Puppygirl[R: Renderer]:
|
|
renderer: R
|
|
elements: list[Renderable]
|
|
templates: Templates
|
|
|
|
def __init__(self, renderer: R, elements: list[Callable[[Self], Renderable]] = [], templates: ParsableIterable = []):
|
|
self.renderer = renderer
|
|
self.templates = Puppygirl._create_template_dict(templates)
|
|
self.elements = [self._instantiate(el) for el in elements]
|
|
|
|
def _instantiate(self, value: Callable[[Self], Renderable] | Renderable) -> Renderable:
|
|
if(isinstance(value, Callable)):
|
|
return value(self)
|
|
return value
|
|
|
|
def _create_template_dict(templates: Iterable[Parsable]) -> Templates:
|
|
templates = [Template.from_element(t) for t in templates]
|
|
return {t.id: t for t in templates}
|
|
|
|
def add_template(self, template: Parsable):
|
|
template = Template.from_element(template)
|
|
self._templates[template[IdAttr]] = template
|
|
|
|
def _is_parsed(value: Parsable) -> bool:
|
|
return isinstance(value, BeautifulSoup) or \
|
|
isinstance(value, Tag) or \
|
|
isinstance(value, Node) or \
|
|
isinstance(value, Template)
|
|
|
|
def parse(self, value: Parsable) -> BeautifulSoup:
|
|
if value is None:
|
|
return BeautifulSoup(features='html.parser')
|
|
|
|
if Puppygirl._is_parsed(value):
|
|
return self.parse_tree(value)
|
|
|
|
return self.parse_tree(BeautifulSoup(value, features='html.parser'))
|
|
|
|
def parse_tree(self, tree: BeautifulSoup) -> BeautifulSoup:
|
|
return self.renderer.render(self, tree)
|