This commit is contained in:
Rowan 2025-10-07 17:31:32 -04:00
parent f9b01181e2
commit 1b03a74478
4 changed files with 33 additions and 18 deletions

View file

@ -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()

View file

@ -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)

View file

@ -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'))

View file

@ -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]"