Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
fb0176b
Autogenerate stubs using scripts/create_baseline_stubs.py weasyprint
TuringTux Jan 31, 2026
f750a13
Start adding a few type hints for HTML
TuringTux Jan 31, 2026
427bbda
Upgrade stubs to latest versions
TuringTux Jul 13, 2026
0842b94
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
46f8cc3
Add further types
TuringTux Jul 13, 2026
bdaab60
Mark undocumented properties as undocumented
TuringTux Jul 13, 2026
0425f51
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
88e9688
Annotate color_profiles
TuringTux Jul 13, 2026
213f456
Fix broken toml key
TuringTux Jul 13, 2026
86286e9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
931bd96
Add further annotations in __init__.pyi
TuringTux Jul 13, 2026
e15bfbb
Try inferring type of layer
TuringTux Jul 13, 2026
3da66c6
Add missing "| None"
TuringTux Jul 13, 2026
6d3440a
Guess type to be string
TuringTux Jul 13, 2026
4dfb333
Fix pre-commit check warnings for __init__.pyi
TuringTux Jul 13, 2026
190b8a6
Delete files which we won't need type annotations for
TuringTux Jul 13, 2026
dd8d51f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
1d953f4
Add FontConfiguration stub
TuringTux Jul 13, 2026
a32a507
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
7a85e56
Try adding dependencies
TuringTux Jul 13, 2026
1abc58d
Add two typehints for urls.py
TuringTux Jul 13, 2026
e0fb952
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
7c28b5a
Remove dependency which does not have any types provided
TuringTux Jul 13, 2026
a120724
Cheaply stub types for now
TuringTux Jul 13, 2026
27940ab
Consistently apply naming
TuringTux Jul 13, 2026
11a204d
Fix misreading error (it's not pypdf, its pydyf)
TuringTux Jul 13, 2026
8c41e38
Fix typo
TuringTux Jul 13, 2026
9aa6d4f
Use likely more accurate Reader type instead of underspecified IO type
TuringTux Jul 13, 2026
df0a682
Add types to dict
TuringTux Jul 13, 2026
97e8a13
Cheap out and just make the dicts all "Incomplete"
TuringTux Jul 13, 2026
12a7f32
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
582e91d
Revert "Use likely more accurate Reader type instead of underspecifie…
TuringTux Jul 13, 2026
bf75073
Add generic annotations
TuringTux Jul 13, 2026
b59e392
Avoid mentioning CounterName
TuringTux Jul 13, 2026
f844d02
Try avoiding generics altogether
TuringTux Jul 13, 2026
2d885d1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyrightconfig.stricter.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"stubs/tensorflow",
"stubs/tqdm",
"stubs/vobject",
"stubs/weasyprint",
"stubs/workalendar",
"stubs/xmldiff",
],
Expand Down
2 changes: 2 additions & 0 deletions stubs/weasyprint/METADATA.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
version = "69.0.*"
upstream-repository = "https://github.com/Kozea/WeasyPrint"
Comment thread
TuringTux marked this conversation as resolved.
146 changes: 146 additions & 0 deletions stubs/weasyprint/weasyprint/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
from _typeshed import Incomplete
from collections.abc import Callable
from datetime import datetime
from pathlib import Path
from typing import Any, BinaryIO, TextIO, TypeAlias, TypedDict
from typing_extensions import Unpack
from xml.etree.ElementTree import Element

from .css import ColorProfile
from .css.counters import CounterStyle
from .document import Document as Document, Page as Page
from .text.fonts import FontConfiguration
from .urls import URLFetcher, default_url_fetcher as default_url_fetcher

_ElementWrapper: TypeAlias = Any # actually csselect2.ElementWrapper
_Matcher: TypeAlias = Any # actually csselect2.Matcher
_PDF: TypeAlias = Any # actually pydyf.PDF

