mypy linting: everything except for WIP functional pattern

This commit is contained in:
James Turk 2024-04-26 16:31:12 -05:00
parent e3d7961674
commit 8374359309
10 changed files with 33 additions and 31 deletions

View File

@ -16,7 +16,7 @@ mypy = "^1.10.0"
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[mypy] [tool.mypy]
ignore = [ exclude = [
"src/doodles/examples/*" "src/doodles/examples/"
] ]

View File

@ -24,4 +24,4 @@ from .color import Color
from .text import Text from .text import Text
__all__ = [Doodle, Group, Line, Circle, Rectangle, Color, Text] __all__ = ["Doodle", "Group", "Line", "Circle", "Rectangle", "Color", "Text"]

View File

@ -41,7 +41,7 @@ class Doodle(ABC):
_updates: list[Callable] _updates: list[Callable]
_color: tuple[int, int, int] _color: tuple[int, int, int]
_alpha: int _alpha: int
_z_index: int _z_index: float
def __init__(self, parent=None): def __init__(self, parent=None):
# To avoid all child constructors having an ever-expanding # To avoid all child constructors having an ever-expanding
@ -258,14 +258,14 @@ class Doodle(ABC):
return self._pos_vec[1] return self._pos_vec[1]
@property @property
def world_vec(self) -> (float, float): def world_vec(self) -> tuple[float, float]:
""" """
Obtain derived position vector as a 2-tuple. Obtain derived position vector as a 2-tuple.
""" """
return self.world_x, self.world_y return self.world_x, self.world_y
@property @property
def rgba(self) -> (int, int, int, int): def rgba(self) -> tuple[int, int, int, int]:
""" """
Access for color+alpha, used by draw functions Access for color+alpha, used by draw functions
which need a 4-tuple. which need a 4-tuple.
@ -321,7 +321,7 @@ class Group(Doodle):
""" """
pass pass
def copy(self) -> "Group": def copy(self) -> Self:
""" """
An override of copy that handles the special An override of copy that handles the special
case of having a mutable list of Doodles case of having a mutable list of Doodles
@ -340,7 +340,7 @@ class Group(Doodle):
child._register() child._register()
return new return new
def color(self, color: tuple[int, int, int]) -> Doodle: def color(self, color: tuple[int, int, int]) -> Self:
""" """
An override of Doodle.color. An override of Doodle.color.

View File

@ -3,14 +3,12 @@ from typing import TYPE_CHECKING
# this is needed because of circular references # this is needed because of circular references
if TYPE_CHECKING: if TYPE_CHECKING:
from .colors import Color
from .doodles import Doodle from .doodles import Doodle
from .shapes import Rectangle, Circle from .shapes import Rectangle, Circle
from .lines import Line from .lines import Line
from .text import Text from .text import Text
class DrawEngine(abc.ABC): class DrawEngine(abc.ABC):
""" """
This is an abstract class that defines the methods needed This is an abstract class that defines the methods needed
@ -36,6 +34,7 @@ class DrawEngine(abc.ABC):
isolation (such as a library you want to avoid tight coupling to) isolation (such as a library you want to avoid tight coupling to)
only is added to a specific class or module. only is added to a specific class or module.
""" """
@abc.abstractmethod @abc.abstractmethod
def init(self): def init(self):
""" """
@ -44,7 +43,7 @@ class DrawEngine(abc.ABC):
""" """
@abc.abstractmethod @abc.abstractmethod
def render(self, background_color: "Color", drawables: list["Doodle"]): def render(self, background_color: tuple[int, int, int], drawables: list["Doodle"]):
""" """
Workhorse function, should set background and then draw all Doodles. Workhorse function, should set background and then draw all Doodles.
@ -70,7 +69,7 @@ class DrawEngine(abc.ABC):
""" """
@abc.abstractmethod @abc.abstractmethod
def text_render(self, text: "Text"): def text_render(self, text: str, font: str, color: tuple[int, int, int]):
""" """
Method to pre-render a text object. Method to pre-render a text object.
""" """

View File

@ -6,7 +6,7 @@ the easiest to learn from.
""" """
import math import math
import random import random
from typing import Callable from typing import Callable, Self
from .doodles import Doodle from .doodles import Doodle
from .world import world from .world import world
@ -50,7 +50,7 @@ class Line(Doodle):
## Setters / Modifiers / Getters ############## ## Setters / Modifiers / Getters ##############
def to(self, x: float, y: float) -> "Doodle": def to(self, x: float, y: float) -> Self:
""" """
A setter for the line's offset vector. A setter for the line's offset vector.
@ -63,7 +63,7 @@ class Line(Doodle):
self._offset_vec = (x, y) self._offset_vec = (x, y)
return self return self
def vec(self, degrees: float, magnitude: float): def vec(self, degrees: float | Callable, magnitude: float):
""" """
Alternate setter, to create offset vector from angle & length. Alternate setter, to create offset vector from angle & length.
@ -72,7 +72,7 @@ class Line(Doodle):
directly (`to`), but there is also an alternate option directly (`to`), but there is also an alternate option
that handles commonly used case. that handles commonly used case.
""" """
if isinstance(degrees, Callable): if callable(degrees):
self.register_update( self.register_update(
self.to, self.to,
lambda: magnitude * math.cos(math.radians(degrees())), lambda: magnitude * math.cos(math.radians(degrees())),
@ -85,7 +85,7 @@ class Line(Doodle):
magnitude * math.sin(math.radians(degrees)), magnitude * math.sin(math.radians(degrees)),
) )
def random(self) -> "Doodle": def random(self) -> Self:
""" """
Overrides the parent's random, since a random line Overrides the parent's random, since a random line
also needs to have a offset vector. also needs to have a offset vector.

