Skip to content

Commit

Permalink
Update Pyright and Pillow, fix many type errors
Browse files Browse the repository at this point in the history
  • Loading branch information
object-Object committed Nov 28, 2024
1 parent af2c5bf commit 869074b
Show file tree
Hide file tree
Showing 16 changed files with 114 additions and 57 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Pydantic's HISTORY.md](https://github.com/pydantic/pydantic/blob/main/HISTORY.md), and this project *mostly* adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [UNRELEASED]

### Changed

* Update dependencies:
* Pyright: `1.1.389`
* Pillow: `11.0.0`

## `1!0.1.0a20`

### Added
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ dependencies = [
"minecraft-render~=2.0.0a6",

# Favicons deps, because it's vendored
"pillow~=9.5.0",
"pillow~=11.0.0",
"rich~=13.3.4",
"svglib~=1.5.1",
]
Expand All @@ -72,7 +72,7 @@ pdoc = [
"pdoc~=14.1",
]
test = [
"pyright==1.1.361",
"pyright==1.1.389",
"pytest~=7.4",
"pytest-dependency~=0.5",
"pytest-describe~=2.2",
Expand Down Expand Up @@ -203,7 +203,6 @@ exclude = [

typeCheckingMode = "basic"

enableExperimentalFeatures = true
strictDictionaryInference = true
strictListInference = true
strictSetInference = true
Expand Down
2 changes: 1 addition & 1 deletion src/hexdoc/core/properties/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class Properties(BaseProperties):
lang: defaultdict[
str,
Annotated[LangProps, Field(default_factory=lambda: LangProps())],
] = Field(default_factory=lambda: defaultdict(LangProps))
] = Field(default_factory=lambda: defaultdict[str, LangProps](LangProps))
"""Per-language configuration. The key should be the language code, eg. `en_us`."""

extra: dict[str, Any] = Field(default_factory=dict)
Expand Down
10 changes: 5 additions & 5 deletions src/hexdoc/core/resource_dir.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
from hexdoc.model import HexdocModel
from hexdoc.model.base import DEFAULT_CONFIG
from hexdoc.plugin import PluginManager
from hexdoc.utils import JSONDict, RelativePath
from hexdoc.utils.types import cast_nullable
from hexdoc.utils import RelativePath
from hexdoc.utils.types import cast_nullable, isdict


class BaseResourceDir(HexdocModel, ABC):
Expand Down Expand Up @@ -65,8 +65,8 @@ def internal(self):

@model_validator(mode="before")
@classmethod
def _default_reexport(cls, data: JSONDict | Any):
if not isinstance(data, dict):
def _default_reexport(cls, data: Any) -> Any:
if not isdict(data):
return data

external = cls._get_external(data)
Expand All @@ -79,7 +79,7 @@ def _default_reexport(cls, data: JSONDict | Any):
return data

@classmethod
def _get_external(cls, data: JSONDict | Any):
def _get_external(cls, data: dict[Any, Any]):
match data:
case {"external": bool(), "internal": bool()}:
raise ValueError(f"Expected internal OR external, got both: {data}")
Expand Down
14 changes: 8 additions & 6 deletions src/hexdoc/graphics/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __init__(self, ctx: Context, wnd: HeadlessWindow):
dtype="f4",
) * Matrix44.from_scale((1, -1, 1), "f4")

self.camera, self.eye = direction_camera(pos="south")
self.camera, self.eye = direction_camera(pos=FaceName.south)