__all__ = [
"CSS",
"DEFAULT_OPTIONS",
"HTML",
"VERSION",
"Attachment",
"Document",
"Page",
"__version__",
"default_url_fetcher",
"Options",
"PageRule",
"Selector",
]

VERSION: str
__version__: str
DEFAULT_OPTIONS: Options

class Options(TypedDict):
stylesheets: Incomplete
attachments: Incomplete
attachment_relationships: Incomplete
pdf_identifier: Incomplete
pdf_variant: Incomplete
pdf_version: Incomplete
pdf_forms: Incomplete
pdf_tags: Incomplete
uncompressed_pdf: Incomplete
xmp_metadata: Incomplete
custom_metadata: Incomplete
presentational_hints: Incomplete
output_intent: Incomplete
optimize_images: Incomplete
jpeg_quality: Incomplete
dpi: Incomplete
full_fonts: Incomplete
hinting: Incomplete
cache: Incomplete

Selector: TypeAlias = tuple[Incomplete, str | None, Incomplete]
PageRule: TypeAlias = tuple[Incomplete, list[Selector], Incomplete]

class HTML:
base_url: str | Path | None # undocumented
url_fetcher: URLFetcher # undocumented
media_type: str # undocumented
wrapper_element: _ElementWrapper # undocumented
etree_element: Element # undocumented
def __init__(
self,
guess: str | Path | TextIO | BinaryIO | None = None,
filename: str | Path | None = None,
url: str | None = None,
file_obj: TextIO | BinaryIO | None = None,
string: str | None = None,
encoding: str | None = None,
base_url: str | Path | None = None,
url_fetcher: URLFetcher | None = None,
media_type: str = "print",
) -> None: ...
def render(
self,
font_config: FontConfiguration | None = None,
counter_style: CounterStyle | None = None,
color_profiles: dict[str, ColorProfile] | None = None,
**options: Unpack[Options],
) -> Document: ...
def write_pdf(
self,
target: str | Path | TextIO | BinaryIO | None = None,
zoom: float = 1,
finisher: Callable[[Document, _PDF], Any] | None = None,
font_config: FontConfiguration | None = None,
counter_style: CounterStyle | None = None,
color_profiles: dict[str, ColorProfile] | None = None,
**options: Unpack[Options],
) -> bytes | None: ...

class CSS:
base_url: str | Path | None # undocumented
matcher: _Matcher # undocumented
page_rules: list[PageRule] # undocumented
layers: list[str] # undocumented
def __init__(
self,
guess: str | Path | TextIO | BinaryIO | None = None,
filename: str | Path | None = None,
url: str | None = None,
file_obj: TextIO | BinaryIO | None = None,
string: str | None = None,
encoding: str | None = None,
base_url: str | Path | None = None,
url_fetcher: URLFetcher | None = None,
_check_mime_type: bool = False,
media_type: str = "print",
font_config: FontConfiguration | None = None,
counter_style: CounterStyle | None = None,
color_profiles: dict[str, ColorProfile] | None = None,
matcher: _Matcher | None = None,
page_rules: list[PageRule] | None = None,
layers: list[str] | None = None,
layer: str | None = None,
) -> None: ...

class Attachment:
source: tuple[TextIO | BinaryIO, str, str | None, str | None] # undocumented
name: str | None # undocumented
description: str | None # undocumented
relationship: str # undocumented
md5: Incomplete # undocumented
created: datetime # undocumented
modified: datetime # undocumented
def __init__(
self,
guess: str | Path | TextIO | BinaryIO | None = None,
filename: str | Path | None = None,
url: str | None = None,
file_obj: TextIO | BinaryIO | None = None,
string: str | None = None,
base_url: str | Path | None = None,
url_fetcher: URLFetcher | None = None,
name: str | None = None,
description: str | None = None,
created: datetime | None = None,
modified: datetime | None = None,
relationship: str = "Unspecified",
) -> None: ...
111 changes: 111 additions & 0 deletions stubs/weasyprint/weasyprint/css/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from _typeshed import Incomplete
from collections.abc import Generator
from typing import NamedTuple

