Skip to content

Commit

Permalink
Replace BaseModels with dataclasses in _format
Browse files Browse the repository at this point in the history
These classes do not need to be serializable and the dynamic creation
of generic classes does not play nicely with both pyright strict and
pydantic with the current class hierarchy. This could be refactored
in future to separate dynamic class creation from generic class
parameterization.
  • Loading branch information
GDYendell committed Jul 10, 2024
1 parent 615375e commit 8693912
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 33 deletions.
35 changes: 15 additions & 20 deletions src/pvi/_format/screen.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from __future__ import annotations

from collections.abc import Iterator, Sequence
from dataclasses import dataclass, field
from typing import (
Generic,
TypeVar,
)

from pydantic import BaseModel, Field

from pvi._format.utils import Bounds
from pvi._format.widget import (
GroupFormatter,
Expand Down Expand Up @@ -41,30 +40,26 @@
T = TypeVar("T")


class ScreenLayout(BaseModel):
spacing: int = Field(description="Spacing between widgets")
title_height: int = Field(description="Height of screen title bar")
max_height: int = Field(description="Max height of the screen")
group_label_height: int = Field(description="Height of the group title label")
label_width: int = Field(description="Width of the labels describing widgets")
widget_width: int = Field(description="Width of the widgets")
widget_height: int = Field(
description="Height of the widgets (Labels use this too)"
)
group_widget_indent: int = Field(
0, description="Indentation of widgets within groups. Defaults to 0"
)
group_width_offset: int = Field(
0, description="Additional border width when using group objects. Defaults to 0"
)
@dataclass
class ScreenLayout:
spacing: int
title_height: int
max_height: int
group_label_height: int
label_width: int
widget_width: int
widget_height: int
group_widget_indent: int
group_width_offset: int


class ScreenFormatterFactory(BaseModel, Generic[T]):
@dataclass
class ScreenFormatterFactory(Generic[T]):
screen_formatter_cls: type[GroupFormatter[T]]
group_formatter_cls: type[GroupFormatter[T]]
widget_formatter_factory: WidgetFormatterFactory[T]
layout: ScreenLayout
components: dict[str, ComponentUnion] = Field(default={}, init_var=False)
components: dict[str, ComponentUnion] = field(default_factory=dict)
base_file_name: str = ""

def create_screen_formatter(
Expand Down
31 changes: 18 additions & 13 deletions src/pvi/_format/widget.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any, Generic, TypeVar

from typing_extensions import Self

from pydantic import BaseModel, Field, create_model

from pvi._format.utils import Bounds
from pvi.device import (
LED,
Expand Down Expand Up @@ -79,7 +78,8 @@ def create_group(
raise NotImplementedError(self)


class WidgetFormatter(BaseModel, Generic[T]):
@dataclass
class WidgetFormatter(Generic[T]):
bounds: Bounds

def format(self) -> list[T]:
Expand Down Expand Up @@ -132,23 +132,26 @@ def format(self: WidgetFormatter[T]) -> list[T]:
)
]

return create_model(
return type( # type: ignore
f"""{cls.__name__}<{search.strip('"')}>""",
__base__=cls,
format=format,
(cls,),
{"format": format},
)


@dataclass
class LabelWidgetFormatter(WidgetFormatter[T]):
text: str
description: str = ""


@dataclass
class PVWidgetFormatter(WidgetFormatter[T]):
pv: str
widget: WidgetUnion


@dataclass
class ActionWidgetFormatter(WidgetFormatter[T]):
label: str
pv: str
Expand All @@ -159,18 +162,20 @@ def tooltip(self) -> str:
return f"{self.pv} = {self.value}"


@dataclass
class SubScreenWidgetFormatter(WidgetFormatter[T]):
label: str
file_name: str
components: Group | None = None
macros: dict[str, str] = Field(default={})
macros: dict[str, str] = field(default_factory=dict)


class GroupType(StrEnum):
GROUP = "GROUP"
SCREEN = "SCREEN"


@dataclass
class GroupFormatter(WidgetFormatter[T]):
bounds: Bounds
title: str
Expand All @@ -180,7 +185,7 @@ def format(self) -> list[T]:
"""Instances should be created using `from_template`, which defines `format`"""
raise NotImplementedError(self)

def model_post_init(self, _context: Any) -> None:
def __post_init__(self) -> None:
self.resize()

def resize(self):
Expand Down Expand Up @@ -259,15 +264,15 @@ def resize(self: GroupFormatter[T]):
)
pass

return create_model(
return type( # type: ignore
f"{cls.__name__}<{search}>",
__base__=cls,
format=format,
resize=resize,
(cls,),
{"format": format, "resize": resize},
)


class WidgetFormatterFactory(BaseModel, Generic[T]):
@dataclass
class WidgetFormatterFactory(Generic[T]):
header_formatter_cls: type[LabelWidgetFormatter[T]]
label_formatter_cls: type[LabelWidgetFormatter[T]]
led_formatter_cls: type[PVWidgetFormatter[T]]
Expand Down

0 comments on commit 8693912

Please sign in to comment.