reflex 0.8.8a2__py3-none-any.whl → 0.8.9a1__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/istate/data.py CHANGED
@@ -83,6 +83,11 @@ class HeaderData(_HeaderData):
83
83
  )
84
84
 
85
85
 
86
+ @serializer(to=dict)
87
+ def _serialize_header_data(obj: HeaderData) -> dict:
88
+ return {k.name: getattr(obj, k.name) for k in dataclasses.fields(obj)}
89
+
90
+
86
91
  @serializer(to=dict)
87
92
  def serialize_frozen_dict_str_str(obj: _FrozenDictStrStr) -> dict:
88
93
  """Serialize a _FrozenDictStrStr object to a dict.
@@ -165,6 +170,11 @@ class PageData:
165
170
  )
166
171
 
167
172
 
173
+ @serializer(to=dict)
174
+ def _serialize_page_data(obj: PageData) -> dict:
175
+ return dataclasses.asdict(obj)
176
+
177
+
168
178
  @dataclasses.dataclass(frozen=True)
169
179
  class SessionData:
170
180
  """An object containing session data."""
@@ -190,6 +200,11 @@ class SessionData:
190
200
  )
191
201
 
192
202
 
203
+ @serializer(to=dict)
204
+ def _serialize_session_data(obj: SessionData) -> dict:
205
+ return dataclasses.asdict(obj)
206
+
207
+
193
208
  @dataclasses.dataclass(frozen=True)
194
209
  class RouterData:
195
210
  """An object containing RouterData."""
reflex/plugins/sitemap.py CHANGED
@@ -5,8 +5,7 @@ from collections.abc import Sequence
5
5
  from pathlib import Path
6
6
  from types import SimpleNamespace
7
7
  from typing import TYPE_CHECKING, Literal, TypedDict
8
- from xml.dom import minidom
9
- from xml.etree.ElementTree import Element, SubElement, tostring
8
+ from xml.etree.ElementTree import Element, SubElement, indent, tostring
10
9
 
11
10
  from typing_extensions import NotRequired
12
11
 
@@ -104,10 +103,8 @@ def generate_xml(links: Sequence[SitemapLink]) -> str:
104
103
  if (priority := link.get("priority")) is not None:
105
104
  priority_element = SubElement(url, "priority")
106
105
  priority_element.text = str(priority)
107
-
108
- rough_string = tostring(urlset, "utf-8")
109
- reparsed = minidom.parseString(rough_string)
110
- return reparsed.toprettyxml(indent=" ")
106
+ indent(urlset, " ")
107
+ return tostring(urlset, encoding="utf-8", xml_declaration=True).decode("utf-8")
111
108
 
112
109
 
113
110
  def is_route_dynamic(route: str) -> bool:
reflex/reflex.py CHANGED
@@ -360,7 +360,13 @@ def run(
360
360
  default=False,
361
361
  help="Run the command without making any changes.",
362
362
  )
363
- def compile(dry: bool):
363
+ @click.option(
364
+ "--rich/--no-rich",
365
+ default=True,
366
+ is_flag=True,
367
+ help="Whether to use rich progress bars.",
368
+ )
369
+ def compile(dry: bool, rich: bool):
364
370
  """Compile the app in the current directory."""
365
371
  import time
366
372
 
@@ -371,7 +377,7 @@ def compile(dry: bool):
371
377
  _init(name=get_config().app_name)
372
378
  get_config(reload=True)
373
379
  starting_time = time.monotonic()
374
- prerequisites.get_compiled_app(dry_run=dry)
380
+ prerequisites.get_compiled_app(dry_run=dry, use_rich=rich)
375
381
  elapsed_time = time.monotonic() - starting_time
376
382
  console.success(f"App compiled successfully in {elapsed_time:.3f} seconds.")
377
383
 
reflex/state.py CHANGED
@@ -225,8 +225,20 @@ class EventHandlerSetVar(EventHandler):
225
225
  EventHandlerValueError: If the given Var name is not a str
226
226
  NotImplementedError: If the setter for the given Var is async
227
227
  """
228
+ from reflex.config import get_config
228
229
  from reflex.utils.exceptions import EventHandlerValueError
229
230
 
231
+ config = get_config()
232
+ if config.state_auto_setters is None:
233
+ console.deprecate(
234
+ feature_name="state_auto_setters defaulting to True",
235
+ reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
236
+ f"Used {self.state_cls.__name__}.setvar without defining it.",
237
+ deprecation_version="0.8.9",
238
+ removal_version="0.9.0",
239
+ dedupe=True,
240
+ )
241
+
230
242
  if args:
231
243
  if not isinstance(args[0], str):
232
244
  msg = f"Var name must be passed as a string, got {args[0]!r}"
@@ -1036,7 +1048,7 @@ class BaseState(EvenMoreBasicBaseState):
1036
1048
  )
1037
1049
  raise VarTypeError(msg)
1038
1050
  cls._set_var(name, prop)
1039
- if cls.is_user_defined() and get_config().state_auto_setters:
1051
+ if cls.is_user_defined() and get_config().state_auto_setters is not False:
1040
1052
  cls._create_setter(name, prop)
1041
1053
  cls._set_default_value(name, prop)
1042
1054
 
@@ -1096,11 +1108,14 @@ class BaseState(EvenMoreBasicBaseState):
1096
1108
  setattr(cls, name, prop)
1097
1109
 
1098
1110
  @classmethod
1099
- def _create_event_handler(cls, fn: Any):
1111
+ def _create_event_handler(
1112
+ cls, fn: Any, event_handler_cls: type[EventHandler] = EventHandler
1113
+ ):
1100
1114
  """Create an event handler for the given function.
1101
1115
 
1102
1116
  Args:
1103
1117
  fn: The function to create an event handler for.
1118
+ event_handler_cls: The event handler class to use.
1104
1119
 
1105
1120
  Returns:
1106
1121
  The event handler.
@@ -1108,7 +1123,7 @@ class BaseState(EvenMoreBasicBaseState):
1108
1123
  # Check if function has stored event_actions from decorator
1109
1124
  event_actions = getattr(fn, "_rx_event_actions", {})
1110
1125
 
1111
- return EventHandler(
1126
+ return event_handler_cls(
1112
1127
  fn=fn, state_full_name=cls.get_full_name(), event_actions=event_actions
1113
1128
  )
1114
1129
 
@@ -1125,9 +1140,34 @@ class BaseState(EvenMoreBasicBaseState):
1125
1140
  name: The name of the var.
1126
1141
  prop: The var to create a setter for.
1127
1142
  """
1143
+ from reflex.config import get_config
1144
+
1145
+ config = get_config()
1146
+ _create_event_handler_kwargs = {}
1147
+
1148
+ if config.state_auto_setters is None:
1149
+
1150
+ class EventHandlerDeprecatedSetter(EventHandler):
1151
+ def __call__(self, *args, **kwargs):
1152
+ console.deprecate(
1153
+ feature_name="state_auto_setters defaulting to True",
1154
+ reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
1155
+ f"Used {setter_name} in {cls.__name__} without defining it.",
1156
+ deprecation_version="0.8.9",
1157
+ removal_version="0.9.0",
1158
+ dedupe=True,
1159
+ )
1160
+ return super().__call__(*args, **kwargs)
1161
+
1162
+ _create_event_handler_kwargs["event_handler_cls"] = (
1163
+ EventHandlerDeprecatedSetter
1164
+ )
1165
+
1128
1166
  setter_name = Var._get_setter_name_for_name(name)
1129
1167
  if setter_name not in cls.__dict__:
1130
- event_handler = cls._create_event_handler(prop._get_setter(name))
1168
+ event_handler = cls._create_event_handler(
1169
+ prop._get_setter(name), **_create_event_handler_kwargs
1170
+ )
1131
1171
  cls.event_handlers[setter_name] = event_handler
1132
1172
  setattr(cls, setter_name, event_handler)
1133
1173
 
@@ -1810,7 +1850,7 @@ class BaseState(EvenMoreBasicBaseState):
1810
1850
  hinted_args = value_inside_optional(hinted_args)
1811
1851
  if (
1812
1852
  isinstance(value, dict)
1813
- and inspect.isclass(hinted_args)
1853
+ and isinstance(hinted_args, type)
1814
1854
  and not types.is_generic_alias(hinted_args) # py3.10
1815
1855
  ):
1816
1856
  if issubclass(hinted_args, Model):
@@ -2341,7 +2381,7 @@ def _serialize_type(type_: Any) -> str:
2341
2381
  Returns:
2342
2382
  The serialized type.
2343
2383
  """
2344
- if not inspect.isclass(type_):
2384
+ if not isinstance(type_, type):
2345
2385
  return f"{type_}"
2346
2386
  return f"{type_.__module__}.{type_.__qualname__}"
2347
2387
 
reflex/testing.py CHANGED
@@ -472,7 +472,7 @@ class AppHarness:
472
472
  Returns:
473
473
  The rendered app global code.
474
474
  """