PSEUDO_ELEMENTS: Incomplete

class PageSelectorType(NamedTuple):
side: Incomplete
blank: Incomplete
first: Incomplete
index: Incomplete
name: Incomplete

class StyleFor:
initial_page_sizes: Incomplete
font_config: Incomplete
def __init__(self, html, sheets, presentational_hints, font_config, target_collector) -> None: ...
def __call__(self, element, pseudo_type=None): ...
def set_computed_styles(self, element, parent, root=None, pseudo_type=None, base_url=None, target_collector=None) -> None: ...
def add_page_declarations(self, page_type) -> None: ...
def get_cascaded_styles(self): ...
def get_computed_styles(self): ...

def get_child_text(element): ...
def text_decoration(key, value, parent_value, cascaded): ...
def find_stylesheets(
wrapper_element, device_media_type, url_fetcher, base_url, font_config, counter_style, color_profiles, page_rules, layers
) -> Generator[Incomplete]: ...
def find_style_attributes(tree, presentational_hints: bool = False, base_url=None) -> Generator[Incomplete, None, Incomplete]: ...
def declaration_precedence(origin, importance): ...
def resolve_var(computed, token, parent_style): ...
def resolve_math(token, computed=None, property_name=None, refer_to=None): ...

class InitialStyle(dict[Incomplete, Incomplete]):
parent_style: Incomplete
specified: Incomplete
cache: Incomplete
font_config: Incomplete
def __init__(self, font_config) -> None: ...
def __missing__(self, key): ...

class AnonymousStyle(dict[Incomplete, Incomplete]):
parent_style: Incomplete
is_root_element: bool
specified: Incomplete
cache: Incomplete
font_config: Incomplete
def __init__(self, parent_style) -> None: ...
def copy(self): ...
def __missing__(self, key): ...

class ComputedStyle(dict[Incomplete, Incomplete]):
specified: Incomplete
parent_style: Incomplete
cascaded: Incomplete
is_root_element: Incomplete
element: Incomplete
pseudo_type: Incomplete
root_style: Incomplete
base_url: Incomplete
font_config: Incomplete
initial_page_sizes: Incomplete
cache: Incomplete
def __init__(
self, parent_style, cascaded, element, pseudo_type, root_style, base_url, font_config, initial_page_sizes
) -> None: ...
def copy(self): ...
def __missing__(self, key): ...

class ColorProfile:
src: Incomplete
rendering_intent: Incomplete
components: Incomplete
pdf_reference: Incomplete
def __init__(self, file_object, src, rendering_intent, components) -> None: ...
@property
def name(self): ...
@property
def content(self): ...

def computed_from_cascaded(
element, cascaded, parent_style, pseudo_type=None, root_style=None, base_url=None, target_collector=None
): ...
def parse_color_profile_name(prelude): ...
def parse_page_selectors(rule): ...
def preprocess_stylesheet(
device_media_type,
base_url,
stylesheet_rules,
url_fetcher,
matcher,
page_rules,
layers,
font_config,
counter_style,
color_profiles,
ignore_imports: bool = False,
layer=None,
): ...
def get_all_computed_styles(
html,
user_stylesheets=None,
presentational_hints: bool = False,
font_config=None,
counter_style=None,
color_profiles=None,
page_rules=None,
layers=None,
target_collector=None,
forms: bool = False,
): ...
10 changes: 10 additions & 0 deletions stubs/weasyprint/weasyprint/css/counters.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from _typeshed import Incomplete

def symbol(string_or_url) -> str: ...
def parse_counter_style_name(tokens, counter_style): ...