View File

@ -16,6 +16,7 @@ from pathlib import Path
import pygame import pygame
import importlib import importlib
import typer import typer
from typing import Optional
from .world import world from .world import world
@ -54,7 +55,7 @@ def load_module(modname: str):
return mod.create() return mod.create()
def main(modname: str = None): def main(modname: Optional[str] = None):
""" """
Entrypoint method. Entrypoint method.

0
src/doodles/py.typed Normal file
View File

View File

@ -5,6 +5,7 @@ these classes only differ from `Line` in implementation.
The interface & decisions are the same but specific The interface & decisions are the same but specific
to `Circle` and `Rectangle`. to `Circle` and `Rectangle`.
""" """
from typing import Self
import random import random
from .doodles import Doodle from .doodles import Doodle
from .world import world from .world import world
@ -23,7 +24,7 @@ class Circle(Doodle):
# TODO: do we need to override draw? can we move this to Doodle.draw # TODO: do we need to override draw? can we move this to Doodle.draw
world.draw_engine.circle_draw(self) world.draw_engine.circle_draw(self)
def radius(self, r: float) -> "Doodle": def radius(self, r: float) -> Self:
""" """
A setter for the circle's radius. A setter for the circle's radius.
""" """
@ -40,7 +41,7 @@ class Circle(Doodle):
""" """
return self.radius(self._radius + by) return self.radius(self._radius + by)
def random(self) -> "Doodle": def random(self) -> Self:
super().random() super().random()
# constrain to 10-100 # constrain to 10-100
return self.radius(random.random() * 90 + 10) return self.radius(random.random() * 90 + 10)
@ -62,26 +63,26 @@ class Rectangle(Doodle):
def draw(self): def draw(self):
world.draw_engine.rect_draw(self) world.draw_engine.rect_draw(self)
def width(self, w: float) -> "Doodle": def width(self, w: float) -> Self:
""" """
Set new width. Set new width.
""" """
self._width = w self._width = w
return self return self
def height(self, h: float) -> "Doodle": def height(self, h: float) -> Self:
""" """
Set new height. Set new height.
""" """
self._height = h self._height = h
return self return self
def grow(self, dw: float, dh: float): def grow(self, dw: float, dh: float) -> Self:
return self.width(self._w + dw).height(self._h + dh) return self.width(self._width + dw).height(self._height + dh)
def random(self, upper=100) -> "Doodle": def random(self, size: float = 100) -> Self:
super().random() super().random()
# constrain to 10-100 # constrain to 10-100
return self.width(random.random() * upper + 10).height( return self.width(random.random() * size + 10).height(
random.random() * upper + 10 random.random() * size + 10
) )

View File

@ -16,6 +16,7 @@ if TYPE_CHECKING:
from .lines import Line from .lines import Line
from .text import Text from .text import Text
class PygameDrawEngine(DrawEngine): class PygameDrawEngine(DrawEngine):
# Having each bit of text on the screen load a separate copy # Having each bit of text on the screen load a separate copy
# of its font would be wasteful, since the most common case would # of its font would be wasteful, since the most common case would
@ -66,7 +67,7 @@ class PygameDrawEngine(DrawEngine):
world.draw_engine.make_font("medium", 24, "copperplate") world.draw_engine.make_font("medium", 24, "copperplate")
world.draw_engine.make_font("large", 48, "papyrus") world.draw_engine.make_font("large", 48, "papyrus")
def render(self, background_color: Color, drawables: list["Doodle"]): def render(self, background_color: tuple[int, int, int], drawables: list["Doodle"]):
self.buffer.fill((*background_color, 255)) self.buffer.fill((*background_color, 255))
for d in sorted(drawables, key=lambda d: d._z_index): for d in sorted(drawables, key=lambda d: d._z_index):
d.draw() d.draw()
@ -89,8 +90,8 @@ class PygameDrawEngine(DrawEngine):
def line_draw(self, ll: "Line"): def line_draw(self, ll: "Line"):
pygame.draw.aaline(self.buffer, ll.rgba, ll.world_vec, ll.end_vec) pygame.draw.aaline(self.buffer, ll.rgba, ll.world_vec, ll.end_vec)
# TODO: return type? # TODO: hard to type, revisit
def text_render(self, text: str, font: str, color: Color): def text_render(self, text: str, font, color: tuple[int, int, int]):
"""returns an intermediated RenderedText""" """returns an intermediated RenderedText"""
return font.render(text, True, color) return font.render(text, True, color)