From 5fdb85cb193556c79d8e17e9dc5b2d4db426f4cd Mon Sep 17 00:00:00 2001 From: Axy Date: Sun, 27 Sep 2026 23:02:20 +0200 Subject: [PATCH] Mypy and flake8 cleanup --- .flake8 | 2 +- src/pacman/ecs/__init__.py | 5 --- src/pacman/ecs/hierarchy.py | 19 ++++++--- src/pacman/ecs/world.py | 80 ++++++++++++++++++++----------------- 4 files changed, 59 insertions(+), 47 deletions(-) diff --git a/.flake8 b/.flake8 index 0081794..2029706 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,2 @@ [flake8] -ignore = E203,W503 +ignore = E203,W503,E704 diff --git a/src/pacman/ecs/__init__.py b/src/pacman/ecs/__init__.py index f614e28..df086dd 100644 --- a/src/pacman/ecs/__init__.py +++ b/src/pacman/ecs/__init__.py @@ -1,4 +1,3 @@ -from collections.abc import Callable from dataclasses import dataclass from pathlib import Path @@ -17,13 +16,9 @@ from pacman.ecs.schedule import ( UpdateSchedule, ) from pacman.ecs.world import ( - CommandQueue, Component, - Entity, Not, Query, - RawComponentArg, - RawComponentHook, Resource, Systems, World, diff --git a/src/pacman/ecs/hierarchy.py b/src/pacman/ecs/hierarchy.py index c9d98dd..f0698d2 100644 --- a/src/pacman/ecs/hierarchy.py +++ b/src/pacman/ecs/hierarchy.py @@ -1,5 +1,5 @@ from collections.abc import Callable, Generator, Iterable -from typing import get_args, override +from typing import cast, get_args, override from pacman.ecs.world import ( CommandQueue, @@ -114,11 +114,20 @@ class Hierarchy[Items, Filters = tuple[()]](FromWorld): cls, ty: type, world: "World" ) -> Callable[[], "Hierarchy[Items, Filters]"]: items, filters = get_args(ty) - roots_ty: type[RootsQuery[Items, Filters]] = resolve_type_aliases( - RootsQuery[items, filters] + type _Items = items # type: ignore [valid-type] + type _Filters = filters # type: ignore [valid-type] + roots_ty = cast( + type[RootsQuery[Items, Filters]], + resolve_type_aliases( + RootsQuery[ + _Items, + _Filters, + ] + ), ) - nodes_ty: type[NodesQuery[Items, Filters]] = resolve_type_aliases( - NodesQuery[items, filters] + nodes_ty = cast( + type[NodesQuery[Items, Filters]], + resolve_type_aliases(NodesQuery[_Items, _Filters]), ) roots = roots_ty.extract_from_world(roots_ty, world) nodes = nodes_ty.extract_from_world(nodes_ty, world) diff --git a/src/pacman/ecs/world.py b/src/pacman/ecs/world.py index 0443821..b173484 100644 --- a/src/pacman/ecs/world.py +++ b/src/pacman/ecs/world.py @@ -5,6 +5,7 @@ from dataclasses import dataclass from typing import ( Any, Literal, + Never, NewType, Self, Union, @@ -33,7 +34,7 @@ class Bundle(ABC): def components_iter(self) -> Iterator["Component"]: ... @classmethod @abstractmethod - def components_type_iter(cls) -> Iterator[type["Component"]]: ... + def components_type_iter(cls, ty: type) -> Iterator[type["Component"]]: ... type Components = RecursiveTuple["Component | Bundle"] @@ -60,7 +61,9 @@ def components_type_iter( elif issubclass(components, Component): yield components else: - yield from cast(type[Bundle], components).components_type_iter() + yield from cast(type[Bundle], components).components_type_iter( + components + ) ComponentID = NewType("ComponentID", int) @@ -85,8 +88,8 @@ class Archetype: self._world._archetypes.append(self) self._world._archetypes_lookup[self._types] = self - def _compute_add( - self, ty: type[Components] + def _compute_add[T: Components]( + self, ty: type[T] ) -> tuple["Archetype", list[ComponentID]]: ptr = id(ty) if res := self._add_cache.get(ptr): @@ -106,8 +109,8 @@ class Archetype: self._add_cache[ptr] = (ty, res_arch, comps) return (res_arch, comps) - def _compute_remove( - self, ty: type[Components] + def _compute_remove[T: Components]( + self, ty: type[T] ) -> tuple["Archetype", list[ComponentID]]: ptr = id(ty) if res := self._remove_cache.get(ptr): @@ -197,7 +200,7 @@ class Archetype: for ent in entities: del self._world._entities[ent] for hook, comp in comps: - hook._remove(zip(entities, comp)) + hook._remove(zip(entities, comp, strict=True)) def _extend( self, @@ -235,14 +238,14 @@ class Archetype: remove_idx(comp) -type RawSystem[T] = Callable[[], T] +type RawSystem[T = Any] = Callable[[], T] -type System[T] = Callable[..., T] +type System[T = Any] = Callable[..., T] type Plugin = RecursiveTuple[Callable[["World"], None]] type RawComponentArg[T] = Iterable[tuple["Entity", T]] -type RawComponentHook[T] = Callable[[RawComponentArg], None] +type RawComponentHook[T] = Callable[[RawComponentArg[T]], None] type ComponentHook[T] = System[RawComponentHook[T]] @@ -254,7 +257,7 @@ class FromWorld(ABC): ) -> Callable[[], Self | None]: ... def cleanup(self) -> None: - pass + return None class QueryFilter(ABC): @@ -290,6 +293,7 @@ class QueryItem(QueryFilter): @classmethod def fetch_prio(cls, ty: type) -> int: + del ty return 0 @classmethod @@ -331,6 +335,7 @@ class Entity(QueryItem): @override @classmethod def filter(cls, ty: type) -> Callable[[Archetype], bool]: + del ty return lambda _: True @override @@ -338,6 +343,7 @@ class Entity(QueryItem): def filter_fetch( cls, ty: type ) -> Callable[[Archetype], None | Callable[[int], "Entity"]]: + del ty return lambda archetype: lambda i: archetype._entities[i] @@ -346,14 +352,14 @@ class Not[T: FromWorld | Any](FromWorld, QueryItem): @classmethod def filter_fetch( cls, ty: type - ) -> Callable[[Archetype], None | Callable[[int], Self | _NoFetchCls]]: + ) -> Callable[[Archetype], None | Callable[[int], "Not[T] | _NoFetchCls"]]: preprocessed = cls.filter(ty) return lambda archetype: ( (lambda _: Not()) - if (filt := preprocessed(archetype)) == False + if (filt := preprocessed(archetype)) is False else ( None - if filt == True + if filt is True else (lambda i: _NoFetch if filt(i) else Not()) ) ) @@ -376,8 +382,8 @@ class Not[T: FromWorld | Any](FromWorld, QueryItem): def extract_from_world( cls, ty: type, world: "World" ) -> Callable[[], "Not[T] | None"]: - inner = cast(type[FromWorld], get_args(ty)[0]) - extractor = inner.extract_from_world(inner, world) + inner_ty = cast(type[FromWorld], get_args(ty)[0]) + extractor = inner_ty.extract_from_world(inner_ty, world) def inner() -> Not[T] | None: if (res := extractor()) is None: @@ -397,8 +403,8 @@ class Maybe[T: FromWorld](FromWorld): def extract_from_world( cls, ty: type, world: "World" ) -> Callable[[], "Maybe[T]"]: - inner = cast(type[T], get_args(ty)[0]) - extractor = inner.extract_from_world(inner, world) + inner_ty = cast(type[T], get_args(ty)[0]) + extractor = inner_ty.extract_from_world(inner_ty, world) def inner() -> Maybe[T]: return Maybe(extractor()) @@ -539,14 +545,12 @@ class Query[Items, Filters = tuple[()]]( return cast(QueryFilter, filter).filter(filter) def add_archetype(self, archetype: Archetype) -> None: - cond: Callable[[int], bool] - match self._filters_raw(archetype): - case True: - cond = lambda _: True - case False: - return - case e: - cond = e + filt = self._filters_raw(archetype) + if filt is False: + return + cond: Callable[[int], bool] = ( + (lambda _: True) if filt is True else filt + ) fetcher = self._fetchers_raw(archetype) if fetcher is None: @@ -582,7 +586,9 @@ class Query[Items, Filters = tuple[()]]( ) @override - def __contains__(self, entity: Entity) -> bool: + def __contains__(self, entity: object) -> bool: + if not isinstance(entity, Entity): + return False arch: Archetype | None = self._world._entities.get(entity) if arch is None: return False @@ -635,8 +641,8 @@ class Resource(FromWorld, Component): ) -> Callable[[], Self | None]: _query = Query[ty] # type: ignore query: Callable[[], Query[Self]] = cast( - type[Query[Self]], _query - ).extract_from_world(_query, world) + Callable[[], Query[Self]], _query.extract_from_world(_query, world) + ) return lambda: query().single() @@ -650,6 +656,7 @@ class CommandQueue(FromWorld): def extract_from_world( cls, ty: type, world: "World" ) -> Callable[[], Self]: + del ty return lambda: cls(world) @override @@ -661,11 +668,11 @@ class CommandQueue(FromWorld): self._queue.append(sys) -def _system_failed_va[T, *P = *tuple[()]](*_: *P) -> T: +def _system_failed_va[*P = *tuple[()]](*_: *P) -> Never: raise ValueError("Failed to fetch arguments for system") -def _system_failed[T]() -> T: +def _system_failed() -> Never: raise ValueError("Failed to fetch arguments for system") @@ -690,7 +697,7 @@ class World(FromWorld): tuple[type, ComponentHooks[Component]] ] = [] self._components_lookup: dict[type, ComponentID] = {} - self._schedules: dict[ScheduleLabel, Schedule[RawSystem]] = {} + self._schedules: dict[ScheduleLabel, Schedule[RawSystem[Any]]] = {} self._base_archetype: Archetype = Archetype(self, ()) def component_id(self, comp: type) -> ComponentID: @@ -805,7 +812,7 @@ class World(FromWorld): for extract in extractors: curr = extract() if curr is None: - return default() + return default(*cb_args) args.append(curr) res = system(*args)(*cb_args) for arg in args: @@ -840,6 +847,7 @@ class World(FromWorld): def extract_from_world( cls, ty: type, world: "World" ) -> Callable[[], "World"]: + del ty return lambda: world def tick(self, schedule: ScheduleLabel) -> None: @@ -876,13 +884,13 @@ class World(FromWorld): hook: ComponentHook[T], ) -> "World": comp_id = self.component_id(resolve_type_aliases(ty)) - hooks = self._components_cache[comp_id][1] + hooks = cast(ComponentHooks[T], self._components_cache[comp_id][1]) sys = self.add_system(hook, default=lambda _: None) match cycle: case "insert": - hooks.add_insert(lambda e: sys(e)) + hooks.add_insert(sys) case "remove": - hooks.add_remove(lambda e: sys(e)) + hooks.add_remove(sys) return self def with_plugins(self, *plugins: Plugin) -> "World": -- 2.53.0