475
- if not inspect.isclass(value) and not inspect.isfunction(value):
475
+ if not isinstance(value, type) and not inspect.isfunction(value):
476
476
  return f"{key} = {value!r}"
477
477
  return inspect.getsource(value)
478
478
 
reflex/utils/console.py CHANGED
@@ -7,12 +7,13 @@ import datetime
7
7
  import inspect
8
8
  import os
9
9
  import shutil
10
+ import sys
10
11
  import time
11
12
  from pathlib import Path
12
13
  from types import FrameType
13
14
 
14
15
  from rich.console import Console
15
- from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
16
+ from rich.progress import MofNCompleteColumn, Progress, TaskID, TimeElapsedColumn
16
17
  from rich.prompt import Prompt
17
18
 
18
19
  from reflex.constants import LogLevel
@@ -244,23 +245,38 @@ def warn(msg: str, *, dedupe: bool = False, **kwargs):
244
245
  print_to_log_file(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
245
246
 
246
247
 
247
- def _get_first_non_framework_frame() -> FrameType | None:
248
+ @once
249
+ def _exclude_paths_from_frame_info() -> list[Path]:
250
+ import importlib.util
251
+
248
252
  import click
253
+ import granian
254
+ import socketio
249
255
  import typing_extensions
250
256
 
251
257
  import reflex as rx
252
258
 
253
259
  # Exclude utility modules that should never be the source of deprecated reflex usage.
254
- exclude_modules = [click, rx, typing_extensions]
260
+ exclude_modules = [click, rx, typing_extensions, socketio, granian]
261
+ modules_paths = [file for m in exclude_modules if (file := m.__file__)] + [
262
+ spec.origin
263
+ for m in [*sys.builtin_module_names, *sys.stdlib_module_names]
264
+ if (spec := importlib.util.find_spec(m)) and spec.origin
265
+ ]
255
266
  exclude_roots = [
256
267
  p.parent.resolve() if (p := Path(file)).name == "__init__.py" else p.resolve()
257
- for m in exclude_modules
258
- if (file := m.__file__)
268
+ for file in modules_paths
259
269
  ]
260
270
  # Specifically exclude the reflex cli module.
261
271
  if reflex_bin := shutil.which(b"reflex"):
262
272
  exclude_roots.append(Path(reflex_bin.decode()))
263
273
 
274
+ return exclude_roots
275
+
276
+
277
+ def _get_first_non_framework_frame() -> FrameType | None:
278
+ exclude_roots = _exclude_paths_from_frame_info()
279
+
264
280
  frame = inspect.currentframe()
265
281
  while frame := frame and frame.f_back:
266
282
  frame_path = Path(inspect.getfile(frame)).resolve()
@@ -297,13 +313,13 @@ def deprecate(
297
313
  filename = Path(origin_frame.f_code.co_filename)
298
314
  if filename.is_relative_to(Path.cwd()):
299
315
  filename = filename.relative_to(Path.cwd())
300
- loc = f"{filename}:{origin_frame.f_lineno}"
316
+ loc = f" ({filename}:{origin_frame.f_lineno})"
301
317
  dedupe_key = f"{dedupe_key} {loc}"
302
318
 
303
319
  if dedupe_key not in _EMITTED_DEPRECATION_WARNINGS:
304
320
  msg = (
305
321
  f"{feature_name} has been deprecated in version {deprecation_version}. {reason.rstrip('.').lstrip('. ')}. It will be completely "
306
- f"removed in {removal_version}. ({loc})"
322
+ f"removed in {removal_version}.{loc}"
307
323
  )
308
324
  if _LOG_LEVEL <= LogLevel.WARNING:
309
325
  print(f"[yellow]DeprecationWarning: {msg}[/yellow]", **kwargs)
@@ -395,3 +411,47 @@ def timing(msg: str):
395
411
  yield
396
412
  finally:
397
413
  debug(f"[white]\\[timing] {msg}: {time.time() - start:.2f}s[/white]")
414
+
415
+
416
+ class PoorProgress:
417
+ """A poor man's progress bar."""
418
+
419
+ def __init__(self):
420
+ """Initialize the progress bar."""
421
+ super().__init__()
422
+ self.tasks = {}
423
+ self.progress = 0
424
+ self.total = 0
425
+
426
+ def add_task(self, task: str, total: int):
427
+ """Add a task to the progress bar.
428
+
429
+ Args:
430
+ task: The task name.
431
+ total: The total number of steps for the task.
432
+
433
+ Returns:
434
+ The task ID.
435
+ """
436
+ self.total += total
437
+ task_id = TaskID(len(self.tasks))
438
+ self.tasks[task_id] = {"total": total, "current": 0}
439
+ return task_id
440
+
441
+ def advance(self, task: TaskID, advance: int = 1):
442
+ """Advance the progress of a task.
443
+
444
+ Args:
445
+ task: The task ID.
446
+ advance: The number of steps to advance.
447
+ """
448
+ if task in self.tasks:
449
+ self.tasks[task]["current"] += advance
450
+ self.progress += advance
451
+ _console.print(f"Progress: {self.progress}/{self.total}")
452
+
453
+ def start(self):
454
+ """Start the progress bar."""
455
+
456
+ def stop(self):
457
+ """Stop the progress bar."""
@@ -10,6 +10,7 @@ import click
10
10
  from reflex import constants
11
11
  from reflex.compiler import templates
12
12
  from reflex.config import Config, get_config
13
+ from reflex.environment import environment
13
14
  from reflex.utils import console, path_ops
14
15
  from reflex.utils.prerequisites import get_project_hash, get_web_dir
15
16
  from reflex.utils.registry import get_npm_registry
@@ -192,7 +193,11 @@ def _compile_vite_config(config: Config):
192
193
  base = "/"
193
194
  if frontend_path := config.frontend_path.strip("/"):
194
195
  base += frontend_path + "/"
195
- return templates.vite_config_template(base=base)
196
+ return templates.vite_config_template(
197
+ base=base,
198
+ hmr=environment.VITE_HMR.get(),
199
+ force_full_reload=environment.VITE_FORCE_FULL_RELOAD.get(),
200
+ )
196
201
 
197
202
 
198
203
  def initialize_vite_config():
reflex/utils/imports.py CHANGED
@@ -135,7 +135,7 @@ class ImportVar:
135
135
  if self.alias:
136
136
  return (
137
137
  self.alias
138
- if self.is_default
138
+ if self.is_default and self.tag != "*"
139
139
  else (self.tag + " as " + self.alias if self.tag else self.alias)
140
140
  )
141
141
  return self.tag or ""
@@ -248,6 +248,7 @@ def get_compiled_app(
248
248
  prerender_routes: bool = False,
249
249
  dry_run: bool = False,
250
250
  check_if_schema_up_to_date: bool = False,
251
+ use_rich: bool = True,
251
252
  ) -> ModuleType:
252
253
  """Get the app module based on the default config after first compiling it.
253
254
 
@@ -256,6 +257,7 @@ def get_compiled_app(
256
257
  prerender_routes: Whether to prerender routes.
257
258
  dry_run: If True, do not write the compiled app to disk.
258
259
  check_if_schema_up_to_date: If True, check if the schema is up to date.
260
+ use_rich: Whether to use rich progress bars.
259
261
 
260
262
  Returns:
261
263
  The compiled app based on the default config.
@@ -263,7 +265,7 @@ def get_compiled_app(
263
265
  app, app_module = get_and_validate_app(
264
266
  reload=reload, check_if_schema_up_to_date=check_if_schema_up_to_date
265
267
  )
266
- app._compile(prerender_routes=prerender_routes, dry_run=dry_run)
268
+ app._compile(prerender_routes=prerender_routes, dry_run=dry_run, use_rich=use_rich)
267
269
  return app_module
268
270
 
269
271
 
@@ -547,7 +547,7 @@ def _generate_component_create_functiondef(
547
547
  kwargs.extend(prop_kwargs)
548
548
 
549
549
  def figure_out_return_type(annotation: Any):
550
- if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
550
+ if isinstance(annotation, type) and issubclass(annotation, inspect._empty):
551
551
  return ast.Name(id="EventType[Any]")
552
552
 
553
553
  if not isinstance(annotation, str) and get_origin(annotation) is tuple:
@@ -1181,7 +1181,7 @@ class PyiGenerator:
1181
1181
  class_names = {
1182
1182
  name: obj
1183
1183
  for name, obj in vars(module).items()
1184
- if inspect.isclass(obj)
1184
+ if isinstance(obj, type)
1185
1185
  and (
1186
1186
  rx_types.safe_issubclass(obj, Component)
1187
1187
  or rx_types.safe_issubclass(obj, SimpleNamespace)
@@ -187,7 +187,7 @@ def get_serializer(type_: type) -> Serializer | None:
187
187
 
188
188
  # If the type is not registered, check if it is a subclass of a registered type.
189
189
  for registered_type, serializer in reversed(SERIALIZERS.items()):
190
- if types._issubclass(type_, registered_type):
190
+ if issubclass(type_, registered_type):
191
191
  return serializer
192
192
 
193
193
  # If there is no serializer, return None.
@@ -211,7 +211,7 @@ def get_serializer_type(type_: type) -> type | None:
211
211
 
212
212
  # If the type is not registered, check if it is a subclass of a registered type.
213
213
  for registered_type, serializer in reversed(SERIALIZER_TYPES.items()):
214
- if types._issubclass(type_, registered_type):
214
+ if issubclass(type_, registered_type):
215
215
  return serializer
216
216
 
217
217
  # If there is no serializer, return None.
@@ -244,11 +244,11 @@ def can_serialize(type_: type, into_type: type | None = None) -> bool:
244
244
  Returns:
245
245
  Whether there is a serializer for the type.
246
246
  """
247
- return has_serializer(type_, into_type) or (
247
+ return (
248
248
  isinstance(type_, type)
249
249
  and dataclasses.is_dataclass(type_)
250
250
  and (into_type is None or into_type is dict)
251
- )
251
+ ) or has_serializer(type_, into_type)
252
252
 
253
253
 
254
254
  @serializer(to=str)
reflex/utils/types.py CHANGED
@@ -52,11 +52,8 @@ UnionTypes = (Union, types.UnionType)
52
52
  GenericType = type | _GenericAlias
53
53
 
54
54
  # Valid state var types.
55
- JSONType = {str, int, float, bool}
56
- PrimitiveType = int | float | bool | str | list | dict | set | tuple
57
55
  PrimitiveTypes = (int, float, bool, str, list, dict, set, tuple)
58
- StateVar = PrimitiveType | Base | None
59
- StateIterVar = list | set | tuple
56
+ StateVarTypes = (*PrimitiveTypes, Base, type(None))
60
57
 
61
58
  if TYPE_CHECKING:
62
59
  from reflex.vars.base import Var
@@ -401,6 +398,8 @@ def get_field_type(cls: GenericType, field_name: str) -> GenericType | None:
401
398
  Returns:
402
399
  The type of the field, if it exists, else None.
403
400
  """
401
+ if (fields := getattr(cls, "_fields", None)) is not None and field_name in fields:
402
+ return fields[field_name].annotated_type
404
403
  if (
405
404
  hasattr(cls, "__fields__")
406
405
  and field_name in cls.__fields__
@@ -857,8 +856,11 @@ def is_valid_var_type(type_: type) -> bool:
857
856
 
858
857
  if is_union(type_):
859
858
  return all(is_valid_var_type(arg) for arg in get_args(type_))
859
+
860
+ type_ = origin if (origin := get_origin(type_)) is not None else type_
861
+
860
862
  return (
861
- _issubclass(type_, StateVar)
863
+ issubclass(type_, StateVarTypes)
862
864
  or serializers.has_serializer(type_)
863
865
  or dataclasses.is_dataclass(type_)
864
866
  )
@@ -993,11 +995,6 @@ def validate_literal(key: str, value: Any, expected_type: type, comp_name: str):
993
995
  raise ValueError(msg)
994
996
 
995
997
 
996
- # Store this here for performance.
997
- StateBases = get_base_class(StateVar)
998
- StateIterBases = get_base_class(StateIterVar)
999
-
1000
-
1001
998
  def safe_issubclass(cls: Any, cls_check: Any | tuple[Any, ...]):
1002
999
  """Check if a class is a subclass of another class. Returns False if internal error occurs.
1003
1000
 
reflex/vars/base.py CHANGED
@@ -366,7 +366,7 @@ def can_use_in_object_var(cls: GenericType) -> bool:
366
366
  if types.is_union(cls):
367
367
  return all(can_use_in_object_var(t) for t in types.get_args(cls))
368
368
  return (
369
- inspect.isclass(cls)
369
+ isinstance(cls, type)
370
370
  and not safe_issubclass(cls, Var)
371
371
  and serializers.can_serialize(cls, dict)
372
372
  )
@@ -516,6 +516,17 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
516
516
  """
517
517
  return self._var_data
518
518
 
519
+ def __deepcopy__(self, memo: dict[int, Any]) -> Self:
520
+ """Deepcopy the var.
521
+
522
+ Args:
523
+ memo: The memo dictionary to use for the deepcopy.
524
+
525
+ Returns:
526
+ A deepcopy of the var.
527
+ """
528
+ return self
529
+
519
530
  def equals(self, other: Var) -> bool:
520
531
  """Check if two vars are equal.
521
532
 
@@ -795,7 +806,7 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
795
806
  if can_use_in_object_var(output):
796
807
  return self.to(ObjectVar, output)
797
808
 
798
- if inspect.isclass(output):
809
+ if isinstance(output, type):
799
810
  for var_subclass in _var_subclasses[::-1]:
800
811
  if safe_issubclass(output, var_subclass.var_subclass):
801
812
  current_var_type = self._var_type
@@ -891,7 +902,7 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
891
902
  args = get_args(var_type)
892
903
  fixed_type = unionize(*(type(arg) for arg in args))
893
904
 
894
- if not inspect.isclass(fixed_type):
905
+ if not isinstance(fixed_type, type):
895
906
  msg = f"Unsupported type {var_type} for guess_type."
896
907
  raise TypeError(msg)
897
908
 
@@ -930,6 +941,7 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
930
941
  Returns:
931
942
  A function that that creates a setter for the var.
932
943
  """
944
+ setter_name = Var._get_setter_name_for_name(name)
933
945
 
934
946
  def setter(state: Any, value: Any):
935
947
  """Get the setter for the var.
@@ -951,7 +963,7 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
951
963
 
952
964
  setter.__annotations__["value"] = self._var_type
953
965
 
954
- setter.__qualname__ = Var._get_setter_name_for_name(name)
966
+ setter.__qualname__ = setter_name
955
967
 
956
968
  return setter
957
969
 
@@ -1153,18 +1165,6 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
1153
1165
  """
1154
1166
  return dataclasses.replace(self, _var_data=None)
1155
1167
 
1156
- def __get__(self, instance: Any, owner: Any):
1157
- """Get the var.
1158
-
1159
- Args:
1160
- instance: The instance to get the var from.
1161
- owner: The owner of the var.
1162
-
1163
- Returns:
1164
- The var.
1165
- """
1166
- return self
1167
-
1168
1168
  def _decode(self) -> Any:
1169
1169
  """Decode Var as a python value.
1170
1170
 
@@ -1409,7 +1409,7 @@ class LiteralVar(Var):
1409
1409
  bases = cls.__bases__
1410
1410
 
1411
1411
  bases_normalized = [
1412
- base if inspect.isclass(base) else get_origin(base) for base in bases
1412
+ base if isinstance(base, type) else get_origin(base) for base in bases
1413
1413
  ]
1414
1414
 
1415
1415
  possible_bases = [
@@ -1476,6 +1476,13 @@ class LiteralVar(Var):
1476
1476
  if isinstance(value, var_subclass.python_types):
1477
1477
  return literal_subclass.create(value, _var_data=_var_data)
1478
1478
 
1479
+ if (
1480
+ (as_var_method := getattr(value, "_as_var", None)) is not None
1481
+ and callable(as_var_method)
1482
+ and isinstance((resulting_var := as_var_method()), Var)
1483
+ ):
1484
+ return resulting_var
1485
+
1479
1486
  from reflex.event import EventHandler
1480
1487
  from reflex.utils.format import get_event_handler_parts
1481
1488
 
reflex/vars/object.py CHANGED
@@ -6,7 +6,6 @@ import collections.abc
6
6
  import dataclasses
7
7
  import typing
8
8
  from collections.abc import Mapping
9
- from inspect import isclass
10
9
  from typing import (
11
10
  Any,
12
11
  NoReturn,
@@ -328,7 +327,10 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=Mapping):
328
327
 
329
328
  if (
330
329
  is_typeddict(fixed_type)
331
- or (isclass(fixed_type) and not safe_issubclass(fixed_type, Mapping))
330
+ or (
331
+ isinstance(fixed_type, type)
332
+ and not safe_issubclass(fixed_type, Mapping)
333
+ )
332
334
  or (fixed_type in types.UnionTypes)
333
335
  ):
334
336
  attribute_type = get_attribute_access_type(var_type, name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex
3
- Version: 0.8.8a2
3
+ Version: 0.8.9a1
4
4
  Summary: Web apps in pure Python.
5
5
  Project-URL: homepage, https://reflex.dev
6
6
  Project-URL: repository, https://github.com/reflex-dev/reflex