class CounterStyle(dict[Incomplete, Incomplete]):
def resolve_counter(self, counter_name, previous_types=None): ...
def render_value(self, counter_value, counter_name=None, counter=None, previous_types=None): ...
def render_marker(self, counter_name, counter_value): ...
def copy(self) -> CounterStyle: ...
32 changes: 32 additions & 0 deletions stubs/weasyprint/weasyprint/document.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from _typeshed import Incomplete

class Page:
width: Incomplete
height: Incomplete
bleed: Incomplete
bookmarks: Incomplete
links: Incomplete
anchors: Incomplete
forms: Incomplete
def __init__(self, page_box) -> None: ...
def paint(self, stream, scale: int = 1) -> None: ...

class DiskCache:
def __init__(self, folder) -> None: ...
def __getitem__(self, key): ...
def __setitem__(self, key, value) -> None: ...
def __contains__(self, key) -> bool: ...
def __del__(self) -> None: ...

class Document:
pages: Incomplete
metadata: Incomplete
url_fetcher: Incomplete
fonts: Incomplete
font_config: Incomplete
color_profiles: Incomplete
output_intent: Incomplete
def __init__(self, pages, metadata, url_fetcher, font_config, color_profiles, output_intent) -> None: ...
def copy(self, pages: str = "all"): ...
def make_bookmark_tree(self, scale: int = 1, transform_pages: bool = False): ...
def write_pdf(self, target=None, zoom: int = 1, finisher=None, **options): ...
1 change: 1 addition & 0 deletions stubs/weasyprint/weasyprint/text/fonts.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class FontConfiguration: ...
78 changes: 78 additions & 0 deletions stubs/weasyprint/weasyprint/urls.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import contextlib
from _typeshed import Incomplete
from collections.abc import Generator, Sequence
from gzip import GzipFile
from ssl import SSLContext
from urllib import request

UNICODE_SCHEME_RE: Incomplete
BYTES_SCHEME_RE: Incomplete
FILESYSTEM_ENCODING: Incomplete
HTTP_HEADERS: Incomplete

class StreamingGzipFile(GzipFile):
fileobj_to_close: Incomplete
def __init__(self, fileobj) -> None: ...
def close(self) -> None: ...
def seekable(self): ...

def iri_to_uri(url): ...
def path2url(path): ...
def url_is_absolute(url): ...
def get_url_attribute(element, attr_name, base_url, allow_relative: bool = False): ...
def get_url_tuple(url, base_url): ...
def url_join(base_url, url, allow_relative, context, context_args): ...
def get_link_attribute(element, attr_name, base_url): ...
def ensure_url(string): ...
def default_url_fetcher(url, timeout: int = 10, ssl_context=None, http_headers=None, allowed_protocols=None): ...
@contextlib.contextmanager
def select_source(
guess=None,
filename=None,
url=None,
file_obj=None,
string=None,
base_url=None,
url_fetcher=None,
check_css_mime_type: bool = False,
) -> Generator[Incomplete]: ...

class URLFetchingError(IOError): ...
class FatalURLFetchingError(BaseException): ...

class URLFetcher(request.OpenerDirector):
def __init__(
self,
timeout: int = 10,
ssl_context: SSLContext | None = None,
http_headers=None,
allowed_protocols: Sequence[str] | None = None,
allow_redirects: bool = True,
fail_on_errors: bool = False,
**kwargs,
) -> None: ...
def fetch(self, url, headers=None): ...
def open(self, url, data=None, timeout=None): ...
def __call__(self, url): ...

class URLFetcherResponse:
url: Incomplete
status: Incomplete
headers: Incomplete
def __init__(self, url, body=None, headers=None, status: int = 200, **kwargs) -> None: ...
def read(self, *args, **kwargs): ...
def close(self) -> None: ...
@property
def path(self): ...
@property
def content_type(self): ...
@property
def charset(self): ...
def geturl(self): ...
def info(self): ...
@property
def code(self): ...
def getcode(self): ...

@contextlib.contextmanager
def fetch(url_fetcher, url) -> Generator[Incomplete]: ...
Loading