self.lights = [
((0, -1, 0), LIGHT_TOP),
Expand Down Expand Up @@ -100,9 +100,9 @@ def __init__(self, ctx: Context, wnd: HeadlessWindow):
pos = 8
neg = 0
for from_, to, color, direction in [
((0, neg, neg), (0, pos, pos), (1, 0, 0, 0.75), "east"),
((neg, 0, neg), (pos, 0, pos), (0, 1, 0, 0.75), "up"),
((neg, neg, 0), (pos, pos, 0), (0, 0, 1, 0.75), "south"),
((0, neg, neg), (0, pos, pos), (1, 0, 0, 0.75), FaceName.east),
((neg, 0, neg), (pos, 0, pos), (0, 1, 0, 0.75), FaceName.up),
((neg, neg, 0), (pos, pos, 0), (0, 0, 1, 0.75), FaceName.south),
]:
vao = VAO()
verts = get_face_verts(from_, to, direction)
Expand Down Expand Up @@ -153,7 +153,9 @@ def render_block(
frame_height = texture.frame_height
layers = len(texture.frames)

min_alpha, _ = cast(tuple[int, int], image.getextrema()[3])
extrema = image.getextrema()
assert len(extrema) >= 4, f"Expected 4 bands but got {len(extrema)}"
min_alpha, _ = extrema[3]
if min_alpha < 255:
logger.debug(f"Transparent texture: {name} ({min_alpha=})")
transparent_textures.add(name)
Expand Down Expand Up @@ -256,7 +258,7 @@ def _render_frame(self, baked_faces: list[BakedFace], debug: DebugType, tick: in
mode="RGBA",
size=self.wnd.fbo.size,
data=self.wnd.fbo.read(components=4),
).transpose(Image.FLIP_TOP_BOTTOM)
).transpose(Image.Transpose.FLIP_TOP_BOTTOM)

return image

Expand Down
2 changes: 1 addition & 1 deletion src/hexdoc/graphics/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def orbit_camera(pitch: float, yaw: float):
), eye


def direction_camera(pos: FaceName, up: FaceName = "up"):
def direction_camera(pos: FaceName, up: FaceName = FaceName.up):
"""eg. north -> camera is placed to the north of the model, looking south"""
eye = get_direction_vec(pos, 64)
return Matrix44.look_at(
Expand Down
36 changes: 18 additions & 18 deletions src/hexdoc/graphics/lookups.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):

