From 1b03a74478a159001d9d94c2f3245d754586b833 Mon Sep 17 00:00:00 2001 From: rowan Date: Tue, 7 Oct 2025 17:31:32 -0400 Subject: [PATCH] earwrf --- puppygirl/__main__.py | 3 ++- puppygirl/elements/shadow_root.py | 16 ++++++++++++---- puppygirl/pg.py | 23 ++++++++++++++--------- puppygirl/puppytype.py | 9 +++++---- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/puppygirl/__main__.py b/puppygirl/__main__.py index fdbf37e..3fb2ec2 100644 --- a/puppygirl/__main__.py +++ b/puppygirl/__main__.py @@ -3,6 +3,7 @@ from argparse import ArgumentParser from puppygirl import Puppygirl from puppygirl.elements.domme import PuppygirlDomme +from puppygirl.elements import Node from puppygirl.renderer import ClientSideRenderer, ServerSideRenderer parser = ArgumentParser("puppygirl", add_help=True) @@ -24,7 +25,7 @@ def main(): renderer = ServerSideRenderer() pg = Puppygirl(renderer=renderer, elements=[PuppygirlDomme]) - html = pg.fetch(args.input) + html = pg.parse(Node.from_path(args.input)) if args.pretty: html = html.prettify() diff --git a/puppygirl/elements/shadow_root.py b/puppygirl/elements/shadow_root.py index 850f7dd..97b82c9 100644 --- a/puppygirl/elements/shadow_root.py +++ b/puppygirl/elements/shadow_root.py @@ -3,11 +3,11 @@ from dataclasses import dataclass from enum import StrEnum from typing import TYPE_CHECKING, Optional, Self -from bs4 import Tag +from bs4 import BeautifulSoup, Tag from ..clonable import Clonable if TYPE_CHECKING: - from ..puppytype import ElementLike + from ..puppytype import Parsable TemplateName = "template" @@ -32,7 +32,11 @@ class Node(Clonable): serializable=serializable ) - def from_element(element: "ElementLike") -> Self: + def from_path(path: str) -> Self: + with open(path, "r") as f: + return Node(BeautifulSoup(f.read(), 'html.parser')) + + def from_element(element: "Parsable") -> Self: if isinstance(element, Node): return element return Node(element) @@ -88,7 +92,11 @@ class Template(Clonable): def serializable(self, value: bool): self._value["serializable"] = value - def from_element(element: "ElementLike") -> Self: + def from_path(path: str) -> Self: + with open(path, "r") as f: + return Template(BeautifulSoup(f.read(), 'html.parser')) + + def from_element(element: "Parsable") -> Self: if isinstance(element, Template): return element return Template(element) diff --git a/puppygirl/pg.py b/puppygirl/pg.py index 3f61a61..be68a63 100644 --- a/puppygirl/pg.py +++ b/puppygirl/pg.py @@ -1,16 +1,16 @@ from typing import Callable, Iterable, Self from bs4 import BeautifulSoup, Tag -from .elements import IdAttr, Template +from .elements import IdAttr, Template, Node from .renderer import Renderable, Renderer -from .puppytype import ElementLike, ElementLikeList, Parsable, Templates +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: ElementLikeList = []): + 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] @@ -20,20 +20,25 @@ class Puppygirl[R: Renderer]: return value(self) return value - def _create_template_dict(templates: Iterable[ElementLike]) -> Templates: + 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} - def add_template(self, template: ElementLike): + def add_template(self, template: Parsable): template = Template.from_element(template) self._templates[template[IdAttr]] = template - def fetch(self, path: str) -> BeautifulSoup: - with open(path, "r") as f: - return self.parse(f) + 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 isinstance(value, BeautifulSoup) or isinstance(value, Tag): + if value is None: + return BeautifulSoup() + + if Puppygirl._is_parsed(value): return self.parse_tree(value) return self.parse_tree(BeautifulSoup(value, features='html.parser')) diff --git a/puppygirl/puppytype.py b/puppygirl/puppytype.py index 4c4c30c..2026d5c 100644 --- a/puppygirl/puppytype.py +++ b/puppygirl/puppytype.py @@ -1,12 +1,13 @@ -from typing import BinaryIO, Iterable, TextIO, TypeAlias, TYPE_CHECKING +from typing import IO, Iterable, TypeAlias, TYPE_CHECKING if TYPE_CHECKING: from string import Template from bs4 import BeautifulSoup, Tag from .elements import Node -Parsable: TypeAlias = "BeautifulSoup | Tag | str | bytes | TextIO | BinaryIO" -ElementLike: TypeAlias = "BeautifulSoup | Tag | str | Node | Template" -ElementLikeList: TypeAlias = "Iterable[ElementLike]" +Markup: TypeAlias = str | bytes | IO[str] | IO[bytes] +ParsedMarkup: TypeAlias = "BeautifulSoup | Tag | Node | Template" +Parsable: TypeAlias = Markup | ParsedMarkup +ParsableIterable: TypeAlias = "Iterable[Parsable]" RenderableElement: TypeAlias = "Node | Iterable[Node]" Templates: TypeAlias = "dict[str, Template]"