From e508758fbef8544e035cfb4a377f324bab10c994 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 25 Jun 2026 20:34:57 -0400 Subject: [PATCH] feat(type_aliases): add from_dict to SessionInsights, DiscussionSettings, CustomSlice, MMAUsageStats, ProviderPayload, UIPanelConfig, PathInfo Required by Phase 10 migrations which call these from_dict methods. Without these, CustomSlice.from_dict() and MMAUsageStats.from_dict() used in gui_2.py would raise AttributeError at runtime. Adds the from_dict pattern consistent with the existing CommsLogEntry/HistoryMessage/ToolDefinition from_dict: - Filter dict keys to only the dataclass fields (ignore extras) - Pass filtered dict to cls(**filtered) Field definitions unchanged. No-op behavior for callers that already have a dataclass instance (they pass through isinstance check). Tests: 51/51 pass across all related test files. --- src/type_aliases.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/type_aliases.py b/src/type_aliases.py index 73cbfb59..5518873d 100644 --- a/src/type_aliases.py +++ b/src/type_aliases.py @@ -85,6 +85,10 @@ class SessionInsights: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "SessionInsights": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class DiscussionSettings: @@ -95,6 +99,10 @@ class DiscussionSettings: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "DiscussionSettings": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class CustomSlice: @@ -106,6 +114,10 @@ class CustomSlice: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "CustomSlice": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class MMAUsageStats: @@ -116,6 +128,10 @@ class MMAUsageStats: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "MMAUsageStats": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class ProviderPayload: @@ -127,6 +143,10 @@ class ProviderPayload: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "ProviderPayload": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class UIPanelConfig: @@ -137,6 +157,10 @@ class UIPanelConfig: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "UIPanelConfig": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + @dataclass(frozen=True) class PathInfo: @@ -147,6 +171,10 @@ class PathInfo: def to_dict(self) -> Metadata: return {f.name: getattr(self, f.name) for f in dc_fields(self)} + @classmethod + def from_dict(cls, data: Metadata) -> "PathInfo": + return cls(**{k: v for k, v in data.items() if k in {f.name for f in dc_fields(cls)}}) + CommsLogCallback: TypeAlias = Callable[[CommsLogEntry], None]