← back to Exo
Fix tests
5097493a42d432367bc0c2cafd9e84e6e6e15339 · 2025-07-24 13:22:58 +0100 · Matt Beton
Files touched
M shared/types/events/__init__.pyM shared/types/events/_common.pyM shared/types/events/_events.pyM shared/types/events/components.pyM worker/main.py
Diff
commit 5097493a42d432367bc0c2cafd9e84e6e6e15339
Author: Matt Beton <matthew.beton@gmail.com>
Date: Thu Jul 24 13:22:58 2025 +0100
Fix tests
---
shared/types/events/__init__.py | 61 +++++++++++++++++++++++++++++++++++++
shared/types/events/_common.py | 63 ++-------------------------------------
shared/types/events/_events.py | 7 +++--
shared/types/events/components.py | 2 +-
worker/main.py | 13 ++------
5 files changed, 71 insertions(+), 75 deletions(-)
diff --git a/shared/types/events/__init__.py b/shared/types/events/__init__.py
index b3c5ac1b..c3052e88 100644
--- a/shared/types/events/__init__.py
+++ b/shared/types/events/__init__.py
@@ -14,3 +14,64 @@ EventParser: TypeAdapter[Event] = TypeAdapter(Event)
"""Type adaptor to parse :class:`Event`s."""
__all__ = ["Event", "EventParser", "apply", "EventFromEventLog"]
+
+# Event type consistency check - runs after all imports are complete
+def _check_event_type_consistency():
+ import types
+ import typing
+
+ from shared.constants import get_error_reporting_message
+
+ from ._common import _BaseEvent, _EventType # pyright: ignore[reportPrivateUsage]
+ from ._events import _Event # pyright: ignore[reportPrivateUsage]
+
+ # Grab enum values from members
+ member_enum_values = [m for m in _EventType]
+
+ # grab enum values from the union => scrape the type annotation
+ union_enum_values: list[_EventType] = []
+ union_classes = list(typing.get_args(_Event))
+ for cls in union_classes: # pyright: ignore[reportAny]
+ assert issubclass(cls, object), (
+ f"{get_error_reporting_message()}",
+ f"The class {cls} is NOT a subclass of {object}."
+ )
+
+ # ensure the first base parameter is ALWAYS _BaseEvent
+ base_cls = list(types.get_original_bases(cls))
+ assert len(base_cls) >= 1 and issubclass(base_cls[0], object) \
+ and issubclass(base_cls[0], _BaseEvent), (
+ f"{get_error_reporting_message()}",
+ f"The class {cls} does NOT inherit from {_BaseEvent} {typing.get_origin(base_cls[0])}."
+ )
+
+ # grab type hints and extract the right values from it
+ cls_hints = typing.get_type_hints(cls)
+ assert "event_type" in cls_hints and \
+ typing.get_origin(cls_hints["event_type"]) is typing.Literal, ( # pyright: ignore[reportAny]
+ f"{get_error_reporting_message()}",
+ f"The class {cls} is missing a {typing.Literal}-annotated `event_type` field."
+ )
+
+ # make sure the value is an instance of `_EventType`
+ enum_value = list(typing.get_args(cls_hints["event_type"]))
+ assert len(enum_value) == 1 and isinstance(enum_value[0], _EventType), (
+ f"{get_error_reporting_message()}",
+ f"The `event_type` of {cls} has a non-{_EventType} literal-type."
+ )
+ union_enum_values.append(enum_value[0])
+
+ # ensure there is a 1:1 bijection between the two
+ for m in member_enum_values:
+ assert m in union_enum_values, (
+ f"{get_error_reporting_message()}",
+ f"There is no event-type registered for {m} in {_Event}."
+ )
+ union_enum_values.remove(m)
+ assert len(union_enum_values) == 0, (
+ f"{get_error_reporting_message()}",
+ f"The following events have multiple event types defined in {_Event}: {union_enum_values}."
+ )
+
+
+_check_event_type_consistency()
diff --git a/shared/types/events/_common.py b/shared/types/events/_common.py
index a99af369..0090dd32 100644
--- a/shared/types/events/_common.py
+++ b/shared/types/events/_common.py
@@ -1,12 +1,6 @@
-import types
-import typing
from enum import Enum
from typing import TYPE_CHECKING
-from shared.constants import get_error_reporting_message
-
-from ._events import _Event # pyright: ignore[reportPrivateUsage]
-
if TYPE_CHECKING:
pass
@@ -14,6 +8,8 @@ from pydantic import BaseModel
from shared.types.common import NewUUID, NodeId
+# These are exported for use in other modules
+__all__ = ["EventId", "CommandId", "_EventType", "_BaseEvent"]
class EventId(NewUUID):
"""
@@ -89,58 +85,3 @@ class _BaseEvent[T: _EventType](BaseModel):
Subclasses can override this method to implement specific validation logic.
"""
return True
-
-
-
-def _check_event_type_consistency():
- # Grab enum values from members
- member_enum_values = [m for m in _EventType]
-
- # grab enum values from the union => scrape the type annotation
- union_enum_values: list[_EventType] = []
- union_classes = list(typing.get_args(_Event))
- for cls in union_classes: # pyright: ignore[reportAny]
- assert issubclass(cls, object), (
- f"{get_error_reporting_message()}",
- f"The class {cls} is NOT a subclass of {object}."
- )
-
- # ensure the first base parameter is ALWAYS _BaseEvent
- base_cls = list(types.get_original_bases(cls))
- assert len(base_cls) >= 1 and issubclass(base_cls[0], object) \
- and issubclass(base_cls[0], _BaseEvent), (
- f"{get_error_reporting_message()}",
- f"The class {cls} does NOT inherit from {_BaseEvent} {typing.get_origin(base_cls[0])}."
- )
-
- # grab type hints and extract the right values from it
- cls_hints = typing.get_type_hints(cls)
- assert "event_type" in cls_hints and \
- typing.get_origin(cls_hints["event_type"]) is typing.Literal, ( # pyright: ignore[reportAny]
- f"{get_error_reporting_message()}",
- f"The class {cls} is missing a {typing.Literal}-annotated `event_type` field."
- )
-
- # make sure the value is an instance of `_EventType`
- enum_value = list(typing.get_args(cls_hints["event_type"]))
- assert len(enum_value) == 1 and isinstance(enum_value[0], _EventType), (
- f"{get_error_reporting_message()}",
- f"The `event_type` of {cls} has a non-{_EventType} literal-type."
- )
- union_enum_values.append(enum_value[0])
-
- # ensure there is a 1:1 bijection between the two
- for m in member_enum_values:
- assert m in union_enum_values, (
- f"{get_error_reporting_message()}",
- f"There is no event-type registered for {m} in {_Event}."
- )
- union_enum_values.remove(m)
- assert len(union_enum_values) == 0, (
- f"{get_error_reporting_message()}",
- f"The following events have multiple event types defined in {_Event}: {union_enum_values}."
- )
-
-
-_check_event_type_consistency()
-
diff --git a/shared/types/events/_events.py b/shared/types/events/_events.py
index 9023567c..4f14b924 100644
--- a/shared/types/events/_events.py
+++ b/shared/types/events/_events.py
@@ -4,14 +4,17 @@ from pydantic import Field
from shared.topology import Connection, ConnectionProfile, Node, NodePerformanceProfile
from shared.types.common import NodeId
-from shared.types.events import CommandId
from shared.types.events.chunks import GenerationChunk
from shared.types.tasks import Task, TaskId, TaskStatus
from shared.types.worker.common import InstanceId, NodeStatus
from shared.types.worker.instances import InstanceParams, TypeOfInstance
from shared.types.worker.runners import RunnerId, RunnerStatus
-from ._common import _BaseEvent, _EventType # pyright: ignore[reportPrivateUsage]
+from ._common import (
+ CommandId,
+ _BaseEvent, # pyright: ignore[reportPrivateUsage]
+ _EventType, # pyright: ignore[reportPrivateUsage]
+)
class TaskCreated(_BaseEvent[_EventType.TaskCreated]):
diff --git a/shared/types/events/components.py b/shared/types/events/components.py
index 0a676ae8..f507d322 100644
--- a/shared/types/events/components.py
+++ b/shared/types/events/components.py
@@ -13,7 +13,7 @@ from typing import Callable
from pydantic import BaseModel, Field, model_validator
from shared.types.common import NodeId
-from shared.types.events import Event
+from shared.types.events._events import Event
from shared.types.state import State
diff --git a/worker/main.py b/worker/main.py
index 2f0589e0..3af1997b 100644
--- a/worker/main.py
+++ b/worker/main.py
@@ -12,7 +12,6 @@ from shared.types.common import NodeId
from shared.types.events import (
ChunkGenerated,
Event,
- InstanceCreated,
InstanceId,
RunnerStatusUpdated,
TaskStateUpdated,
@@ -78,17 +77,9 @@ class AssignedRunner(BaseModel):
# TODO: This should all be shared with the master.
type ApplyFromEventLog = Callable[[State, EventFromEventLog[Event]], State]
def get_apply_fn() -> ApplyFromEventLog:
- # TODO: this needs to be done in a nice type-safe way
- def _apply_instance_created(state: State, event_from_log: InstanceCreated) -> State:
- return state
-
+ # TODO: this will get fixed in the worker-integration pr.
def apply_fn(state: State, event_from_log: EventFromEventLog[Event]) -> State:
- if isinstance(event_from_log.event, InstanceCreated):
- next_state = _apply_instance_created(state, event_from_log.event)
- else:
- raise ValueError(f"Unknown event type: {event_from_log.event}")
- next_state.last_event_applied_idx = event_from_log.idx_in_log
- return next_state
+ return state
return apply_fn
← a6b3ab63 Worker plan
·
back to Exo
·
Topology apply df1fe3af →