Source code for bacommon.docui.routes.docuitest

# Released under the MIT License. See LICENSE for details.
#
"""Routes for the doc-ui test domain."""

from __future__ import annotations  # Docs-generation hack.

from enum import Enum
from dataclasses import dataclass
from typing import TYPE_CHECKING, Annotated, override

from efro.dataclassio import ioprepped, IOAttrs

import bacommon.docui.v2 as dui2
from bacommon.docui.routes import (
    DocUIRoute,
    DocUILocalActionBase,
    DocUIState,
    family_members,
)

if TYPE_CHECKING:
    import bacommon.docui.v2


[docs] class TestRoute(DocUIRoute): """Family class for doc-ui test routes."""
[docs] @override @classmethod def get_route_types(cls) -> tuple[type[DocUIRoute], ...]: return family_members(AnyTestRoute)
[docs] @ioprepped @dataclass class Root(TestRoute, path='/'): """The root test page.""" #: Draw bounds and other debug bits. debug: bool = False #: Have the response include some client-effects. test_effects: bool = False #: Have the response include a local-action. test_action: bool = False
[docs] @ioprepped @dataclass class Test2(TestRoute, path='/test2'): """A second simple page."""
[docs] @ioprepped @dataclass class Slow(TestRoute, path='/slow'): """A page that takes a while to load."""
[docs] @ioprepped @dataclass class TimedActions(TestRoute, path='/timedactions'): """A page that counts down via timed-actions and then closes.""" val: int = 5
[docs] @ioprepped @dataclass class DisplayItems(TestRoute, path='/displayitems'): """Display-item tests.""" debug: bool = False
[docs] @ioprepped @dataclass class TextImages(TestRoute, path='/textimages'): """Text-with-images tests.""" debug: bool = False
[docs] @ioprepped @dataclass class Depictions(TestRoute, path='/depictions'): """Depiction tests.""" debug: bool = False
[docs] @ioprepped @dataclass class Names(TestRoute, path='/names'): """Name depiction tests (basic and capsule forms).""" debug: bool = False
[docs] @ioprepped @dataclass class EmptyPage(TestRoute, path='/emptypage'): """A page with nothing on it."""
[docs] @ioprepped @dataclass class BoundsTests(TestRoute, path='/boundstests'): """Button-style bounds tests."""
[docs] @ioprepped @dataclass class Widgets(TestRoute, path='/widgets'): """Control rows and page state.""" debug: bool = False
[docs] class ControlRowKind(Enum): """Kinds of control row (for :class:`NavTest`).""" CHECKBOX = 'checkbox' TEXT_INPUT = 'text' CHOICE = 'choice' SLIDER = 'slider' NUMBER = 'number' COLOR = 'color' BUTTON = 'button'
[docs] @ioprepped @dataclass class Sections(TestRoute, path='/sections'): """Sections: headings, notes, backings and spacing between them.""" debug: bool = False
[docs] @override @classmethod def get_window_layout(cls) -> dui2.WindowLayout: # A column, like the settings pages sections mostly live in. return dui2.WindowLayout.SMALL_TALLER
[docs] @ioprepped @dataclass class WindowLayouts(TestRoute, path='/windowlayouts'): """Assorted rows for judging window layouts (browse to it at each). Control rows, titles and button rows at every alignment, and long rows, which in a narrow column scroll within it. """ debug: bool = False
[docs] @ioprepped @dataclass class WideFit(TestRoute, path='/widefit'): """A row exactly as big as wide pages get (browse at each layout). It should fill the page's height (wide and wider) and width (wide) with no scrolling, at every ui-scale; with ``over`` / ``wide_over`` set it's a hair taller / wider, which should scroll. """ over: bool = False wide_over: bool = False
[docs] class Flavor(Enum): """Something to pick from on the widgets test page.""" VANILLA = 'v' CHOCOLATE = 'c' STRAWBERRY = 's' MINT = 'm'
[docs] class Size(Enum): """Something else to pick from on the widgets test page.""" S = 's' M = 'm' L = 'l' XL = 'x'
[docs] @ioprepped @dataclass class WidgetTestState(DocUIState, state_id='docuitest.widgets'): """State for the widgets test page.""" #: A checkbox with no on-change action. plain: bool = False #: A checkbox that re-requests the page when changed. live: bool = False #: Disabled checkboxes (selectable; not toggleable), one checked and #: one not. checked_disabled: bool = True unchecked_disabled: bool = False #: Nothing shows or edits this directly; it simply rides along #: (and gets bumped by a button). presses: int = 0 #: Text inputs with labels of assorted lengths. text_short: str = '' text_medium: str = 'Some text' text_long: str = '' #: A text input that re-requests the page when an edit is committed. text_live: str = '' #: A disabled text input (selectable; not editable). text_disabled: str = 'Not editable' #: Choices, plain and live. flavor: Flavor = Flavor.VANILLA flavor_live: Flavor = Flavor.VANILLA #: Short choice labels (a compact button) and an absurdly long one. size: Size = Size.M size_long: Size = Size.M #: An optional choice -- a 'nothing' option ahead of the flavors. topping: Flavor | None = None #: Choices over an arbitrary string set (the page defines the #: options, not an enum); plain and optional. difficulty: str = 'normal' region: str | None = None #: Disabled choice rows (selectable; menus won't open), one of each #: form: enum, optional enum, str, optional str. flavor_disabled: Flavor = ( Flavor.CHOCOLATE ) topping_disabled: Flavor | None = ( None ) difficulty_disabled: str = 'hard' region_disabled: str | None = 'eu' #: A slider value shaped like the sound-settings ones -- 0-1 by 0.05. volume: float = 0.5 #: A disabled slider (selectable; not adjustable). volume_disabled: float = 0.3 #: A number-row value shaped like a series length -- 1-21 by 2. series_length: float = 7.0 #: A disabled number row (selectable; not adjustable). series_length_disabled: float = 5.0 #: An rgb color, edited via the color-picker popup. tint: tuple[float, float, float] = ( 0.5, 0.25, 1.0, ) #: A disabled color row (selectable; picker won't open). tint_disabled: tuple[float, float, float] = (1.0, 0.6, 0.1) #: Checkboxes on rows demonstrating control-row spacing and header / #: footer bands (they drive nothing). spacing_top_demo: bool = False spacing_bottom_demo: bool = False bands_demo: bool = False
[docs] @ioprepped @dataclass class WebTestGet(TestRoute, path='/webtest/get'): """A page fetched from a web server via GET."""
[docs] @ioprepped @dataclass class WebTestPost( TestRoute, path='/webtest/post', method=dui2.RequestMethod.POST ): """A page fetched from a web server via POST."""
[docs] @ioprepped @dataclass class CloudMsgTestGet(TestRoute, path='/cloudmsgtest/get'): """A page fetched through our cloud connection via GET."""
[docs] @ioprepped @dataclass class CloudMsgTestPost( TestRoute, path='/cloudmsgtest/post', method=dui2.RequestMethod.POST ): """A page fetched through our cloud connection via POST."""
# All routes in the family. Handlers can match against this with # assert_never to be sure they cover everything. AnyTestRoute = ( Root | Test2 | Slow | TimedActions | DisplayItems | TextImages | Depictions | Names | EmptyPage | BoundsTests | Widgets | NavTest | Sections | WindowLayouts | WideFit | WebTestGet | WebTestPost | CloudMsgTestGet | CloudMsgTestPost )
[docs] class TestLocalAction(DocUILocalActionBase): """Family class for doc-ui test local-actions."""
[docs] @override @classmethod def get_action_types(cls) -> tuple[type[DocUILocalActionBase], ...]: return family_members(AnyTestLocalAction)
[docs] @ioprepped @dataclass class TestAction(TestLocalAction, name='testaction'): """Show a message proving we got here.""" testparam: int
# All local-actions in the family (just the one for now).
[docs] @ioprepped @dataclass class ShowVolume(TestLocalAction, name='showvolume'): """Show the volume slider's live value (fired while dragging)."""
AnyTestLocalAction = TestAction | ShowVolume # Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self, TypeIs) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum