ex4nicegui 0.7.1__py3-none-any.whl → 0.8.1__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.
- ex4nicegui/reactive/EChartsComponent/ECharts.js +2 -3
- ex4nicegui/reactive/EChartsComponent/ECharts.py +2 -4
- ex4nicegui/reactive/__init__.py +2 -1
- ex4nicegui/reactive/base.py +108 -50
- ex4nicegui/reactive/mermaid/mermaid.py +2 -5
- ex4nicegui/reactive/mixins/backgroundColor.py +4 -8
- ex4nicegui/reactive/mixins/disableable.py +4 -8
- ex4nicegui/reactive/mixins/flexLayout.py +51 -0
- ex4nicegui/reactive/mixins/textColor.py +8 -10
- ex4nicegui/reactive/mixins/value_element.py +27 -0
- ex4nicegui/reactive/officials/card.py +32 -2
- ex4nicegui/reactive/officials/checkbox.py +7 -12
- ex4nicegui/reactive/officials/chip.py +11 -1
- ex4nicegui/reactive/officials/circular_progress.py +7 -11
- ex4nicegui/reactive/officials/color_picker.py +4 -10
- ex4nicegui/reactive/officials/column.py +19 -11
- ex4nicegui/reactive/officials/date.py +4 -11
- ex4nicegui/reactive/officials/dialog.py +4 -11
- ex4nicegui/reactive/officials/echarts.py +9 -7
- ex4nicegui/reactive/officials/expansion.py +4 -11
- ex4nicegui/reactive/officials/input.py +13 -13
- ex4nicegui/reactive/officials/knob.py +4 -13
- ex4nicegui/reactive/officials/linear_progress.py +6 -11
- ex4nicegui/reactive/officials/number.py +7 -11
- ex4nicegui/reactive/officials/radio.py +4 -12
- ex4nicegui/reactive/officials/row.py +18 -11
- ex4nicegui/reactive/officials/slider.py +4 -12
- ex4nicegui/reactive/officials/switch.py +5 -12
- ex4nicegui/reactive/officials/tab_panels.py +4 -8
- ex4nicegui/reactive/officials/tabs.py +4 -9
- ex4nicegui/reactive/officials/textarea.py +6 -12
- ex4nicegui/reactive/services/reactive_service.py +2 -1
- ex4nicegui/reactive/vfor.py +4 -0
- ex4nicegui/reactive/view_model.py +147 -6
- ex4nicegui/utils/proxy/__init__.py +19 -0
- ex4nicegui/utils/proxy/base.py +9 -0
- ex4nicegui/utils/proxy/bool.py +58 -0
- ex4nicegui/utils/proxy/date.py +88 -0
- ex4nicegui/utils/proxy/descriptor.py +126 -0
- ex4nicegui/utils/proxy/dict.py +110 -0
- ex4nicegui/utils/proxy/float.py +153 -0
- ex4nicegui/utils/proxy/int.py +223 -0
- ex4nicegui/utils/proxy/list.py +147 -0
- ex4nicegui/utils/proxy/string.py +430 -0
- ex4nicegui/utils/proxy/utils.py +6 -0
- ex4nicegui/utils/signals.py +9 -1
- {ex4nicegui-0.7.1.dist-info → ex4nicegui-0.8.1.dist-info}/METADATA +497 -244
- {ex4nicegui-0.7.1.dist-info → ex4nicegui-0.8.1.dist-info}/RECORD +50 -37
- {ex4nicegui-0.7.1.dist-info → ex4nicegui-0.8.1.dist-info}/LICENSE +0 -0
- {ex4nicegui-0.7.1.dist-info → ex4nicegui-0.8.1.dist-info}/WHEEL +0 -0
|
@@ -10,9 +10,10 @@ from ex4nicegui.utils.signals import (
|
|
|
10
10
|
from ex4nicegui.utils.scheduler import next_tick
|
|
11
11
|
from nicegui import ui, background_tasks, core
|
|
12
12
|
from .base import BindableUi
|
|
13
|
+
from ex4nicegui.reactive.mixins.value_element import ValueElementMixin
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class TabPanelsBindableUi(BindableUi[ui.tab_panels]):
|
|
16
|
+
class TabPanelsBindableUi(BindableUi[ui.tab_panels], ValueElementMixin[bool]):
|
|
16
17
|
def __init__(
|
|
17
18
|
self,
|
|
18
19
|
value: Optional[TMaybeRef[str]] = None,
|
|
@@ -50,16 +51,11 @@ class TabPanelsBindableUi(BindableUi[ui.tab_panels]):
|
|
|
50
51
|
return self.element.value
|
|
51
52
|
|
|
52
53
|
def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
|
|
53
|
-
if prop
|
|
54
|
-
return self
|
|
54
|
+
if ValueElementMixin._bind_specified_props(self, prop, value):
|
|
55
|
+
return self
|
|
55
56
|
|
|
56
57
|
return super().bind_prop(prop, value)
|
|
57
58
|
|
|
58
|
-
def bind_value(self, value: TGetterOrReadonlyRef):
|
|
59
|
-
@self._ui_effect
|
|
60
|
-
def _():
|
|
61
|
-
self.element.set_value(to_value(value))
|
|
62
|
-
|
|
63
59
|
|
|
64
60
|
class lazy_tab_panel(ui.tab_panel):
|
|
65
61
|
def __init__(self, name: str) -> None:
|
|
@@ -2,14 +2,14 @@ from typing import Any, Callable, Optional
|
|
|
2
2
|
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
3
3
|
from ex4nicegui.utils.signals import (
|
|
4
4
|
TGetterOrReadonlyRef,
|
|
5
|
-
to_value,
|
|
6
5
|
_TMaybeRef as TMaybeRef,
|
|
7
6
|
)
|
|
8
7
|
from nicegui import ui
|
|
9
8
|
from .base import BindableUi
|
|
9
|
+
from ex4nicegui.reactive.mixins.value_element import ValueElementMixin
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class TabsBindableUi(BindableUi[ui.tabs]):
|
|
12
|
+
class TabsBindableUi(BindableUi[ui.tabs], ValueElementMixin[str]):
|
|
13
13
|
def __init__(
|
|
14
14
|
self,
|
|
15
15
|
value: Optional[TMaybeRef[str]] = None,
|
|
@@ -33,12 +33,7 @@ class TabsBindableUi(BindableUi[ui.tabs]):
|
|
|
33
33
|
return self.element.value
|
|
34
34
|
|
|
35
35
|
def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
|
|
36
|
-
if prop
|
|
37
|
-
return self
|
|
36
|
+
if ValueElementMixin._bind_specified_props(self, prop, value):
|
|
37
|
+
return self
|
|
38
38
|
|
|
39
39
|
return super().bind_prop(prop, value)
|
|
40
|
-
|
|
41
|
-
def bind_value(self, value: TGetterOrReadonlyRef):
|
|
42
|
-
@self._ui_effect
|
|
43
|
-
def _():
|
|
44
|
-
self.element.set_value(to_value(value))
|
|
@@ -16,9 +16,10 @@ from ex4nicegui.utils.signals import (
|
|
|
16
16
|
from nicegui import ui
|
|
17
17
|
from nicegui.events import handle_event
|
|
18
18
|
from .base import BindableUi
|
|
19
|
+
from ex4nicegui.reactive.mixins.value_element import ValueElementMixin
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class TextareaBindableUi(BindableUi[ui.textarea]):
|
|
22
|
+
class TextareaBindableUi(BindableUi[ui.textarea], ValueElementMixin[str]):
|
|
22
23
|
def __init__(
|
|
23
24
|
self,
|
|
24
25
|
label: Optional[TMaybeRef[str]] = None,
|
|
@@ -26,7 +27,7 @@ class TextareaBindableUi(BindableUi[ui.textarea]):
|
|
|
26
27
|
placeholder: Optional[TMaybeRef[str]] = None,
|
|
27
28
|
value: TMaybeRef[str] = "",
|
|
28
29
|
on_change: Optional[Callable[..., Any]] = None,
|
|
29
|
-
validation: Dict[str, Callable[..., bool]] =
|
|
30
|
+
validation: Optional[Dict[str, Callable[..., bool]]] = None,
|
|
30
31
|
) -> None:
|
|
31
32
|
pc = ParameterClassifier(
|
|
32
33
|
locals(),
|
|
@@ -53,18 +54,11 @@ class TextareaBindableUi(BindableUi[ui.textarea]):
|
|
|
53
54
|
return self.element.value
|
|
54
55
|
|
|
55
56
|
def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
|
|
56
|
-
if prop
|
|
57
|
-
return self
|
|
57
|
+
if ValueElementMixin._bind_specified_props(self, prop, value):
|
|
58
|
+
return self
|
|
58
59
|
|
|
59
60
|
return super().bind_prop(prop, value)
|
|
60
61
|
|
|
61
|
-
def bind_value(self, value: TGetterOrReadonlyRef[str]):
|
|
62
|
-
@self._ui_signal_on(value)
|
|
63
|
-
def _():
|
|
64
|
-
self.element.set_value(to_value(value))
|
|
65
|
-
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
62
|
|
|
69
63
|
class LazyTextareaBindableUi(TextareaBindableUi):
|
|
70
64
|
def __init__(
|
|
@@ -74,7 +68,7 @@ class LazyTextareaBindableUi(TextareaBindableUi):
|
|
|
74
68
|
placeholder: Optional[TMaybeRef[str]] = None,
|
|
75
69
|
value: TMaybeRef[str] = "",
|
|
76
70
|
on_change: Optional[Callable[..., Any]] = None,
|
|
77
|
-
validation: Dict[str, Callable[..., bool]] =
|
|
71
|
+
validation: Optional[Dict[str, Callable[..., bool]]] = None,
|
|
78
72
|
) -> None:
|
|
79
73
|
org_value = value
|
|
80
74
|
is_setter_value = is_setter_ref(value)
|
|
@@ -15,6 +15,7 @@ from ex4nicegui.reactive.systems.reactive_system import (
|
|
|
15
15
|
convert_kws_ref2value,
|
|
16
16
|
inject_method,
|
|
17
17
|
)
|
|
18
|
+
from ex4nicegui.utils.proxy import is_base_type_proxy
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class ParameterClassifier:
|
|
@@ -34,7 +35,7 @@ class ParameterClassifier:
|
|
|
34
35
|
exclude.append(extend_kws)
|
|
35
36
|
|
|
36
37
|
self._args: Dict[str, Any] = {
|
|
37
|
-
k: v
|
|
38
|
+
k: v._ref if is_base_type_proxy(v) else v
|
|
38
39
|
for k, v in args.items()
|
|
39
40
|
if k != "self" and k[0] != "_" and (k not in exclude)
|
|
40
41
|
}
|
ex4nicegui/reactive/vfor.py
CHANGED
|
@@ -28,6 +28,8 @@ from dataclasses import dataclass
|
|
|
28
28
|
from signe.core.scope import Scope
|
|
29
29
|
from ex4nicegui.reactive.systems.object_system import get_attribute
|
|
30
30
|
from ex4nicegui.reactive.empty import Empty
|
|
31
|
+
from ex4nicegui.utils.proxy import to_ref_if_base_type_proxy
|
|
32
|
+
|
|
31
33
|
|
|
32
34
|
_T = TypeVar("_T")
|
|
33
35
|
_T_data = Union[List[Any], TGetterOrReadonlyRef[List[Any]], RefWrapper]
|
|
@@ -178,6 +180,8 @@ class vfor(Generic[_T]):
|
|
|
178
180
|
*,
|
|
179
181
|
key: Optional[Union[str, Callable[[int, Any], Any]]] = None,
|
|
180
182
|
) -> None:
|
|
183
|
+
data = to_ref_if_base_type_proxy(data)
|
|
184
|
+
|
|
181
185
|
self._data = to_ref_wrapper(lambda: data) if is_reactive(data) else data
|
|
182
186
|
self._get_key = vfor.index_key
|
|
183
187
|
self._transition_props = {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Callable, Union, Type, TypeVar
|
|
2
|
+
from typing import Any, Callable, List, Optional, Union, Type, TypeVar, overload
|
|
3
3
|
from ex4nicegui.utils.signals import (
|
|
4
4
|
deep_ref,
|
|
5
5
|
is_ref,
|
|
@@ -13,8 +13,16 @@ from ex4nicegui.utils.signals import (
|
|
|
13
13
|
from ex4nicegui.utils.types import ReadonlyRef
|
|
14
14
|
from functools import partial
|
|
15
15
|
from signe.core.reactive import NoProxy
|
|
16
|
+
from ex4nicegui.utils.proxy.descriptor import class_var_setter
|
|
17
|
+
from ex4nicegui.utils.proxy.bool import BoolProxy
|
|
18
|
+
from ex4nicegui.utils.proxy.int import IntProxy
|
|
19
|
+
from ex4nicegui.utils.proxy.float import FloatProxy
|
|
20
|
+
from ex4nicegui.utils.proxy.base import Proxy
|
|
21
|
+
from ex4nicegui.utils.proxy import to_value_if_base_type_proxy
|
|
22
|
+
from ex4nicegui.utils.proxy.descriptor import ProxyDescriptor
|
|
16
23
|
|
|
17
24
|
_CACHED_VARS_FLAG = "__vm_cached__"
|
|
25
|
+
_LIST_VAR_FLAG = "__vm_list_var__"
|
|
18
26
|
|
|
19
27
|
_T = TypeVar("_T")
|
|
20
28
|
|
|
@@ -31,15 +39,30 @@ class ViewModel(NoProxy):
|
|
|
31
39
|
from ex4nicegui import rxui
|
|
32
40
|
|
|
33
41
|
class MyVm(rxui.ViewModel):
|
|
34
|
-
count =
|
|
35
|
-
data =
|
|
42
|
+
count = 0
|
|
43
|
+
data = []
|
|
44
|
+
nums = rxui.list_var(lambda: [1, 2, 3])
|
|
45
|
+
|
|
46
|
+
def __init__(self):
|
|
47
|
+
super().__init__()
|
|
48
|
+
self.data = [1, 2, 3]
|
|
49
|
+
|
|
50
|
+
def increment(self):
|
|
51
|
+
self.count += 1
|
|
52
|
+
|
|
53
|
+
def add_data(self):
|
|
54
|
+
self.data.append(4)
|
|
55
|
+
|
|
36
56
|
|
|
37
57
|
vm = MyVm()
|
|
38
58
|
|
|
39
59
|
rxui.label(vm.count)
|
|
40
60
|
rxui.number(value=vm.count)
|
|
41
61
|
|
|
42
|
-
|
|
62
|
+
ui.button("Increment", on_click=vm.increment)
|
|
63
|
+
ui.button("Add Data", on_click=vm.add_data)
|
|
64
|
+
rxui.label(vm.data)
|
|
65
|
+
rxui.label(vm.nums)
|
|
43
66
|
"""
|
|
44
67
|
|
|
45
68
|
def __init__(self):
|
|
@@ -49,8 +72,86 @@ class ViewModel(NoProxy):
|
|
|
49
72
|
if callable(value) and hasattr(value, _CACHED_VARS_FLAG):
|
|
50
73
|
setattr(self, name, computed(partial(value, self)))
|
|
51
74
|
|
|
75
|
+
def __init_subclass__(cls) -> None:
|
|
76
|
+
need_vars = (
|
|
77
|
+
(name, value)
|
|
78
|
+
for name, value in vars(cls).items()
|
|
79
|
+
if not name.startswith("_")
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
for name, value in need_vars:
|
|
83
|
+
class_var_setter(cls, name, value, _LIST_VAR_FLAG)
|
|
84
|
+
|
|
85
|
+
@overload
|
|
86
|
+
@staticmethod
|
|
87
|
+
def on_refs_changed(vm: ViewModel): ...
|
|
88
|
+
|
|
89
|
+
@overload
|
|
90
|
+
@staticmethod
|
|
91
|
+
def on_refs_changed(
|
|
92
|
+
vm: ViewModel, callback: Optional[Callable[[], Any]] = None
|
|
93
|
+
): ...
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def on_refs_changed(vm: ViewModel, callback: Optional[Callable[[], Any]] = None):
|
|
97
|
+
if callback is None:
|
|
98
|
+
|
|
99
|
+
def wrapper(fn: Callable[[], Any]):
|
|
100
|
+
return ViewModel.on_refs_changed(vm, fn)
|
|
101
|
+
|
|
102
|
+
return wrapper
|
|
103
|
+
|
|
104
|
+
refs = ViewModel.get_refs(vm)
|
|
105
|
+
|
|
106
|
+
@on(refs, onchanges=True, deep=False)
|
|
107
|
+
def _():
|
|
108
|
+
callback()
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def get_refs(vm: ViewModel):
|
|
112
|
+
"""Get all the refs of a ViewModel.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
vm (ViewModel): The ViewModel to get refs from.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
var_names = [
|
|
120
|
+
name
|
|
121
|
+
for name, value in vm.__class__.__dict__.items()
|
|
122
|
+
if isinstance(value, ProxyDescriptor)
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
return [getattr(vm, name) for name in var_names]
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def to_value(value: Union[ViewModel, Proxy, List, dict]):
|
|
129
|
+
"""Convert a ViewModel, Proxy, List, or dict to a value.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
value (Union[ViewModel, Proxy, List, dict]): The value to convert.
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
if isinstance(value, list):
|
|
136
|
+
return [ViewModel.to_value(v) for v in value]
|
|
137
|
+
|
|
138
|
+
if isinstance(value, dict):
|
|
139
|
+
return {k: ViewModel.to_value(v) for k, v in value.items()}
|
|
140
|
+
|
|
141
|
+
if isinstance(value, ViewModel):
|
|
142
|
+
return {
|
|
143
|
+
k: ViewModel.to_value(v)
|
|
144
|
+
for k, v in value.__dict__.items()
|
|
145
|
+
if not k.startswith("_")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if isinstance(value, Proxy):
|
|
149
|
+
return to_value_if_base_type_proxy(value)
|
|
150
|
+
|
|
151
|
+
return value
|
|
152
|
+
|
|
52
153
|
@staticmethod
|
|
53
|
-
def
|
|
154
|
+
def _display(model: Union[ViewModel, Type]):
|
|
54
155
|
result = to_ref("")
|
|
55
156
|
|
|
56
157
|
watch_refs = _recursive_to_refs(model)
|
|
@@ -67,6 +168,18 @@ class ViewModel(NoProxy):
|
|
|
67
168
|
|
|
68
169
|
return result
|
|
69
170
|
|
|
171
|
+
@staticmethod
|
|
172
|
+
def is_bool(value: Any):
|
|
173
|
+
return isinstance(value, bool) or isinstance(value, BoolProxy)
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def is_int(value: Any):
|
|
177
|
+
return isinstance(value, int) or isinstance(value, IntProxy)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def is_float(value: Any):
|
|
181
|
+
return isinstance(value, float) or isinstance(value, FloatProxy)
|
|
182
|
+
|
|
70
183
|
|
|
71
184
|
def _recursive_to_value(value_or_model):
|
|
72
185
|
value = to_raw(to_value(value_or_model))
|
|
@@ -139,6 +252,34 @@ def var(value: Union[_T_Var_Value, Callable[[], _T_Var_Value]]) -> Ref[_T_Var_Va
|
|
|
139
252
|
return deep_ref(value)
|
|
140
253
|
|
|
141
254
|
|
|
255
|
+
def list_var(factory: Callable[[], List[_T_Var_Value]]) -> List[_T_Var_Value]:
|
|
256
|
+
"""Create implicitly proxied reactive variables for lists. Use them just like ordinary lists while maintaining reactivity. Only use within rxui.ViewModel.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
factory (Callable[[], List[_T_Var_Value]]): A factory function that returns a new list.
|
|
260
|
+
|
|
261
|
+
Example:
|
|
262
|
+
.. code-block:: python
|
|
263
|
+
from ex4nicegui import rxui
|
|
264
|
+
class State(rxui.ViewModel):
|
|
265
|
+
data = rxui.list_var(lambda: [1, 2, 3])
|
|
266
|
+
|
|
267
|
+
def append_data(self):
|
|
268
|
+
self.data.append(len(self.data) + 1)
|
|
269
|
+
|
|
270
|
+
def display_data(self):
|
|
271
|
+
return ",".join(map(str, self.data))
|
|
272
|
+
|
|
273
|
+
state = State()
|
|
274
|
+
ui.button("Append", on_click=state.append_data)
|
|
275
|
+
rxui.label(state.display_data)
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
assert callable(factory), "factory must be a callable"
|
|
279
|
+
setattr(factory, _LIST_VAR_FLAG, None)
|
|
280
|
+
return factory # type: ignore
|
|
281
|
+
|
|
282
|
+
|
|
142
283
|
def cached_var(func: Callable[..., _T]) -> ReadonlyRef[_T]:
|
|
143
284
|
"""A decorator to cache the result of a function. Only use within rxui.ViewModel.
|
|
144
285
|
|
|
@@ -149,7 +290,7 @@ def cached_var(func: Callable[..., _T]) -> ReadonlyRef[_T]:
|
|
|
149
290
|
.. code-block:: python
|
|
150
291
|
from ex4nicegui import rxui
|
|
151
292
|
class MyVm(rxui.ViewModel):
|
|
152
|
-
name =
|
|
293
|
+
name = "John"
|
|
153
294
|
|
|
154
295
|
@rxui.cached_var
|
|
155
296
|
def uppper_name(self):
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .base import Proxy
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def is_base_type_proxy(obj):
|
|
5
|
+
return isinstance(obj, Proxy)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def to_ref_if_base_type_proxy(obj):
|
|
9
|
+
if is_base_type_proxy(obj):
|
|
10
|
+
return obj._ref
|
|
11
|
+
else:
|
|
12
|
+
return obj
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def to_value_if_base_type_proxy(obj):
|
|
16
|
+
if is_base_type_proxy(obj):
|
|
17
|
+
return obj._ref.value
|
|
18
|
+
else:
|
|
19
|
+
return obj
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
from . import utils
|
|
3
|
+
from .base import Proxy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BoolProxy(Proxy):
|
|
7
|
+
def __init__(self, value: bool):
|
|
8
|
+
from ex4nicegui.utils.signals import to_ref
|
|
9
|
+
|
|
10
|
+
if isinstance(value, (bool, int)):
|
|
11
|
+
self._ref = to_ref(value)
|
|
12
|
+
else:
|
|
13
|
+
raise ValueError("only accepts boolean or integer values")
|
|
14
|
+
|
|
15
|
+
def __bool__(self):
|
|
16
|
+
return self._ref.value
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return str(self._ref.value)
|
|
20
|
+
|
|
21
|
+
def __eq__(self, other):
|
|
22
|
+
return self._ref.value.__eq__(utils.to_value(other))
|
|
23
|
+
|
|
24
|
+
def __ne__(self, other):
|
|
25
|
+
return self._ref.value.__ne__(utils.to_value(other))
|
|
26
|
+
|
|
27
|
+
def __lt__(self, value) -> bool:
|
|
28
|
+
return self._ref.value.__lt__(bool(utils.to_value(value)))
|
|
29
|
+
|
|
30
|
+
def __le__(self, value) -> bool:
|
|
31
|
+
return self._ref.value.__le__(bool(utils.to_value(value)))
|
|
32
|
+
|
|
33
|
+
def __gt__(self, value) -> bool:
|
|
34
|
+
return self._ref.value.__gt__(bool(utils.to_value(value)))
|
|
35
|
+
|
|
36
|
+
def __ge__(self, value) -> bool:
|
|
37
|
+
return self._ref.value.__ge__(bool(utils.to_value(value)))
|
|
38
|
+
|
|
39
|
+
def __and__(self, other):
|
|
40
|
+
return self._ref.value.__and__(utils.to_value(other))
|
|
41
|
+
|
|
42
|
+
def __or__(self, other):
|
|
43
|
+
return self._ref.value.__or__(utils.to_value(other))
|
|
44
|
+
|
|
45
|
+
def __xor__(self, other):
|
|
46
|
+
return self._ref.value.__xor__(utils.to_value(other))
|
|
47
|
+
|
|
48
|
+
def __rand__(self, value: bool, /) -> bool:
|
|
49
|
+
return self._ref.value.__rand__(value)
|
|
50
|
+
|
|
51
|
+
def __ror__(self, value: bool, /) -> bool:
|
|
52
|
+
return self._ref.value.__ror__(value)
|
|
53
|
+
|
|
54
|
+
def __rxor__(self, value: bool, /) -> bool:
|
|
55
|
+
return self._ref.value.__rxor__(value)
|
|
56
|
+
|
|
57
|
+
def __getnewargs__(self) -> Tuple[int]:
|
|
58
|
+
return (int(self._ref.value),)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from . import utils
|
|
2
|
+
import datetime
|
|
3
|
+
from .base import Proxy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DateProxy(Proxy, datetime.date):
|
|
7
|
+
def __new__(cls, year, month=None, day=None):
|
|
8
|
+
return super().__new__(cls, year, month, day)
|
|
9
|
+
|
|
10
|
+
def __init__(self, year, month, day):
|
|
11
|
+
from ex4nicegui.utils.signals import to_ref
|
|
12
|
+
|
|
13
|
+
self._ref = to_ref(datetime.date(year, month, day))
|
|
14
|
+
|
|
15
|
+
def __str__(self):
|
|
16
|
+
return str(self._ref.value)
|
|
17
|
+
|
|
18
|
+
def ctime(self):
|
|
19
|
+
return self._ref.value.ctime()
|
|
20
|
+
|
|
21
|
+
def strftime(self, fmt):
|
|
22
|
+
return self._ref.value.strftime(fmt)
|
|
23
|
+
|
|
24
|
+
def __format__(self, fmt):
|
|
25
|
+
return self._ref.value.__format__(fmt)
|
|
26
|
+
|
|
27
|
+
def isoformat(self):
|
|
28
|
+
return self._ref.value.isoformat()
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def year(self):
|
|
32
|
+
return self._ref.value.year
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def month(self):
|
|
36
|
+
return self._ref.value.month
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def day(self):
|
|
40
|
+
return self._ref.value.day
|
|
41
|
+
|
|
42
|
+
def timetuple(self):
|
|
43
|
+
return self._ref.value.timetuple()
|
|
44
|
+
|
|
45
|
+
def toordinal(self):
|
|
46
|
+
return self._ref.value.toordinal()
|
|
47
|
+
|
|
48
|
+
def replace(self, year=None, month=None, day=None):
|
|
49
|
+
return self._ref.value.replace(year=year, month=month, day=day)
|
|
50
|
+
|
|
51
|
+
def __eq__(self, other):
|
|
52
|
+
return self._ref.value.__eq__(utils.to_value(other))
|
|
53
|
+
|
|
54
|
+
def __le__(self, other):
|
|
55
|
+
return self._ref.value.__le__(utils.to_value(other))
|
|
56
|
+
|
|
57
|
+
def __lt__(self, other):
|
|
58
|
+
return self._ref.value.__lt__(utils.to_value(other))
|
|
59
|
+
|
|
60
|
+
def __ge__(self, other):
|
|
61
|
+
return self._ref.value.__ge__(utils.to_value(other))
|
|
62
|
+
|
|
63
|
+
def __gt__(self, other):
|
|
64
|
+
return self._ref.value.__gt__(utils.to_value(other))
|
|
65
|
+
|
|
66
|
+
def __hash__(self):
|
|
67
|
+
return self._ref.value.__hash__()
|
|
68
|
+
|
|
69
|
+
def __add__(self, other):
|
|
70
|
+
return self._ref.value.__add__(utils.to_value(other))
|
|
71
|
+
|
|
72
|
+
def __radd__(self, other):
|
|
73
|
+
return self._ref.value.__radd__(utils.to_value(other))
|
|
74
|
+
|
|
75
|
+
def __sub__(self, other):
|
|
76
|
+
return self._ref.value.__sub__(utils.to_value(other))
|
|
77
|
+
|
|
78
|
+
def weekday(self):
|
|
79
|
+
return self._ref.value.weekday()
|
|
80
|
+
|
|
81
|
+
def isoweekday(self):
|
|
82
|
+
return self._ref.value.isoweekday()
|
|
83
|
+
|
|
84
|
+
def isocalendar(self):
|
|
85
|
+
return self._ref.value.isocalendar()
|
|
86
|
+
|
|
87
|
+
def __reduce__(self):
|
|
88
|
+
return self._ref.value.__reduce__()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Generic
|
|
3
|
+
from .base import ProxyProtocol
|
|
4
|
+
from .int import IntProxy
|
|
5
|
+
from .list import ListProxy
|
|
6
|
+
from .string import StringProxy
|
|
7
|
+
from .float import FloatProxy
|
|
8
|
+
from .bool import BoolProxy
|
|
9
|
+
from .date import DateProxy
|
|
10
|
+
from .dict import DictProxy
|
|
11
|
+
import datetime
|
|
12
|
+
import warnings
|
|
13
|
+
from . import to_value_if_base_type_proxy
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProxyDescriptor(Generic[T]):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
name: str,
|
|
22
|
+
value: T,
|
|
23
|
+
proxy_builder: Callable[[T], ProxyProtocol],
|
|
24
|
+
proxy_rebuilder: Optional[Callable[[ProxyProtocol], ProxyProtocol]] = None,
|
|
25
|
+
) -> None:
|
|
26
|
+
self.value = value
|
|
27
|
+
self.name = name
|
|
28
|
+
self._proxy_builder = proxy_builder
|
|
29
|
+
self._proxy_rebuilder = proxy_rebuilder
|
|
30
|
+
|
|
31
|
+
def __get__(self, instance: object, owner: Any):
|
|
32
|
+
if instance is None:
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
proxy = instance.__dict__.get(self.name, None)
|
|
36
|
+
if proxy is None:
|
|
37
|
+
proxy = self._proxy_builder(self.value)
|
|
38
|
+
instance.__dict__[self.name] = proxy
|
|
39
|
+
else:
|
|
40
|
+
proxy = self._proxy_rebuilder(proxy) if self._proxy_rebuilder else proxy
|
|
41
|
+
proxy._ref.value # type: ignore
|
|
42
|
+
return proxy
|
|
43
|
+
|
|
44
|
+
def __set__(self, instance: object, value: T) -> None:
|
|
45
|
+
value = to_value_if_base_type_proxy(value)
|
|
46
|
+
proxy = instance.__dict__.get(self.name, None)
|
|
47
|
+
if proxy is None:
|
|
48
|
+
proxy = self._proxy_builder(value) # type: ignore
|
|
49
|
+
instance.__dict__[self.name] = proxy
|
|
50
|
+
|
|
51
|
+
proxy._ref.value = value # type: ignore
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class IntDescriptor(ProxyDescriptor[int]):
|
|
55
|
+
def __init__(self, name: str, value: int) -> None:
|
|
56
|
+
super().__init__(name, value, IntProxy)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ListDescriptor(ProxyDescriptor[Callable[[], List]]):
|
|
60
|
+
def __init__(self, name: str, value: Callable[[], List]) -> None:
|
|
61
|
+
super().__init__(name, value, lambda x: ListProxy(x() if callable(x) else x))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class DictDescriptor(ProxyDescriptor[Dict]):
|
|
65
|
+
def __init__(self, name: str, value: Dict) -> None:
|
|
66
|
+
super().__init__(name, value, DictProxy)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class StringDescriptor(ProxyDescriptor[str]):
|
|
70
|
+
def __init__(self, name: str, value: str) -> None:
|
|
71
|
+
def rebuild_proxy(proxy: ProxyProtocol) -> ProxyProtocol:
|
|
72
|
+
sp = StringProxy(proxy._ref.value)
|
|
73
|
+
sp._ref = proxy._ref
|
|
74
|
+
return sp
|
|
75
|
+
|
|
76
|
+
super().__init__(name, value, StringProxy, rebuild_proxy)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FloatDescriptor(ProxyDescriptor[float]):
|
|
80
|
+
def __init__(self, name: str, value: float) -> None:
|
|
81
|
+
super().__init__(name, value, FloatProxy)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class BoolDescriptor(ProxyDescriptor[bool]):
|
|
85
|
+
def __init__(self, name: str, value: bool) -> None:
|
|
86
|
+
super().__init__(name, value, BoolProxy)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class DateDescriptor(ProxyDescriptor[datetime.date]):
|
|
90
|
+
def __init__(self, name: str, value: datetime.date) -> None:
|
|
91
|
+
super().__init__(name, value, lambda x: DateProxy(x.year, x.month, x.day))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def class_var_setter(cls: Type, name: str, value, list_var_flat: str) -> None:
|
|
95
|
+
if value is None or isinstance(value, str):
|
|
96
|
+
setattr(cls, name, StringDescriptor(name, value))
|
|
97
|
+
elif isinstance(value, bool):
|
|
98
|
+
setattr(cls, name, BoolDescriptor(name, value))
|
|
99
|
+
elif isinstance(value, int):
|
|
100
|
+
setattr(cls, name, IntDescriptor(name, value))
|
|
101
|
+
elif callable(value) and hasattr(value, list_var_flat):
|
|
102
|
+
setattr(cls, name, ListDescriptor(name, value))
|
|
103
|
+
|
|
104
|
+
elif isinstance(value, list):
|
|
105
|
+
if len(value) > 0:
|
|
106
|
+
with warnings.catch_warnings():
|
|
107
|
+
warnings.showwarning = _custom_showwarning
|
|
108
|
+
warnings.warn(
|
|
109
|
+
f"The variable [{cls.__name__}.{name}] will be empty list.you should initialize it in the constructor,or use list_var for definition.\n {name} = rxui.list_var(lambda:[1,2,3])",
|
|
110
|
+
stacklevel=3,
|
|
111
|
+
)
|
|
112
|
+
setattr(cls, name, ListDescriptor(name, lambda: []))
|
|
113
|
+
|
|
114
|
+
elif isinstance(value, dict):
|
|
115
|
+
pass # TODO
|
|
116
|
+
# setattr(cls, name, DictDescriptor(name, value))
|
|
117
|
+
elif isinstance(value, float):
|
|
118
|
+
setattr(cls, name, FloatDescriptor(name, value))
|
|
119
|
+
elif isinstance(value, datetime.date):
|
|
120
|
+
setattr(cls, name, DateDescriptor(name, value))
|
|
121
|
+
else:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _custom_showwarning(message, category, filename, lineno, file=None, line=None):
|
|
126
|
+
sys.stderr.write(f"{filename}:{lineno}: {category.__name__}: {message}\n")
|