reflex 0.8.12a1__py3-none-any.whl → 0.8.13a1__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.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/utils/state.js +48 -17
- reflex/app.py +17 -12
- reflex/app_mixins/lifespan.py +11 -0
- reflex/compiler/compiler.py +4 -1
- reflex/components/core/upload.py +53 -14
- reflex/components/core/upload.pyi +8 -0
- reflex/components/react_player/react_player.py +159 -19
- reflex/components/recharts/recharts.py +2 -2
- reflex/constants/colors.py +3 -1
- reflex/constants/installer.py +2 -2
- reflex/environment.py +3 -0
- reflex/istate/proxy.py +36 -36
- reflex/plugins/shared_tailwind.py +1 -1
- reflex/reflex.py +54 -3
- reflex/state.py +15 -5
- reflex/testing.py +14 -0
- reflex/utils/build.py +77 -57
- reflex/utils/exec.py +12 -0
- reflex/utils/export.py +7 -2
- reflex/utils/prerequisites.py +82 -7
- reflex/utils/serializers.py +8 -4
- reflex/utils/token_manager.py +10 -0
- reflex/utils/types.py +2 -0
- reflex/vars/__init__.py +56 -26
- reflex/vars/base.py +20 -113
- reflex/vars/color.py +214 -0
- reflex/vars/number.py +2 -2
- reflex/vars/sequence.py +0 -136
- {reflex-0.8.12a1.dist-info → reflex-0.8.13a1.dist-info}/METADATA +1 -1
- {reflex-0.8.12a1.dist-info → reflex-0.8.13a1.dist-info}/RECORD +33 -32
- {reflex-0.8.12a1.dist-info → reflex-0.8.13a1.dist-info}/WHEEL +0 -0
- {reflex-0.8.12a1.dist-info → reflex-0.8.13a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.12a1.dist-info → reflex-0.8.13a1.dist-info}/licenses/LICENSE +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -269,25 +269,100 @@ def get_compiled_app(
|
|
|
269
269
|
return app_module
|
|
270
270
|
|
|
271
271
|
|
|
272
|
+
def _can_colorize() -> bool:
|
|
273
|
+
"""Check if the output can be colorized.
|
|
274
|
+
|
|
275
|
+
Copied from _colorize.can_colorize.
|
|
276
|
+
|
|
277
|
+
https://raw.githubusercontent.com/python/cpython/refs/heads/main/Lib/_colorize.py
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
If the output can be colorized
|
|
281
|
+
"""
|
|
282
|
+
import io
|
|
283
|
+
import os
|
|
284
|
+
|
|
285
|
+
def _safe_getenv(k: str, fallback: str | None = None) -> str | None:
|
|
286
|
+
"""Exception-safe environment retrieval. See gh-128636.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
k: The environment variable key.
|
|
290
|
+
fallback: The fallback value if the environment variable is not set.
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
The value of the environment variable or the fallback value.
|
|
294
|
+
"""
|
|
295
|
+
try:
|
|
296
|
+
return os.environ.get(k, fallback)
|
|
297
|
+
except Exception:
|
|
298
|
+
return fallback
|
|
299
|
+
|
|
300
|
+
file = sys.stdout
|
|
301
|
+
|
|
302
|
+
if not sys.flags.ignore_environment:
|
|
303
|
+
if _safe_getenv("PYTHON_COLORS") == "0":
|
|
304
|
+
return False
|
|
305
|
+
if _safe_getenv("PYTHON_COLORS") == "1":
|
|
306
|
+
return True
|
|
307
|
+
if _safe_getenv("NO_COLOR"):
|
|
308
|
+
return False
|
|
309
|
+
if _safe_getenv("FORCE_COLOR"):
|
|
310
|
+
return True
|
|
311
|
+
if _safe_getenv("TERM") == "dumb":
|
|
312
|
+
return False
|
|
313
|
+
|
|
314
|
+
if not hasattr(file, "fileno"):
|
|
315
|
+
return False
|
|
316
|
+
|
|
317
|
+
if sys.platform == "win32":
|
|
318
|
+
try:
|
|
319
|
+
import nt
|
|
320
|
+
|
|
321
|
+
if not nt._supports_virtual_terminal():
|
|
322
|
+
return False
|
|
323
|
+
except (ImportError, AttributeError):
|
|
324
|
+
return False
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
return os.isatty(file.fileno())
|
|
328
|
+
except io.UnsupportedOperation:
|
|
329
|
+
return hasattr(file, "isatty") and file.isatty()
|
|
330
|
+
|
|
331
|
+
|
|
272
332
|
def compile_or_validate_app(
|
|
273
333
|
compile: bool = False,
|
|
274
334
|
check_if_schema_up_to_date: bool = False,
|
|
275
335
|
prerender_routes: bool = False,
|
|
276
|
-
):
|
|
336
|
+
) -> bool:
|
|
277
337
|
"""Compile or validate the app module based on the default config.
|
|
278
338
|
|
|
279
339
|
Args:
|
|
280
340
|
compile: Whether to compile the app.
|
|
281
341
|
check_if_schema_up_to_date: If True, check if the schema is up to date.
|
|
282
342
|
prerender_routes: Whether to prerender routes.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
True if the app was successfully compiled or validated, False otherwise.
|
|
283
346
|
"""
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
347
|
+
try:
|
|
348
|
+
if compile:
|
|
349
|
+
get_compiled_app(
|
|
350
|
+
check_if_schema_up_to_date=check_if_schema_up_to_date,
|
|
351
|
+
prerender_routes=prerender_routes,
|
|
352
|
+
)
|
|
353
|
+
else:
|
|
354
|
+
get_and_validate_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
|
|
355
|
+
except Exception as e:
|
|
356
|
+
import traceback
|
|
357
|
+
|
|
358
|
+
try:
|
|
359
|
+
colorize = _can_colorize()
|
|
360
|
+
traceback.print_exception(e, colorize=colorize) # pyright: ignore[reportCallIssue]
|
|
361
|
+
except Exception:
|
|
362
|
+
traceback.print_exception(e)
|
|
363
|
+
return False
|
|
289
364
|
else:
|
|
290
|
-
|
|
365
|
+
return True
|
|
291
366
|
|
|
292
367
|
|
|
293
368
|
def get_redis() -> Redis | None:
|
reflex/utils/serializers.py
CHANGED
|
@@ -20,7 +20,7 @@ from pydantic import BaseModel as BaseModelV2
|
|
|
20
20
|
from pydantic.v1 import BaseModel as BaseModelV1
|
|
21
21
|
|
|
22
22
|
from reflex.base import Base
|
|
23
|
-
from reflex.constants.colors import Color
|
|
23
|
+
from reflex.constants.colors import Color
|
|
24
24
|
from reflex.utils import console, types
|
|
25
25
|
|
|
26
26
|
# Mapping from type to a serializer.
|
|
@@ -413,8 +413,8 @@ def serialize_decimal(value: decimal.Decimal) -> float:
|
|
|
413
413
|
return float(value)
|
|
414
414
|
|
|
415
415
|
|
|
416
|
-
@serializer(to=
|
|
417
|
-
def serialize_color(color: Color) ->
|
|
416
|
+
@serializer(to=dict)
|
|
417
|
+
def serialize_color(color: Color) -> dict:
|
|
418
418
|
"""Serialize a color.
|
|
419
419
|
|
|
420
420
|
Args:
|
|
@@ -423,7 +423,11 @@ def serialize_color(color: Color) -> str:
|
|
|
423
423
|
Returns:
|
|
424
424
|
The serialized color.
|
|
425
425
|
"""
|
|
426
|
-
return
|
|
426
|
+
return {
|
|
427
|
+
"color": color.color,
|
|
428
|
+
"shade": color.shade,
|
|
429
|
+
"alpha": color.alpha,
|
|
430
|
+
}
|
|
427
431
|
|
|
428
432
|
|
|
429
433
|
with contextlib.suppress(ImportError):
|
reflex/utils/token_manager.py
CHANGED
|
@@ -66,6 +66,16 @@ class TokenManager(ABC):
|
|
|
66
66
|
|
|
67
67
|
return LocalTokenManager()
|
|
68
68
|
|
|
69
|
+
async def disconnect_all(self):
|
|
70
|
+
"""Disconnect all tracked tokens when the server is going down."""
|
|
71
|
+
token_sid_pairs: set[tuple[str, str]] = set(self.token_to_sid.items())
|
|
72
|
+
token_sid_pairs.update(
|
|
73
|
+
((token, sid) for sid, token in self.sid_to_token.items())
|
|
74
|
+
)
|
|
75
|
+
# Perform the disconnection logic here
|
|
76
|
+
for token, sid in token_sid_pairs:
|
|
77
|
+
await self.disconnect_token(token, sid)
|
|
78
|
+
|
|
69
79
|
|
|
70
80
|
class LocalTokenManager(TokenManager):
|
|
71
81
|
"""Token manager using local in-memory dictionaries (single worker)."""
|
reflex/utils/types.py
CHANGED
|
@@ -6,6 +6,7 @@ import dataclasses
|
|
|
6
6
|
import sys
|
|
7
7
|
import types
|
|
8
8
|
from collections.abc import Callable, Iterable, Mapping, Sequence
|
|
9
|
+
from enum import Enum
|
|
9
10
|
from functools import cached_property, lru_cache
|
|
10
11
|
from types import GenericAlias
|
|
11
12
|
from typing import ( # noqa: UP035
|
|
@@ -1241,6 +1242,7 @@ IMMUTABLE_TYPES = (
|
|
|
1241
1242
|
frozenset,
|
|
1242
1243
|
tuple,
|
|
1243
1244
|
type(None),
|
|
1245
|
+
Enum,
|
|
1244
1246
|
)
|
|
1245
1247
|
|
|
1246
1248
|
|
reflex/vars/__init__.py
CHANGED
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
"""Immutable-Based Var System."""
|
|
2
2
|
|
|
3
|
-
from .base import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
19
|
-
from .number import LiteralBooleanVar
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
3
|
+
from .base import (
|
|
4
|
+
BaseStateMeta,
|
|
5
|
+
EvenMoreBasicBaseState,
|
|
6
|
+
Field,
|
|
7
|
+
LiteralVar,
|
|
8
|
+
Var,
|
|
9
|
+
VarData,
|
|
10
|
+
field,
|
|
11
|
+
get_unique_variable_name,
|
|
12
|
+
get_uuid_string_var,
|
|
13
|
+
var_operation,
|
|
14
|
+
var_operation_return,
|
|
15
|
+
)
|
|
16
|
+
from .color import ColorVar, LiteralColorVar
|
|
17
|
+
from .datetime import DateTimeVar
|
|
18
|
+
from .function import FunctionStringVar, FunctionVar, VarOperationCall
|
|
19
|
+
from .number import BooleanVar, LiteralBooleanVar, LiteralNumberVar, NumberVar
|
|
20
|
+
from .object import LiteralObjectVar, ObjectVar
|
|
21
|
+
from .sequence import (
|
|
22
|
+
ArrayVar,
|
|
23
|
+
ConcatVarOperation,
|
|
24
|
+
LiteralArrayVar,
|
|
25
|
+
LiteralStringVar,
|
|
26
|
+
StringVar,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"ArrayVar",
|
|
31
|
+
"BaseStateMeta",
|
|
32
|
+
"BooleanVar",
|
|
33
|
+
"ColorVar",
|
|
34
|
+
"ConcatVarOperation",
|
|
35
|
+
"DateTimeVar",
|
|
36
|
+
"EvenMoreBasicBaseState",
|
|
37
|
+
"Field",
|
|
38
|
+
"FunctionStringVar",
|
|
39
|
+
"FunctionVar",
|
|
40
|
+
"LiteralArrayVar",
|
|
41
|
+
"LiteralBooleanVar",
|
|
42
|
+
"LiteralColorVar",
|
|
43
|
+
"LiteralNumberVar",
|
|
44
|
+
"LiteralObjectVar",
|
|
45
|
+
"LiteralStringVar",
|
|
46
|
+
"LiteralVar",
|
|
47
|
+
"NumberVar",
|
|
48
|
+
"ObjectVar",
|
|
49
|
+
"StringVar",
|
|
50
|
+
"Var",
|
|
51
|
+
"VarData",
|
|
52
|
+
"VarOperationCall",
|
|
53
|
+
"field",
|
|
54
|
+
"get_unique_variable_name",
|
|
55
|
+
"get_uuid_string_var",
|
|
56
|
+
"var_operation",
|
|
57
|
+
"var_operation_return",
|
|
58
|
+
]
|
reflex/vars/base.py
CHANGED
|
@@ -18,21 +18,16 @@ from collections.abc import Callable, Coroutine, Iterable, Mapping, Sequence
|
|
|
18
18
|
from dataclasses import _MISSING_TYPE, MISSING
|
|
19
19
|
from decimal import Decimal
|
|
20
20
|
from types import CodeType, FunctionType
|
|
21
|
-
from typing import (
|
|
21
|
+
from typing import (
|
|
22
22
|
TYPE_CHECKING,
|
|
23
23
|
Annotated,
|
|
24
24
|
Any,
|
|
25
25
|
ClassVar,
|
|
26
|
-
Dict,
|
|
27
|
-
FrozenSet,
|
|
28
26
|
Generic,
|
|
29
|
-
List,
|
|
30
27
|
Literal,
|
|
31
28
|
NoReturn,
|
|
32
29
|
ParamSpec,
|
|
33
30
|
Protocol,
|
|
34
|
-
Set,
|
|
35
|
-
Tuple,
|
|
36
31
|
TypeGuard,
|
|
37
32
|
TypeVar,
|
|
38
33
|
cast,
|
|
@@ -78,8 +73,10 @@ from reflex.utils.types import (
|
|
|
78
73
|
|
|
79
74
|
if TYPE_CHECKING:
|
|
80
75
|
from reflex.components.component import BaseComponent
|
|
76
|
+
from reflex.constants.colors import Color
|
|
81
77
|
from reflex.state import BaseState
|
|
82
78
|
|
|
79
|
+
from .color import LiteralColorVar
|
|
83
80
|
from .number import BooleanVar, LiteralBooleanVar, LiteralNumberVar, NumberVar
|
|
84
81
|
from .object import LiteralObjectVar, ObjectVar
|
|
85
82
|
from .sequence import ArrayVar, LiteralArrayVar, LiteralStringVar, StringVar
|
|
@@ -642,6 +639,14 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
|
|
|
642
639
|
_var_data: VarData | None = None,
|
|
643
640
|
) -> LiteralNumberVar[Decimal]: ...
|
|
644
641
|
|
|
642
|
+
@overload
|
|
643
|
+
@classmethod
|
|
644
|
+
def create( # pyright: ignore [reportOverlappingOverload]
|
|
645
|
+
cls,
|
|
646
|
+
value: Color,
|
|
647
|
+
_var_data: VarData | None = None,
|
|
648
|
+
) -> LiteralColorVar: ...
|
|
649
|
+
|
|
645
650
|
@overload
|
|
646
651
|
@classmethod
|
|
647
652
|
def create( # pyright: ignore [reportOverlappingOverload]
|
|
@@ -3080,7 +3085,8 @@ def transform(fn: Callable[[Var], Var]) -> Callable[[Var], Var]:
|
|
|
3080
3085
|
TypeError: If the Var return type does not have a generic type.
|
|
3081
3086
|
ValueError: If a function for the generic type is already registered.
|
|
3082
3087
|
"""
|
|
3083
|
-
|
|
3088
|
+
types = get_type_hints(fn)
|
|
3089
|
+
return_type = types["return"]
|
|
3084
3090
|
|
|
3085
3091
|
origin = get_origin(return_type)
|
|
3086
3092
|
|
|
@@ -3105,101 +3111,6 @@ def transform(fn: Callable[[Var], Var]) -> Callable[[Var], Var]:
|
|
|
3105
3111
|
return fn
|
|
3106
3112
|
|
|
3107
3113
|
|
|
3108
|
-
def generic_type_to_actual_type_map(
|
|
3109
|
-
generic_type: GenericType, actual_type: GenericType
|
|
3110
|
-
) -> dict[TypeVar, GenericType]:
|
|
3111
|
-
"""Map the generic type to the actual type.
|
|
3112
|
-
|
|
3113
|
-
Args:
|
|
3114
|
-
generic_type: The generic type.
|
|
3115
|
-
actual_type: The actual type.
|
|
3116
|
-
|
|
3117
|
-
Returns:
|
|
3118
|
-
The mapping of type variables to actual types.
|
|
3119
|
-
|
|
3120
|
-
Raises:
|
|
3121
|
-
TypeError: If the generic type and actual type do not match.
|
|
3122
|
-
TypeError: If the number of generic arguments and actual arguments do not match.
|
|
3123
|
-
"""
|
|
3124
|
-
generic_origin = get_origin(generic_type) or generic_type
|
|
3125
|
-
actual_origin = get_origin(actual_type) or actual_type
|
|
3126
|
-
|
|
3127
|
-
if generic_origin is not actual_origin:
|
|
3128
|
-
if isinstance(generic_origin, TypeVar):
|
|
3129
|
-
return {generic_origin: actual_origin}
|
|
3130
|
-
msg = f"Type mismatch: expected {generic_origin}, got {actual_origin}."
|
|
3131
|
-
raise TypeError(msg)
|
|
3132
|
-
|
|
3133
|
-
generic_args = get_args(generic_type)
|
|
3134
|
-
actual_args = get_args(actual_type)
|
|
3135
|
-
|
|
3136
|
-
if len(generic_args) != len(actual_args):
|
|
3137
|
-
msg = f"Number of generic arguments mismatch: expected {len(generic_args)}, got {len(actual_args)}."
|
|
3138
|
-
raise TypeError(msg)
|
|
3139
|
-
|
|
3140
|
-
# call recursively for nested generic types and merge the results
|
|
3141
|
-
return {
|
|
3142
|
-
k: v
|
|
3143
|
-
for generic_arg, actual_arg in zip(generic_args, actual_args, strict=True)
|
|
3144
|
-
for k, v in generic_type_to_actual_type_map(generic_arg, actual_arg).items()
|
|
3145
|
-
}
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
def resolve_generic_type_with_mapping(
|
|
3149
|
-
generic_type: GenericType, type_mapping: dict[TypeVar, GenericType]
|
|
3150
|
-
):
|
|
3151
|
-
"""Resolve a generic type with a type mapping.
|
|
3152
|
-
|
|
3153
|
-
Args:
|
|
3154
|
-
generic_type: The generic type.
|
|
3155
|
-
type_mapping: The type mapping.
|
|
3156
|
-
|
|
3157
|
-
Returns:
|
|
3158
|
-
The resolved generic type.
|
|
3159
|
-
"""
|
|
3160
|
-
if isinstance(generic_type, TypeVar):
|
|
3161
|
-
return type_mapping.get(generic_type, generic_type)
|
|
3162
|
-
|
|
3163
|
-
generic_origin = get_origin(generic_type) or generic_type
|
|
3164
|
-
|
|
3165
|
-
generic_args = get_args(generic_type)
|
|
3166
|
-
|
|
3167
|
-
if not generic_args:
|
|
3168
|
-
return generic_type
|
|
3169
|
-
|
|
3170
|
-
mapping_for_older_python = {
|
|
3171
|
-
list: List, # noqa: UP006
|
|
3172
|
-
set: Set, # noqa: UP006
|
|
3173
|
-
dict: Dict, # noqa: UP006
|
|
3174
|
-
tuple: Tuple, # noqa: UP006
|
|
3175
|
-
frozenset: FrozenSet, # noqa: UP006
|
|
3176
|
-
}
|
|
3177
|
-
|
|
3178
|
-
return mapping_for_older_python.get(generic_origin, generic_origin)[
|
|
3179
|
-
tuple(
|
|
3180
|
-
resolve_generic_type_with_mapping(arg, type_mapping) for arg in generic_args
|
|
3181
|
-
)
|
|
3182
|
-
]
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
def resolve_arg_type_from_return_type(
|
|
3186
|
-
arg_type: GenericType, return_type: GenericType, actual_return_type: GenericType
|
|
3187
|
-
) -> GenericType:
|
|
3188
|
-
"""Resolve the argument type from the return type.
|
|
3189
|
-
|
|
3190
|
-
Args:
|
|
3191
|
-
arg_type: The argument type.
|
|
3192
|
-
return_type: The return type.
|
|
3193
|
-
actual_return_type: The requested return type.
|
|
3194
|
-
|
|
3195
|
-
Returns:
|
|
3196
|
-
The argument type without the generics that are resolved.
|
|
3197
|
-
"""
|
|
3198
|
-
return resolve_generic_type_with_mapping(
|
|
3199
|
-
arg_type, generic_type_to_actual_type_map(return_type, actual_return_type)
|
|
3200
|
-
)
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
3114
|
def dispatch(
|
|
3204
3115
|
field_name: str,
|
|
3205
3116
|
var_data: VarData,
|
|
@@ -3227,11 +3138,12 @@ def dispatch(
|
|
|
3227
3138
|
|
|
3228
3139
|
if result_origin_var_type in dispatchers:
|
|
3229
3140
|
fn = dispatchers[result_origin_var_type]
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3141
|
+
fn_types = get_type_hints(fn)
|
|
3142
|
+
fn_first_arg_type = fn_types.get(
|
|
3143
|
+
next(iter(inspect.signature(fn).parameters.values())).name, Any
|
|
3144
|
+
)
|
|
3233
3145
|
|
|
3234
|
-
fn_return =
|
|
3146
|
+
fn_return = fn_types.get("return", Any)
|
|
3235
3147
|
|
|
3236
3148
|
fn_return_origin = get_origin(fn_return) or fn_return
|
|
3237
3149
|
|
|
@@ -3257,22 +3169,17 @@ def dispatch(
|
|
|
3257
3169
|
msg = f"Expected generic type of {fn_first_arg_type} to be a type."
|
|
3258
3170
|
raise TypeError(msg)
|
|
3259
3171
|
|
|
3260
|
-
arg_type = arg_generic_args[0]
|
|
3261
3172
|
fn_return_type = fn_return_generic_args[0]
|
|
3262
3173
|
|
|
3263
3174
|
var = (
|
|
3264
3175
|
Var(
|
|
3265
3176
|
field_name,
|
|
3266
3177
|
_var_data=var_data,
|
|
3267
|
-
_var_type=
|
|
3268
|
-
arg_type, fn_return_type, result_var_type
|
|
3269
|
-
),
|
|
3178
|
+
_var_type=fn_return_type,
|
|
3270
3179
|
).guess_type()
|
|
3271
3180
|
if existing_var is None
|
|
3272
3181
|
else existing_var._replace(
|
|
3273
|
-
_var_type=
|
|
3274
|
-
arg_type, fn_return_type, result_var_type
|
|
3275
|
-
),
|
|
3182
|
+
_var_type=fn_return_type,
|
|
3276
3183
|
_var_data=var_data,
|
|
3277
3184
|
_js_expr=field_name,
|
|
3278
3185
|
).guess_type()
|
reflex/vars/color.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Vars for colors."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
|
|
5
|
+
from reflex.constants.colors import Color
|
|
6
|
+
from reflex.vars.base import (
|
|
7
|
+
CachedVarOperation,
|
|
8
|
+
LiteralVar,
|
|
9
|
+
Var,
|
|
10
|
+
VarData,
|
|
11
|
+
cached_property_no_lock,
|
|
12
|
+
get_python_literal,
|
|
13
|
+
transform,
|
|
14
|
+
)
|
|
15
|
+
from reflex.vars.number import BooleanVar, NumberVar, ternary_operation
|
|
16
|
+
from reflex.vars.object import LiteralObjectVar
|
|
17
|
+
from reflex.vars.sequence import ConcatVarOperation, LiteralStringVar, StringVar
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@transform
|
|
21
|
+
def evaluate_color(js_dict: Var[dict]) -> Var[Color]:
|
|
22
|
+
"""Evaluate a color var.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
js_dict: The color var as a dict.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
The color var as a string.
|
|
29
|
+
"""
|
|
30
|
+
js_color_dict = js_dict.to(dict)
|
|
31
|
+
str_part = ConcatVarOperation.create(
|
|
32
|
+
LiteralStringVar.create("var(--"),
|
|
33
|
+
js_color_dict.color,
|
|
34
|
+
LiteralStringVar.create("-"),
|
|
35
|
+
ternary_operation(
|
|
36
|
+
js_color_dict.alpha,
|
|
37
|
+
LiteralStringVar.create("a"),
|
|
38
|
+
LiteralStringVar.create(""),
|
|
39
|
+
),
|
|
40
|
+
js_color_dict.shade.to_string(use_json=False),
|
|
41
|
+
LiteralStringVar.create(")"),
|
|
42
|
+
)
|
|
43
|
+
return js_dict._replace(
|
|
44
|
+
_js_expr=f"Object.assign(new String({str_part!s}), {js_dict!s})",
|
|
45
|
+
_var_type=Color,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ColorVar(StringVar[Color], python_types=Color):
|
|
50
|
+
"""Base class for immutable color vars."""
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def color(self) -> StringVar:
|
|
54
|
+
"""Get the color of the color var.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The color of the color var.
|
|
58
|
+
"""
|
|
59
|
+
return self.to(dict).color.to(str)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def alpha(self) -> BooleanVar:
|
|
63
|
+
"""Get the alpha of the color var.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
The alpha of the color var.
|
|
67
|
+
"""
|
|
68
|
+
return self.to(dict).alpha.to(bool)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def shade(self) -> NumberVar:
|
|
72
|
+
"""Get the shade of the color var.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The shade of the color var.
|
|
76
|
+
"""
|
|
77
|
+
return self.to(dict).shade.to(int)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclasses.dataclass(
|
|
81
|
+
eq=False,
|
|
82
|
+
frozen=True,
|
|
83
|
+
slots=True,
|
|
84
|
+
)
|
|
85
|
+
class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
|
|
86
|
+
"""Base class for immutable literal color vars."""
|
|
87
|
+
|
|
88
|
+
_var_value: Color = dataclasses.field(default_factory=lambda: Color(color="black"))
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def create(
|
|
92
|
+
cls,
|
|
93
|
+
value: Color,
|
|
94
|
+
_var_type: type[Color] | None = None,
|
|
95
|
+
_var_data: VarData | None = None,
|
|
96
|
+
) -> ColorVar:
|
|
97
|
+
"""Create a var from a string value.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
value: The value to create the var from.
|
|
101
|
+
_var_type: The type of the var.
|
|
102
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The var.
|
|
106
|
+
"""
|
|
107
|
+
return cls(
|
|
108
|
+
_js_expr="",
|
|
109
|
+
_var_type=_var_type or Color,
|
|
110
|
+
_var_data=_var_data,
|
|
111
|
+
_var_value=value,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def __hash__(self) -> int:
|
|
115
|
+
"""Get the hash of the var.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The hash of the var.
|
|
119
|
+
"""
|
|
120
|
+
return hash(
|
|
121
|
+
(
|
|
122
|
+
self.__class__.__name__,
|
|
123
|
+
self._var_value.color,
|
|
124
|
+
self._var_value.alpha,
|
|
125
|
+
self._var_value.shade,
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@cached_property_no_lock
|
|
130
|
+
def _cached_var_name(self) -> str:
|
|
131
|
+
"""The name of the var.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
The name of the var.
|
|
135
|
+
"""
|
|
136
|
+
alpha = self._var_value.alpha
|
|
137
|
+
alpha = (
|
|
138
|
+
ternary_operation(
|
|
139
|
+
alpha,
|
|
140
|
+
LiteralStringVar.create("a"),
|
|
141
|
+
LiteralStringVar.create(""),
|
|
142
|
+
)
|
|
143
|
+
if isinstance(alpha, Var)
|
|
144
|
+
else LiteralStringVar.create("a" if alpha else "")
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
shade = self._var_value.shade
|
|
148
|
+
shade = (
|
|
149
|
+
shade.to_string(use_json=False)
|
|
150
|
+
if isinstance(shade, Var)
|
|
151
|
+
else LiteralStringVar.create(str(shade))
|
|
152
|
+
)
|
|
153
|
+
string_part = str(
|
|
154
|
+
ConcatVarOperation.create(
|
|
155
|
+
LiteralStringVar.create("var(--"),
|
|
156
|
+
self._var_value.color,
|
|
157
|
+
LiteralStringVar.create("-"),
|
|
158
|
+
alpha,
|
|
159
|
+
shade,
|
|
160
|
+
LiteralStringVar.create(")"),
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
dict_part = LiteralObjectVar.create(
|
|
164
|
+
{
|
|
165
|
+
"color": self._var_value.color,
|
|
166
|
+
"alpha": self._var_value.alpha,
|
|
167
|
+
"shade": self._var_value.shade,
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
return f"Object.assign(new String({string_part!s}), {dict_part!s})"
|
|
171
|
+
|
|
172
|
+
@cached_property_no_lock
|
|
173
|
+
def _cached_get_all_var_data(self) -> VarData | None:
|
|
174
|
+
"""Get all the var data.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
The var data.
|
|
178
|
+
"""
|
|
179
|
+
return VarData.merge(
|
|
180
|
+
*[
|
|
181
|
+
LiteralVar.create(var)._get_all_var_data()
|
|
182
|
+
for var in (
|
|
183
|
+
self._var_value.color,
|
|
184
|
+
self._var_value.alpha,
|
|
185
|
+
self._var_value.shade,
|
|
186
|
+
)
|
|
187
|
+
],
|
|
188
|
+
self._var_data,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def json(self) -> str:
|
|
192
|
+
"""Get the JSON representation of the var.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
The JSON representation of the var.
|
|
196
|
+
|
|
197
|
+
Raises:
|
|
198
|
+
TypeError: If the color is not a valid color.
|
|
199
|
+
"""
|
|
200
|
+
color, alpha, shade = map(
|
|
201
|
+
get_python_literal,
|
|
202
|
+
(self._var_value.color, self._var_value.alpha, self._var_value.shade),
|
|
203
|
+
)
|
|
204
|
+
if color is None or alpha is None or shade is None:
|
|
205
|
+
msg = "Cannot serialize color that contains non-literal vars."
|
|
206
|
+
raise TypeError(msg)
|
|
207
|
+
if (
|
|
208
|
+
not isinstance(color, str)
|
|
209
|
+
or not isinstance(alpha, bool)
|
|
210
|
+
or not isinstance(shade, int)
|
|
211
|
+
):
|
|
212
|
+
msg = "Color is not a valid color."
|
|
213
|
+
raise TypeError(msg)
|
|
214
|
+
return f"var(--{color}-{'a' if alpha else ''}{shade})"
|
reflex/vars/number.py
CHANGED
|
@@ -909,7 +909,7 @@ def equal_operation(lhs: Var, rhs: Var):
|
|
|
909
909
|
Returns:
|
|
910
910
|
The result of the comparison.
|
|
911
911
|
"""
|
|
912
|
-
return f"({lhs} === {rhs})"
|
|
912
|
+
return f"({lhs}?.valueOf?.() === {rhs}?.valueOf?.())"
|
|
913
913
|
|
|
914
914
|
|
|
915
915
|
@comparison_operator
|
|
@@ -923,7 +923,7 @@ def not_equal_operation(lhs: Var, rhs: Var):
|
|
|
923
923
|
Returns:
|
|
924
924
|
The result of the comparison.
|
|
925
925
|
"""
|
|
926
|
-
return f"({lhs} !== {rhs})"
|
|
926
|
+
return f"({lhs}?.valueOf?.() !== {rhs}?.valueOf?.())"
|
|
927
927
|
|
|
928
928
|
|
|
929
929
|
@var_operation
|