streamtree 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamtree/__init__.py +19 -0
- streamtree/core/__init__.py +13 -0
- streamtree/core/component.py +36 -0
- streamtree/core/context.py +66 -0
- streamtree/core/element.py +51 -0
- streamtree/elements/__init__.py +59 -0
- streamtree/elements/layout.py +164 -0
- streamtree/elements/widgets.py +235 -0
- streamtree/py.typed +0 -0
- streamtree/renderers/__init__.py +5 -0
- streamtree/renderers/streamlit.py +335 -0
- streamtree/state/__init__.py +166 -0
- streamtree/testing/__init__.py +204 -0
- streamtree-0.1.0.dist-info/METADATA +207 -0
- streamtree-0.1.0.dist-info/RECORD +18 -0
- streamtree-0.1.0.dist-info/WHEEL +5 -0
- streamtree-0.1.0.dist-info/licenses/LICENSE +21 -0
- streamtree-0.1.0.dist-info/top_level.txt +1 -0
streamtree/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Streamtree: declarative, typed composition for Streamlit."""
|
|
2
|
+
|
|
3
|
+
from streamtree import elements, state, testing
|
|
4
|
+
from streamtree.core import ComponentCall, Element, Fragment, component, fragment, render
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0"
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"ComponentCall",
|
|
10
|
+
"Element",
|
|
11
|
+
"Fragment",
|
|
12
|
+
"__version__",
|
|
13
|
+
"component",
|
|
14
|
+
"elements",
|
|
15
|
+
"fragment",
|
|
16
|
+
"render",
|
|
17
|
+
"state",
|
|
18
|
+
"testing",
|
|
19
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Core primitives: elements, components, render."""
|
|
2
|
+
|
|
3
|
+
from streamtree.core.component import component, render
|
|
4
|
+
from streamtree.core.element import ComponentCall, Element, Fragment, fragment
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ComponentCall",
|
|
8
|
+
"Element",
|
|
9
|
+
"Fragment",
|
|
10
|
+
"component",
|
|
11
|
+
"fragment",
|
|
12
|
+
"render",
|
|
13
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""@component decorator and public render entrypoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from functools import wraps
|
|
7
|
+
from typing import ParamSpec, TypeVar
|
|
8
|
+
|
|
9
|
+
from streamtree.core.context import render_context
|
|
10
|
+
from streamtree.core.element import ComponentCall, Element
|
|
11
|
+
from streamtree.renderers.streamlit import render_element as _render_streamlit
|
|
12
|
+
|
|
13
|
+
P = ParamSpec("P")
|
|
14
|
+
R = TypeVar("R", bound=Element)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def component(fn: Callable[P, R]) -> Callable[P, ComponentCall]:
|
|
18
|
+
"""Mark a function as a Streamtree component.
|
|
19
|
+
|
|
20
|
+
The function body runs when the tree is rendered (each Streamlit rerun),
|
|
21
|
+
not when building the virtual tree from call sites like ``Page(Counter())``.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@wraps(fn)
|
|
25
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> ComponentCall:
|
|
26
|
+
kw = dict(kwargs)
|
|
27
|
+
key = kw.pop("key", None) # type: ignore[assignment]
|
|
28
|
+
return ComponentCall(fn=fn, args=args, kwargs=kw, key=key) # type: ignore[arg-type]
|
|
29
|
+
|
|
30
|
+
return wrapper # type: ignore[return-value]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def render(root: Element, *, context_root: str = "app") -> None:
|
|
34
|
+
"""Render a virtual element tree using the Streamlit backend."""
|
|
35
|
+
with render_context(context_root):
|
|
36
|
+
_render_streamlit(root)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Render-time context for stable keys and nested component paths."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterator
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from contextvars import ContextVar
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
|
|
10
|
+
_ctx: ContextVar[RenderContext | None] = ContextVar("streamtree_render_context", default=None)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class RenderContext:
|
|
15
|
+
"""Stacked path segments and a per-scope counter for anonymous state slots."""
|
|
16
|
+
|
|
17
|
+
parent: RenderContext | None
|
|
18
|
+
segment: str
|
|
19
|
+
_counter: int = field(default=0, repr=False)
|
|
20
|
+
|
|
21
|
+
def child(self, segment: str) -> RenderContext:
|
|
22
|
+
return RenderContext(parent=self, segment=segment)
|
|
23
|
+
|
|
24
|
+
def next_anonymous_index(self) -> int:
|
|
25
|
+
i = self._counter
|
|
26
|
+
self._counter += 1
|
|
27
|
+
return i
|
|
28
|
+
|
|
29
|
+
def path(self) -> str:
|
|
30
|
+
if self.parent is None:
|
|
31
|
+
return self.segment
|
|
32
|
+
base = self.parent.path()
|
|
33
|
+
return f"{base}.{self.segment}" if base else self.segment
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def current_context() -> RenderContext:
|
|
37
|
+
c = _ctx.get()
|
|
38
|
+
if c is None:
|
|
39
|
+
raise RuntimeError("streamtree: no active render context; call from inside render()")
|
|
40
|
+
return c
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@contextmanager
|
|
44
|
+
def render_context(root_segment: str = "app") -> Iterator[RenderContext]:
|
|
45
|
+
parent = _ctx.get()
|
|
46
|
+
ctx = (
|
|
47
|
+
RenderContext(parent=parent, segment=root_segment)
|
|
48
|
+
if parent
|
|
49
|
+
else RenderContext(parent=None, segment=root_segment)
|
|
50
|
+
)
|
|
51
|
+
token = _ctx.set(ctx)
|
|
52
|
+
try:
|
|
53
|
+
yield ctx
|
|
54
|
+
finally:
|
|
55
|
+
_ctx.reset(token)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@contextmanager
|
|
59
|
+
def push_segment(segment: str) -> Iterator[RenderContext]:
|
|
60
|
+
parent = current_context()
|
|
61
|
+
ctx = parent.child(segment)
|
|
62
|
+
token = _ctx.set(ctx)
|
|
63
|
+
try:
|
|
64
|
+
yield ctx
|
|
65
|
+
finally:
|
|
66
|
+
_ctx.reset(token)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Virtual element tree nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Sequence
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Any, TypeAlias
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class Element:
|
|
12
|
+
"""Base class for virtual tree nodes."""
|
|
13
|
+
|
|
14
|
+
key: str | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ElementChild: TypeAlias = Element | Sequence[Element | None] | None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class Fragment(Element):
|
|
22
|
+
"""Group multiple children without a Streamlit container."""
|
|
23
|
+
|
|
24
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def normalize_children(children: tuple[ElementChild, ...]) -> tuple[Element, ...]:
|
|
28
|
+
out: list[Element] = []
|
|
29
|
+
for ch in children:
|
|
30
|
+
if ch is None:
|
|
31
|
+
continue
|
|
32
|
+
if isinstance(ch, Element):
|
|
33
|
+
out.append(ch)
|
|
34
|
+
elif isinstance(ch, Sequence) and not isinstance(ch, (str, bytes)):
|
|
35
|
+
out.extend(normalize_children(tuple(ch))) # type: ignore[arg-type]
|
|
36
|
+
else:
|
|
37
|
+
raise TypeError(f"Invalid child type: {type(ch)!r}")
|
|
38
|
+
return tuple(out)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def fragment(*children: ElementChild, key: str | None = None) -> Fragment:
|
|
42
|
+
return Fragment(key=key, children=normalize_children(children))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class ComponentCall(Element):
|
|
47
|
+
"""Deferred invocation of a @component function."""
|
|
48
|
+
|
|
49
|
+
fn: Callable[..., Element] = field(kw_only=True, repr=False)
|
|
50
|
+
args: tuple[Any, ...] = field(default_factory=tuple, kw_only=True)
|
|
51
|
+
kwargs: dict[str, Any] = field(default_factory=dict, kw_only=True)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Declarative layout and widget primitives."""
|
|
2
|
+
|
|
3
|
+
from streamtree.core.element import Element, Fragment, fragment
|
|
4
|
+
from streamtree.elements.layout import (
|
|
5
|
+
Card,
|
|
6
|
+
Columns,
|
|
7
|
+
Expander,
|
|
8
|
+
Form,
|
|
9
|
+
Grid,
|
|
10
|
+
HStack,
|
|
11
|
+
Page,
|
|
12
|
+
Sidebar,
|
|
13
|
+
Spacer,
|
|
14
|
+
Tabs,
|
|
15
|
+
VStack,
|
|
16
|
+
)
|
|
17
|
+
from streamtree.elements.widgets import (
|
|
18
|
+
Button,
|
|
19
|
+
Checkbox,
|
|
20
|
+
DataFrame,
|
|
21
|
+
Divider,
|
|
22
|
+
Image,
|
|
23
|
+
Markdown,
|
|
24
|
+
NumberInput,
|
|
25
|
+
Selectbox,
|
|
26
|
+
Subheader,
|
|
27
|
+
Text,
|
|
28
|
+
TextInput,
|
|
29
|
+
Title,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"Button",
|
|
34
|
+
"Card",
|
|
35
|
+
"Checkbox",
|
|
36
|
+
"Columns",
|
|
37
|
+
"DataFrame",
|
|
38
|
+
"Divider",
|
|
39
|
+
"Element",
|
|
40
|
+
"Expander",
|
|
41
|
+
"Form",
|
|
42
|
+
"Fragment",
|
|
43
|
+
"Grid",
|
|
44
|
+
"HStack",
|
|
45
|
+
"Image",
|
|
46
|
+
"Markdown",
|
|
47
|
+
"NumberInput",
|
|
48
|
+
"Page",
|
|
49
|
+
"Selectbox",
|
|
50
|
+
"Sidebar",
|
|
51
|
+
"Spacer",
|
|
52
|
+
"Subheader",
|
|
53
|
+
"Tabs",
|
|
54
|
+
"Text",
|
|
55
|
+
"TextInput",
|
|
56
|
+
"Title",
|
|
57
|
+
"VStack",
|
|
58
|
+
"fragment",
|
|
59
|
+
]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Layout primitives."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
from streamtree.core.element import Element, ElementChild, normalize_children
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class VStack(Element):
|
|
12
|
+
"""Render children vertically in order."""
|
|
13
|
+
|
|
14
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
15
|
+
|
|
16
|
+
def __init__(self, *children: ElementChild, key: str | None = None) -> None:
|
|
17
|
+
object.__setattr__(self, "key", key)
|
|
18
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class HStack(Element):
|
|
23
|
+
"""Render children in a horizontal row of equal columns."""
|
|
24
|
+
|
|
25
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
26
|
+
gap: str | None = None
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
*children: ElementChild,
|
|
31
|
+
gap: str | None = None,
|
|
32
|
+
key: str | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
object.__setattr__(self, "key", key)
|
|
35
|
+
object.__setattr__(self, "gap", gap)
|
|
36
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class Columns(Element):
|
|
41
|
+
"""Render children in weighted columns (``weights`` length must match children)."""
|
|
42
|
+
|
|
43
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
44
|
+
weights: tuple[float, ...] = field(default_factory=tuple)
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
*children: ElementChild,
|
|
49
|
+
weights: tuple[float, ...] | None = None,
|
|
50
|
+
key: str | None = None,
|
|
51
|
+
) -> None:
|
|
52
|
+
ch = normalize_children(children)
|
|
53
|
+
object.__setattr__(self, "key", key)
|
|
54
|
+
object.__setattr__(self, "children", ch)
|
|
55
|
+
if weights is None:
|
|
56
|
+
object.__setattr__(self, "weights", tuple(1.0 for _ in ch))
|
|
57
|
+
else:
|
|
58
|
+
object.__setattr__(self, "weights", weights)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True)
|
|
62
|
+
class Grid(Element):
|
|
63
|
+
"""Render children left-to-right in a fixed column count."""
|
|
64
|
+
|
|
65
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
66
|
+
columns: int = 2
|
|
67
|
+
|
|
68
|
+
def __init__(self, *children: ElementChild, columns: int = 2, key: str | None = None) -> None:
|
|
69
|
+
object.__setattr__(self, "key", key)
|
|
70
|
+
object.__setattr__(self, "columns", max(1, columns))
|
|
71
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass(frozen=True)
|
|
75
|
+
class Card(Element):
|
|
76
|
+
"""Group content in a bordered container when supported by Streamlit."""
|
|
77
|
+
|
|
78
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
79
|
+
|
|
80
|
+
def __init__(self, *children: ElementChild, key: str | None = None) -> None:
|
|
81
|
+
object.__setattr__(self, "key", key)
|
|
82
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass(frozen=True)
|
|
86
|
+
class Page(Element):
|
|
87
|
+
"""Top-level page container (column layout)."""
|
|
88
|
+
|
|
89
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
90
|
+
|
|
91
|
+
def __init__(self, *children: ElementChild, key: str | None = None) -> None:
|
|
92
|
+
object.__setattr__(self, "key", key)
|
|
93
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True)
|
|
97
|
+
class Tabs(Element):
|
|
98
|
+
"""Named tabs; each entry is (title, child_element)."""
|
|
99
|
+
|
|
100
|
+
tabs: tuple[tuple[str, Element], ...] = ()
|
|
101
|
+
|
|
102
|
+
def __init__(self, *tabs: tuple[str, Element], key: str | None = None) -> None:
|
|
103
|
+
object.__setattr__(self, "key", key)
|
|
104
|
+
object.__setattr__(self, "tabs", tabs)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass(frozen=True)
|
|
108
|
+
class Sidebar(Element):
|
|
109
|
+
"""Render children in ``st.sidebar``."""
|
|
110
|
+
|
|
111
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
112
|
+
|
|
113
|
+
def __init__(self, *children: ElementChild, key: str | None = None) -> None:
|
|
114
|
+
object.__setattr__(self, "key", key)
|
|
115
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass(frozen=True)
|
|
119
|
+
class Form(Element):
|
|
120
|
+
"""Streamlit form boundary."""
|
|
121
|
+
|
|
122
|
+
form_key: str = "form"
|
|
123
|
+
clear_on_submit: bool = False
|
|
124
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
125
|
+
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
*children: ElementChild,
|
|
129
|
+
form_key: str = "form",
|
|
130
|
+
clear_on_submit: bool = False,
|
|
131
|
+
key: str | None = None,
|
|
132
|
+
) -> None:
|
|
133
|
+
object.__setattr__(self, "key", key)
|
|
134
|
+
object.__setattr__(self, "form_key", form_key)
|
|
135
|
+
object.__setattr__(self, "clear_on_submit", clear_on_submit)
|
|
136
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass(frozen=True)
|
|
140
|
+
class Expander(Element):
|
|
141
|
+
"""Collapsible section."""
|
|
142
|
+
|
|
143
|
+
label: str = ""
|
|
144
|
+
expanded: bool = False
|
|
145
|
+
children: tuple[Element, ...] = field(default_factory=tuple)
|
|
146
|
+
|
|
147
|
+
def __init__(
|
|
148
|
+
self,
|
|
149
|
+
label: str,
|
|
150
|
+
*children: ElementChild,
|
|
151
|
+
expanded: bool = False,
|
|
152
|
+
key: str | None = None,
|
|
153
|
+
) -> None:
|
|
154
|
+
object.__setattr__(self, "key", key)
|
|
155
|
+
object.__setattr__(self, "label", label)
|
|
156
|
+
object.__setattr__(self, "expanded", expanded)
|
|
157
|
+
object.__setattr__(self, "children", normalize_children(children))
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass(frozen=True)
|
|
161
|
+
class Spacer(Element):
|
|
162
|
+
"""Vertical breathing room."""
|
|
163
|
+
|
|
164
|
+
height: int | None = None
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""Leaf widgets and controls."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Sequence
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
|
|
9
|
+
from streamtree.core.element import Element
|
|
10
|
+
from streamtree.state import FormState, StateVar, ToggleState
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class Text(Element):
|
|
15
|
+
body: str = ""
|
|
16
|
+
|
|
17
|
+
def __init__(self, body: str, *, key: str | None = None) -> None:
|
|
18
|
+
object.__setattr__(self, "key", key)
|
|
19
|
+
object.__setattr__(self, "body", body)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class Markdown(Element):
|
|
24
|
+
body: str = ""
|
|
25
|
+
unsafe_allow_html: bool = False
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
body: str,
|
|
30
|
+
*,
|
|
31
|
+
unsafe_allow_html: bool = False,
|
|
32
|
+
key: str | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
object.__setattr__(self, "key", key)
|
|
35
|
+
object.__setattr__(self, "body", body)
|
|
36
|
+
object.__setattr__(self, "unsafe_allow_html", unsafe_allow_html)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class Button(Element):
|
|
41
|
+
label: str = ""
|
|
42
|
+
on_click: Callable[[], None] | None = None
|
|
43
|
+
disabled: bool = False
|
|
44
|
+
submit: bool = False
|
|
45
|
+
help: str | None = None
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
label: str,
|
|
50
|
+
*,
|
|
51
|
+
on_click: Callable[[], None] | None = None,
|
|
52
|
+
disabled: bool = False,
|
|
53
|
+
submit: bool = False,
|
|
54
|
+
help: str | None = None,
|
|
55
|
+
key: str | None = None,
|
|
56
|
+
) -> None:
|
|
57
|
+
object.__setattr__(self, "key", key)
|
|
58
|
+
object.__setattr__(self, "label", label)
|
|
59
|
+
object.__setattr__(self, "on_click", on_click)
|
|
60
|
+
object.__setattr__(self, "disabled", disabled)
|
|
61
|
+
object.__setattr__(self, "submit", submit)
|
|
62
|
+
object.__setattr__(self, "help", help)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class TextInput(Element):
|
|
67
|
+
label: str = ""
|
|
68
|
+
value: str | StateVar[str] | FormState[str] | None = None
|
|
69
|
+
placeholder: str | None = None
|
|
70
|
+
disabled: bool = False
|
|
71
|
+
type: Literal["default", "password"] = "default"
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
label: str,
|
|
76
|
+
*,
|
|
77
|
+
value: str | StateVar[str] | FormState[str] | None = None,
|
|
78
|
+
placeholder: str | None = None,
|
|
79
|
+
disabled: bool = False,
|
|
80
|
+
type: Literal["default", "password"] = "default",
|
|
81
|
+
key: str | None = None,
|
|
82
|
+
) -> None:
|
|
83
|
+
object.__setattr__(self, "key", key)
|
|
84
|
+
object.__setattr__(self, "label", label)
|
|
85
|
+
object.__setattr__(self, "value", value)
|
|
86
|
+
object.__setattr__(self, "placeholder", placeholder)
|
|
87
|
+
object.__setattr__(self, "disabled", disabled)
|
|
88
|
+
object.__setattr__(self, "type", type)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass(frozen=True)
|
|
92
|
+
class NumberInput(Element):
|
|
93
|
+
label: str = ""
|
|
94
|
+
value: int | float | StateVar[int] | StateVar[float] | None = None
|
|
95
|
+
min_value: int | float | None = None
|
|
96
|
+
max_value: int | float | None = None
|
|
97
|
+
step: int | float | None = None
|
|
98
|
+
format: str | None = None
|
|
99
|
+
disabled: bool = False
|
|
100
|
+
|
|
101
|
+
def __init__(
|
|
102
|
+
self,
|
|
103
|
+
label: str,
|
|
104
|
+
*,
|
|
105
|
+
value: int | float | StateVar[int] | StateVar[float] | None = None,
|
|
106
|
+
min_value: int | float | None = None,
|
|
107
|
+
max_value: int | float | None = None,
|
|
108
|
+
step: int | float | None = None,
|
|
109
|
+
format: str | None = None,
|
|
110
|
+
disabled: bool = False,
|
|
111
|
+
key: str | None = None,
|
|
112
|
+
) -> None:
|
|
113
|
+
object.__setattr__(self, "key", key)
|
|
114
|
+
object.__setattr__(self, "label", label)
|
|
115
|
+
object.__setattr__(self, "value", value)
|
|
116
|
+
object.__setattr__(self, "min_value", min_value)
|
|
117
|
+
object.__setattr__(self, "max_value", max_value)
|
|
118
|
+
object.__setattr__(self, "step", step)
|
|
119
|
+
object.__setattr__(self, "format", format)
|
|
120
|
+
object.__setattr__(self, "disabled", disabled)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass(frozen=True)
|
|
124
|
+
class Selectbox(Element):
|
|
125
|
+
label: str = ""
|
|
126
|
+
options: Sequence[Any] = ()
|
|
127
|
+
index: int | StateVar[int] | None = None
|
|
128
|
+
format_func: Callable[[Any], str] | None = None
|
|
129
|
+
disabled: bool = False
|
|
130
|
+
|
|
131
|
+
def __init__(
|
|
132
|
+
self,
|
|
133
|
+
label: str,
|
|
134
|
+
*,
|
|
135
|
+
options: Sequence[Any],
|
|
136
|
+
index: int | StateVar[int] | None = 0,
|
|
137
|
+
format_func: Callable[[Any], str] | None = None,
|
|
138
|
+
disabled: bool = False,
|
|
139
|
+
key: str | None = None,
|
|
140
|
+
) -> None:
|
|
141
|
+
object.__setattr__(self, "key", key)
|
|
142
|
+
object.__setattr__(self, "label", label)
|
|
143
|
+
object.__setattr__(self, "options", tuple(options))
|
|
144
|
+
object.__setattr__(self, "index", index)
|
|
145
|
+
object.__setattr__(self, "format_func", format_func)
|
|
146
|
+
object.__setattr__(self, "disabled", disabled)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass(frozen=True)
|
|
150
|
+
class Checkbox(Element):
|
|
151
|
+
label: str = ""
|
|
152
|
+
value: bool | StateVar[bool] | ToggleState | None = None
|
|
153
|
+
disabled: bool = False
|
|
154
|
+
|
|
155
|
+
def __init__(
|
|
156
|
+
self,
|
|
157
|
+
label: str,
|
|
158
|
+
*,
|
|
159
|
+
value: bool | StateVar[bool] | ToggleState | None = None,
|
|
160
|
+
disabled: bool = False,
|
|
161
|
+
key: str | None = None,
|
|
162
|
+
) -> None:
|
|
163
|
+
object.__setattr__(self, "key", key)
|
|
164
|
+
object.__setattr__(self, "label", label)
|
|
165
|
+
object.__setattr__(self, "value", value)
|
|
166
|
+
object.__setattr__(self, "disabled", disabled)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@dataclass(frozen=True)
|
|
170
|
+
class DataFrame(Element):
|
|
171
|
+
data: Any = None
|
|
172
|
+
width: int | None = None
|
|
173
|
+
height: int | None = None
|
|
174
|
+
|
|
175
|
+
def __init__(
|
|
176
|
+
self,
|
|
177
|
+
data: Any,
|
|
178
|
+
*,
|
|
179
|
+
width: int | None = None,
|
|
180
|
+
height: int | None = None,
|
|
181
|
+
key: str | None = None,
|
|
182
|
+
) -> None:
|
|
183
|
+
object.__setattr__(self, "key", key)
|
|
184
|
+
object.__setattr__(self, "data", data)
|
|
185
|
+
object.__setattr__(self, "width", width)
|
|
186
|
+
object.__setattr__(self, "height", height)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@dataclass(frozen=True)
|
|
190
|
+
class Image(Element):
|
|
191
|
+
image: Any = None
|
|
192
|
+
caption: str | None = None
|
|
193
|
+
width: int | None = None
|
|
194
|
+
use_column_width: bool | Literal["auto", "always", "never"] | None = None
|
|
195
|
+
|
|
196
|
+
def __init__(
|
|
197
|
+
self,
|
|
198
|
+
image: Any,
|
|
199
|
+
*,
|
|
200
|
+
caption: str | None = None,
|
|
201
|
+
width: int | None = None,
|
|
202
|
+
use_column_width: bool | Literal["auto", "always", "never"] | None = None,
|
|
203
|
+
key: str | None = None,
|
|
204
|
+
) -> None:
|
|
205
|
+
object.__setattr__(self, "key", key)
|
|
206
|
+
object.__setattr__(self, "image", image)
|
|
207
|
+
object.__setattr__(self, "caption", caption)
|
|
208
|
+
object.__setattr__(self, "width", width)
|
|
209
|
+
object.__setattr__(self, "use_column_width", use_column_width)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@dataclass(frozen=True)
|
|
213
|
+
class Divider(Element):
|
|
214
|
+
"""Horizontal rule."""
|
|
215
|
+
|
|
216
|
+
def __init__(self, *, key: str | None = None) -> None:
|
|
217
|
+
object.__setattr__(self, "key", key)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@dataclass(frozen=True)
|
|
221
|
+
class Title(Element):
|
|
222
|
+
text: str = ""
|
|
223
|
+
|
|
224
|
+
def __init__(self, text: str, *, key: str | None = None) -> None:
|
|
225
|
+
object.__setattr__(self, "key", key)
|
|
226
|
+
object.__setattr__(self, "text", text)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass(frozen=True)
|
|
230
|
+
class Subheader(Element):
|
|
231
|
+
text: str = ""
|
|
232
|
+
|
|
233
|
+
def __init__(self, text: str, *, key: str | None = None) -> None:
|
|
234
|
+
object.__setattr__(self, "key", key)
|
|
235
|
+
object.__setattr__(self, "text", text)
|
streamtree/py.typed
ADDED
|
File without changes
|