# fmt: off
match direction:
case "south":
case FaceName.south:
return [
x2, y1, z2,
x2, y2, z2,
Expand All @@ -22,7 +22,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):
x1, y2, z2,
x1, y1, z2,
]
case "east":
case FaceName.east:
return [
x2, y1, z1,
x2, y2, z1,
Expand All @@ -31,7 +31,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):
x2, y2, z2,
x2, y1, z2,
]
case "down":
case FaceName.down:
return [
x2, y1, z1,
x2, y1, z2,
Expand All @@ -40,7 +40,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):
x1, y1, z2,
x1, y1, z1,
]
case "west":
case FaceName.west:
return [
x1, y1, z2,
x1, y2, z2,
Expand All @@ -49,7 +49,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):
x1, y2, z1,
x1, y1, z1,
]
case "north":
case FaceName.north:
return [
x2, y2, z1,
x2, y1, z1,
Expand All @@ -58,7 +58,7 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):
x1, y1, z1,
x1, y2, z1,
]
case "up":
case FaceName.up:
return [
x2, y2, z1,
x1, y2, z1,
Expand All @@ -72,33 +72,33 @@ def get_face_verts(from_: Vec3, to: Vec3, direction: FaceName):

def get_face_uv_indices(direction: FaceName):
match direction:
case "south":
case FaceName.south:
return (2, 3, 1, 3, 0, 1)
case "east":
case FaceName.east:
return (2, 3, 1, 3, 0, 1)
case "down":
case FaceName.down:
return (2, 3, 0, 2, 0, 1)
case "west":
case FaceName.west:
return (2, 3, 0, 2, 0, 1)
case "north":
case FaceName.north:
return (0, 1, 2, 0, 2, 3)
case "up":
case FaceName.up:
return (3, 0, 2, 0, 1, 2)


def get_direction_vec(direction: FaceName, magnitude: float = 1):
match direction:
case "north":
case FaceName.north:
return (0, 0, -magnitude)
case "south":
case FaceName.south:
return (0, 0, magnitude)
case "west":
case FaceName.west:
return (-magnitude, 0, 0)
case "east":
case FaceName.east:
return (magnitude, 0, 0)
case "down":
case FaceName.down:
return (0, -magnitude, 0)
case "up":
case FaceName.up:
return (0, magnitude, 0)


Expand Down
21 changes: 14 additions & 7 deletions src/hexdoc/graphics/model/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import math
import re
from enum import StrEnum
from typing import Annotated, Literal

from pydantic import AfterValidator, Field
Expand Down Expand Up @@ -73,7 +74,13 @@ def eulers(self) -> Vec3:
return (0, 0, angle)


FaceName = Literal["down", "up", "north", "south", "west", "east"]
class FaceName(StrEnum):
down = "down"
up = "up"
north = "north"
south = "south"
west = "west"
east = "east"


class ElementFace(HexdocModel):
Expand Down Expand Up @@ -148,17 +155,17 @@ def default(cls, element: Element, direction: FaceName):

uvs: Vec4
match direction:
case "down":
case FaceName.down:
uvs = (x1, 16 - z2, x2, 16 - z1)
case "up":
case FaceName.up:
uvs = (x1, z1, x2, z2)
case "north":
case FaceName.north:
uvs = (16 - x2, 16 - y2, 16 - x1, 16 - y1)
case "south":
case FaceName.south:
uvs = (x1, 16 - y2, x2, 16 - y1)
case "west":
case FaceName.west:
uvs = (z1, 16 - y2, z2, 16 - y1)
case "east":
case FaceName.east:
uvs = (16 - z2, 16 - y2, 16 - z1, 16 - y1)

return cls(uvs=uvs)
Expand Down
3 changes: 2 additions & 1 deletion src/hexdoc/graphics/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass
from functools import cached_property
from pathlib import Path
from typing import Iterator

import numpy as np
from PIL import Image
Expand Down Expand Up @@ -105,7 +106,7 @@ def get_frame(self, tick: int):

@cached_property
@listify
def frames(self):
def frames(self) -> Iterator[Image.Image]:
"""Returns a list of animation frames, where each frame lasts for one tick.
If `animation` is None, just returns `[image]`.
Expand Down
8 changes: 7 additions & 1 deletion src/hexdoc/model/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ def _hexdoc_check_model_field_type(
else:
annotations = []

if any(isinstance(a, SkipValidation) for a in annotations):
if any(
isinstance(
a,
SkipValidation, # pyright: ignore[reportArgumentType]
)
for a in annotations
):
return

origin_stack.append(origin)
Expand Down
5 changes: 3 additions & 2 deletions src/hexdoc/model/strip_hidden.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pydantic.config import JsonDict

from hexdoc.utils.deserialize.assertions import cast_or_raise
from hexdoc.utils.types import isdict

from .base import DEFAULT_CONFIG, HexdocModel

Expand All @@ -25,8 +26,8 @@ class StripHiddenModel(HexdocModel):
)

@model_validator(mode="before")
def _pre_root_strip_hidden(cls, values: dict[Any, Any] | Any) -> Any:
if not isinstance(values, dict):
def _pre_root_strip_hidden(cls, values: Any) -> Any:
if not isdict(values):
return values

return {
Expand Down
13 changes: 8 additions & 5 deletions src/hexdoc/model/tagged_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Iterable,
LiteralString,
Self,
TypeVar,
Unpack,
)

Expand Down Expand Up @@ -40,6 +41,8 @@

from .base import HexdocModel

_T_UnionModel = TypeVar("_T_UnionModel", bound="UnionModel")

TagValue = str | NoValueType

_RESOLVED = "__resolved"
Expand All @@ -55,15 +58,15 @@ def _resolve_union(
value: Any,
context: dict[str, Any] | None,
*,
model_types: Iterable[type[Self]],
model_types: Iterable[type[_T_UnionModel]],
allow_ambiguous: bool,
error_name: LiteralString = "HexdocUnionMatchError",
error_text: Iterable[LiteralString] = [],
error_data: dict[str, Any] = {},
) -> Self:
) -> _T_UnionModel:
# try all the types
exceptions: list[InitErrorDetails] = []
matches: dict[type[Self], Self] = {}
matches: dict[type[_T_UnionModel], _T_UnionModel] = {}

for model_type in model_types:
try:
Expand Down Expand Up @@ -271,14 +274,14 @@ def _resolve_from_dict(
raise

@model_validator(mode="before")
def _pop_temporary_keys(cls, value: dict[Any, Any] | Any):
def _pop_temporary_keys(cls, value: Any) -> Any:
if isinstance(value, dict) and _RESOLVED in value:
# copy because this validator may be called multiple times
# eg. two types with the same key
value = value.copy()
value.pop(_RESOLVED)
assert value.pop(cls._tag_key, NoValue) == cls._tag_value
return value
return value # pyright: ignore[reportUnknownVariableType]

@classmethod
@override
Expand Down
Loading

0 comments on commit 869074b

Please sign in to comment.