From afa0170041535770eb4cb0ba08e0b579c0c2a76a Mon Sep 17 00:00:00 2001 From: rowan Date: Wed, 8 Oct 2025 05:51:52 -0400 Subject: [PATCH] yeahyeahyeaheyaehehahwrggvdf --- puppygirl/elements/shadow_root.py | 100 ++++++++++++++++++++---------- puppygirl/pg.py | 2 +- puppygirl/renderer.py | 4 +- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/puppygirl/elements/shadow_root.py b/puppygirl/elements/shadow_root.py index 977eb91..623e659 100644 --- a/puppygirl/elements/shadow_root.py +++ b/puppygirl/elements/shadow_root.py @@ -1,7 +1,7 @@ from copy import copy from dataclasses import dataclass from enum import StrEnum -from typing import TYPE_CHECKING, Optional, Self +from typing import TYPE_CHECKING, Iterable, Optional, Self from bs4 import BeautifulSoup, Tag from ..clonable import Clonable @@ -15,10 +15,67 @@ class ShadowRootMode(StrEnum): Open = "open" Closed = "closed" -@dataclass class Node(Clonable): - _value: Tag + @property + def value(self): pass + def from_path(path: str) -> Self: + with open(path, "r") as f: + soup = BeautifulSoup(f.read(), 'html.parser') + nodes = soup.find_all() + + match len(nodes): + case 0: return EmptyNode() + case 1: return SingleNode(nodes[0]) + case _: return NodeCollection(soup) + + def attach_shadow(self, shadow_root_mode: ShadowRootMode, clonable: Optional[bool] = None, delegates_focus: Optional[bool] = None, serializable: Optional[bool] = None): + return ShadowRoot( + host=self.value, + mode=shadow_root_mode, + clonable=clonable, + delegates_focus=delegates_focus, + serializable=serializable + ) + + def find(self, *args, **kwargs): + return self.value.find(*args, **kwargs) + + def find_all(self, *args, **kwargs): + return self.value.find_all(*args, **kwargs) + + def append(self, *args, **kwargs): + return self.value.append(*args, **kwargs) + + def insert(self, *args, **kwargs): + return self.value.insert(*args, **kwargs) + + def has_attr(self, attr: str) -> bool: + return self.value.has_attr(attr) + + def prettify(self) -> str: + return self.value.prettify() + +class EmptyNode(Node): + @property + def value(self): + return None + +@dataclass +class NodeCollection(Node): + nodes: Iterable[Tag] + + @property + def value(self): + return self.nodes + + def clone(self) -> Self: + return NodeCollection(copy(self.value)) + +@dataclass +class SingleNode(Node): + _value: Tag + @property def value(self): return self._value @@ -32,26 +89,12 @@ class Node(Clonable): serializable=serializable ) - def from_path(path: str) -> Self: - with open(path, "r") as f: - return Node(BeautifulSoup(f.read(), 'html.parser').find()) - - def from_element(element: "Parsable") -> Self: - if isinstance(element, Node): - return element - return Node(element) - - def clone(self) -> "Self": - return Node(copy(self.value)) - - def __getattr__(self, name): - if name == '_value': - raise AttributeError() - return getattr(self._value, name) - def __getitem__(self, index): return self._value[index] + def clone(self) -> Self: + return SingleNode(copy(self.value)) + @dataclass class Template(Clonable): _value: Node @@ -60,6 +103,10 @@ class Template(Clonable): def value(self): return self._value + @property + def id(self): + return self._value["id"] + @property def shadow_root_mode(self) -> ShadowRootMode | None: return self._value.get("shadowrootmode") @@ -104,20 +151,9 @@ class Template(Clonable): def clone(self) -> Self: return Template(copy(self._value)) - def __getattr__(self, name): - if name == '_value': - raise AttributeError() - return getattr(self._value, name) - - def __getitem__(self, index): - return self._value[index] - - def __setitem__(self, index, value): - self._value[index] = value - @dataclass class ShadowRoot(Clonable): - host: "Node" + host: Node mode: ShadowRootMode clonable: Optional[bool] = None diff --git a/puppygirl/pg.py b/puppygirl/pg.py index 53b1a86..287c816 100644 --- a/puppygirl/pg.py +++ b/puppygirl/pg.py @@ -22,7 +22,7 @@ class Puppygirl[R: Renderer]: def _create_template_dict(templates: Iterable[Parsable]) -> Templates: templates = [Template.from_element(t) for t in templates] - return {t[IdAttr]: t for t in templates} + return {t.id: t for t in templates} def add_template(self, template: Parsable): template = Template.from_element(template) diff --git a/puppygirl/renderer.py b/puppygirl/renderer.py index 6cdceda..c434fc8 100644 --- a/puppygirl/renderer.py +++ b/puppygirl/renderer.py @@ -3,7 +3,7 @@ from importlib import resources from typing import TYPE_CHECKING, Iterable, Protocol, runtime_checkable from puppygirl.elements import IdAttr, TemplateName -from puppygirl.elements.shadow_root import Node +from puppygirl.elements.shadow_root import Node, SingleNode from puppygirl.puppytype import Templates if TYPE_CHECKING: @@ -47,7 +47,7 @@ class ServerSideRenderer(Renderer): for element in puppygirl.elements: if hasattr(element, "name"): for tag in tree.find_all(element.name): - new_tag = element.render(Node(tag).clone(), templates) + new_tag = element.render(SingleNode(tag).clone(), templates) if isinstance(new_tag, Iterable): tag.extend(new_tag)