Skip to content

[tinycss2] Add stubs for tinycss2#15623

Open
Video-Nomad wants to merge 5 commits intopython:mainfrom
Video-Nomad:tinycss2-stubs
Open

[tinycss2] Add stubs for tinycss2#15623
Video-Nomad wants to merge 5 commits intopython:mainfrom
Video-Nomad:tinycss2-stubs

Conversation

@Video-Nomad
Copy link
Copy Markdown

Hello!
Tinycss2 is completely untyped so here's everything in that lib.
First contribution, so might have made mistakes here and there.

@github-actions

This comment has been minimized.

@srittau
Copy link
Copy Markdown
Collaborator

srittau commented Apr 7, 2026

Thanks, not a full review, yet, but stubtest noticed some differences between the stubs and the runtime: https://github.com/python/typeshed/actions/runs/24074408358/job/70219100854?pr=15623

This doesn't mean that stubtest is correct, but these errors should be looked at. In cases where you're sure that stubtest is wrong, add a file @tests/stubtest_allowlist.txt and add those entries with an appropriate comment why stubtest is wrong. (See other stubtest_allowlist.txt files in this repository.)

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Collaborator

@srittau srittau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, a few smaller suggestions below.

Comment on lines +14 to +15
__version__: str = ...
VERSION: str = ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__version__: str = ...
VERSION: str = ...
__version__: Final[str]
VERSION: Final[str]

(Final needs import from typing.)

def serialize(self) -> str: ...

class ParseError(Node):
type: Literal["error"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to use Final here (and in the type fields below) as well:

Suggested change
type: Literal["error"]
type: Final = "error"

from .ast import Node

def decode_stylesheet_bytes(
css_bytes: bytes, protocol_encoding: str | None = ..., environment_encoding: Encoding | None = ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now generally add simple defaults to typeshed, instead of .... The latter is only used in complex cases:

Suggested change
css_bytes: bytes, protocol_encoding: str | None = ..., environment_encoding: Encoding | None = ...
css_bytes: bytes, protocol_encoding: str | None = None, environment_encoding: Encoding | None = None

Comment on lines +10 to +13
protocol_encoding: str | None = ...,
environment_encoding: Encoding | None = ...,
skip_comments: bool = ...,
skip_whitespace: bool = ...,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protocol_encoding: str | None = ...,
environment_encoding: Encoding | None = ...,
skip_comments: bool = ...,
skip_whitespace: bool = ...,
protocol_encoding: str | None = None,
environment_encoding: Encoding | None = None,
skip_comments: bool = False,
skip_whitespace: bool = False,

COLOR_SPACES: set[str] | None

def parse_color(
input: str | Iterable[Node], color_schemes: Literal["normal"] | Iterable[str] | None = ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
input: str | Iterable[Node], color_schemes: Literal["normal"] | Iterable[str] | None = ...
input: str | Iterable[Node], color_schemes: Literal["normal"] | Iterable[str] | None = None

Comment on lines +8 to +18
def parse_one_component_value(input: str | Iterable[Node], skip_comments: bool = ...) -> Node: ...
def parse_one_declaration(input: str | Iterable[Node], skip_comments: bool = ...) -> Declaration | ParseError: ...
def parse_blocks_contents(
input: str | Iterable[Node], skip_comments: bool = ..., skip_whitespace: bool = ...
) -> list[Declaration | AtRule | QualifiedRule | Comment | WhitespaceToken | ParseError]: ...
def parse_declaration_list(
input: str | Iterable[Node], skip_comments: bool = ..., skip_whitespace: bool = ...
) -> list[Declaration | AtRule | Comment | WhitespaceToken | ParseError]: ...
def parse_one_rule(input: str | Iterable[Node], skip_comments: bool = ...) -> QualifiedRule | AtRule | ParseError: ...
def parse_rule_list(input: str | Iterable[Node], skip_comments: bool = ..., skip_whitespace: bool = ...) -> list[_Rule]: ...
def parse_stylesheet(input: str | Iterable[Node], skip_comments: bool = ..., skip_whitespace: bool = ...) -> list[_Rule]: ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults are missing here as well.

@@ -0,0 +1,3 @@
from .ast import Node

def parse_component_value_list(css: str, skip_comments: bool = ...) -> list[Node]: ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def parse_component_value_list(css: str, skip_comments: bool = ...) -> list[Node]: ...
def parse_component_value_list(css: str, skip_comments: bool = False) -> list[Node]: ...

def serialize(self) -> str: ...

class ParseError(Node):
__slots__ = str | Iterable[str]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For __slots__ you can include the runtime values:

__slots__ = ["kind", "message"]

@@ -0,0 +1,3 @@
version = "1.5.1"
upstream_repository = "https://github.com/Kozea/tinycss2"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just merged a PR that changes field names to use dashes:

Suggested change
upstream_repository = "https://github.com/Kozea/tinycss2"
upstream-repository = "https://github.com/Kozea/tinycss2"

@Video-Nomad
Copy link
Copy Markdown
Author

Thanks for the reviews! Added the changes. Regarding __slots__ - I explicitly declare them as attributes now.

@github-actions

This comment has been minimized.

@Video-Nomad
Copy link
Copy Markdown
Author

Had to return the Literal back in ast.pyi because it won't type narrow with Final correctly otherwise in cases like:

token: IdentToken | NumberToken
if token.type == "ident":
    reveal_type(token)  # IdentToken

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants