reflex 0.7.0a5__py3-none-any.whl → 0.7.1a2__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.

Files changed (126) hide show
  1. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +3 -1
  2. reflex/__init__.py +1 -0
  3. reflex/__init__.pyi +1 -0
  4. reflex/app.py +255 -81
  5. reflex/base.py +4 -10
  6. reflex/compiler/compiler.py +46 -12
  7. reflex/compiler/templates.py +1 -2
  8. reflex/compiler/utils.py +23 -14
  9. reflex/components/base/bare.py +109 -16
  10. reflex/components/component.py +179 -124
  11. reflex/components/core/__init__.py +1 -0
  12. reflex/components/core/__init__.pyi +1 -0
  13. reflex/components/core/auto_scroll.py +111 -0
  14. reflex/components/core/auto_scroll.pyi +284 -0
  15. reflex/components/core/banner.py +40 -9
  16. reflex/components/core/banner.pyi +400 -87
  17. reflex/components/core/breakpoints.py +1 -1
  18. reflex/components/core/cond.py +0 -8
  19. reflex/components/core/foreach.py +12 -2
  20. reflex/components/core/html.pyi +200 -19
  21. reflex/components/core/match.py +4 -4
  22. reflex/components/core/sticky.pyi +874 -90
  23. reflex/components/core/upload.py +3 -5
  24. reflex/components/core/upload.pyi +2 -4
  25. reflex/components/datadisplay/code.py +36 -10
  26. reflex/components/datadisplay/code.pyi +1 -1
  27. reflex/components/datadisplay/dataeditor.py +1 -3
  28. reflex/components/datadisplay/dataeditor.pyi +1 -3
  29. reflex/components/el/elements/base.py +95 -17
  30. reflex/components/el/elements/base.pyi +278 -19
  31. reflex/components/el/elements/forms.py +124 -102
  32. reflex/components/el/elements/forms.pyi +2787 -365
  33. reflex/components/el/elements/inline.py +24 -15
  34. reflex/components/el/elements/inline.pyi +5655 -546
  35. reflex/components/el/elements/media.py +79 -95
  36. reflex/components/el/elements/media.pyi +5167 -565
  37. reflex/components/el/elements/metadata.py +19 -17
  38. reflex/components/el/elements/metadata.pyi +841 -89
  39. reflex/components/el/elements/other.py +3 -5
  40. reflex/components/el/elements/other.pyi +1404 -137
  41. reflex/components/el/elements/scripts.py +10 -13
  42. reflex/components/el/elements/scripts.pyi +634 -65
  43. reflex/components/el/elements/sectioning.pyi +3001 -286
  44. reflex/components/el/elements/tables.py +14 -35
  45. reflex/components/el/elements/tables.pyi +2029 -218
  46. reflex/components/el/elements/typography.py +10 -13
  47. reflex/components/el/elements/typography.pyi +3014 -297
  48. reflex/components/lucide/icon.py +22 -6
  49. reflex/components/markdown/markdown.py +30 -10
  50. reflex/components/markdown/markdown.pyi +3 -2
  51. reflex/components/plotly/plotly.py +1 -3
  52. reflex/components/plotly/plotly.pyi +1 -3
  53. reflex/components/radix/primitives/form.pyi +624 -93
  54. reflex/components/radix/themes/color_mode.py +1 -1
  55. reflex/components/radix/themes/color_mode.pyi +213 -31
  56. reflex/components/radix/themes/components/alert_dialog.pyi +199 -18
  57. reflex/components/radix/themes/components/badge.pyi +199 -18
  58. reflex/components/radix/themes/components/button.pyi +213 -31
  59. reflex/components/radix/themes/components/callout.pyi +1000 -95
  60. reflex/components/radix/themes/components/card.pyi +199 -18
  61. reflex/components/radix/themes/components/context_menu.py +79 -1
  62. reflex/components/radix/themes/components/context_menu.pyi +320 -1
  63. reflex/components/radix/themes/components/dialog.pyi +199 -18
  64. reflex/components/radix/themes/components/hover_card.pyi +199 -18
  65. reflex/components/radix/themes/components/icon_button.pyi +213 -31
  66. reflex/components/radix/themes/components/inset.pyi +199 -18
  67. reflex/components/radix/themes/components/popover.pyi +199 -18
  68. reflex/components/radix/themes/components/table.pyi +1437 -154
  69. reflex/components/radix/themes/components/text_area.py +2 -2
  70. reflex/components/radix/themes/components/text_area.pyi +201 -20
  71. reflex/components/radix/themes/components/text_field.py +1 -1
  72. reflex/components/radix/themes/components/text_field.pyi +444 -88
  73. reflex/components/radix/themes/layout/box.pyi +200 -19
  74. reflex/components/radix/themes/layout/center.pyi +199 -18
  75. reflex/components/radix/themes/layout/container.pyi +199 -18
  76. reflex/components/radix/themes/layout/flex.pyi +199 -18
  77. reflex/components/radix/themes/layout/grid.pyi +199 -18
  78. reflex/components/radix/themes/layout/list.pyi +604 -57
  79. reflex/components/radix/themes/layout/section.pyi +199 -18
  80. reflex/components/radix/themes/layout/spacer.pyi +199 -18
  81. reflex/components/radix/themes/layout/stack.pyi +597 -54
  82. reflex/components/radix/themes/typography/blockquote.pyi +200 -19
  83. reflex/components/radix/themes/typography/code.pyi +199 -18
  84. reflex/components/radix/themes/typography/heading.pyi +199 -18
  85. reflex/components/radix/themes/typography/link.pyi +238 -28
  86. reflex/components/radix/themes/typography/text.pyi +1394 -127
  87. reflex/components/react_player/react_player.py +1 -1
  88. reflex/components/react_player/react_player.pyi +1 -3
  89. reflex/components/sonner/toast.py +41 -12
  90. reflex/components/sonner/toast.pyi +20 -6
  91. reflex/components/tags/iter_tag.py +4 -0
  92. reflex/components/tags/tag.py +3 -3
  93. reflex/config.py +187 -28
  94. reflex/constants/__init__.py +2 -0
  95. reflex/constants/base.py +6 -0
  96. reflex/constants/compiler.py +9 -0
  97. reflex/constants/event.py +1 -0
  98. reflex/constants/installer.py +4 -5
  99. reflex/constants/utils.py +1 -3
  100. reflex/event.py +7 -16
  101. reflex/experimental/layout.pyi +597 -54
  102. reflex/py.typed +0 -0
  103. reflex/reflex.py +30 -41
  104. reflex/state.py +49 -44
  105. reflex/style.py +15 -22
  106. reflex/testing.py +2 -0
  107. reflex/utils/build.py +12 -0
  108. reflex/utils/console.py +4 -0
  109. reflex/utils/decorator.py +25 -0
  110. reflex/utils/exec.py +92 -34
  111. reflex/utils/format.py +35 -6
  112. reflex/utils/path_ops.py +16 -1
  113. reflex/utils/prerequisites.py +34 -8
  114. reflex/utils/processes.py +12 -13
  115. reflex/utils/serializers.py +20 -43
  116. reflex/utils/telemetry.py +4 -15
  117. reflex/utils/types.py +36 -66
  118. reflex/vars/base.py +53 -76
  119. reflex/vars/function.py +17 -5
  120. reflex/vars/number.py +1 -1
  121. reflex/vars/sequence.py +80 -4
  122. {reflex-0.7.0a5.dist-info → reflex-0.7.1a2.dist-info}/METADATA +4 -5
  123. {reflex-0.7.0a5.dist-info → reflex-0.7.1a2.dist-info}/RECORD +126 -122
  124. {reflex-0.7.0a5.dist-info → reflex-0.7.1a2.dist-info}/LICENSE +0 -0
  125. {reflex-0.7.0a5.dist-info → reflex-0.7.1a2.dist-info}/WHEEL +0 -0
  126. {reflex-0.7.0a5.dist-info → reflex-0.7.1a2.dist-info}/entry_points.txt +0 -0
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from datetime import datetime
6
6
  from pathlib import Path
7
- from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Type, Union
7
+ from typing import TYPE_CHECKING, Dict, Iterable, Optional, Sequence, Tuple, Type, Union
8
8
 
9
9
  from reflex import constants
10
10
  from reflex.compiler import templates, utils
@@ -78,6 +78,7 @@ def _compile_app(app_root: Component) -> str:
78
78
  hooks=app_root._get_all_hooks(),
79
79
  window_libraries=window_libraries,
80
80
  render=app_root.render(),
81
+ dynamic_imports=app_root._get_all_dynamic_imports(),
81
82
  )
82
83
 
83
84
 
@@ -507,7 +508,7 @@ def compile_tailwind(
507
508
  The compiled Tailwind config.
508
509
  """
509
510
  # Get the path for the output file.
510
- output_path = get_web_dir() / constants.Tailwind.CONFIG
511
+ output_path = str((get_web_dir() / constants.Tailwind.CONFIG).absolute())
511
512
 
512
513
  # Compile the config.
513
514
  code = _compile_tailwind(config)
@@ -544,7 +545,47 @@ def purge_web_pages_dir():
544
545
 
545
546
 
546
547
  if TYPE_CHECKING:
547
- from reflex.app import UnevaluatedPage
548
+ from reflex.app import ComponentCallable, UnevaluatedPage
549
+
550
+
551
+ def _into_component_once(component: Component | ComponentCallable) -> Component | None:
552
+ """Convert a component to a Component.
553
+
554
+ Args:
555
+ component: The component to convert.
556
+
557
+ Returns:
558
+ The converted component.
559
+ """
560
+ if isinstance(component, Component):
561
+ return component
562
+ if isinstance(component, (Var, int, float, str)):
563
+ return Fragment.create(component)
564
+ if isinstance(component, Sequence):
565
+ return Fragment.create(*component)
566
+ return None
567
+
568
+
569
+ def into_component(component: Component | ComponentCallable) -> Component:
570
+ """Convert a component to a Component.
571
+
572
+ Args:
573
+ component: The component to convert.
574
+
575
+ Returns:
576
+ The converted component.
577
+
578
+ Raises:
579
+ TypeError: If the component is not a Component.
580
+ """
581
+ if (converted := _into_component_once(component)) is not None:
582
+ return converted
583
+ if (
584
+ callable(component)
585
+ and (converted := _into_component_once(component())) is not None
586
+ ):
587
+ return converted
588
+ raise TypeError(f"Expected a Component, got {type(component)}")
548
589
 
549
590
 
550
591
  def compile_unevaluated_page(
@@ -567,12 +608,7 @@ def compile_unevaluated_page(
567
608
  The compiled component and whether state should be enabled.
568
609
  """
569
610
  # Generate the component if it is a callable.
570
- component = page.component
571
- component = component if isinstance(component, Component) else component()
572
-
573
- # unpack components that return tuples in an rx.fragment.
574
- if isinstance(component, tuple):
575
- component = Fragment.create(*component)
611
+ component = into_component(page.component)
576
612
 
577
613
  component._add_style_recursive(style or {}, theme)
578
614
 
@@ -677,10 +713,8 @@ class ExecutorSafeFunctions:
677
713
  The route, compiled component, and compiled page.
678
714
  """
679
715
  component, enable_state = compile_unevaluated_page(
680
- route, cls.UNCOMPILED_PAGES[route]
716
+ route, cls.UNCOMPILED_PAGES[route], cls.STATE, style, theme
681
717
  )
682
- component = component if isinstance(component, Component) else component()
683
- component._add_style_recursive(style, theme)
684
718
  return route, component, compile_page(route, component, cls.STATE)
685
719
 
686
720
  @classmethod
@@ -48,11 +48,10 @@ class ReflexJinjaEnvironment(Environment):
48
48
 
49
49
  def __init__(self) -> None:
50
50
  """Set default environment."""
51
- extensions = ["jinja2.ext.debug"]
52
51
  super().__init__(
53
- extensions=extensions,
54
52
  trim_blocks=True,
55
53
  lstrip_blocks=True,
54
+ auto_reload=False,
56
55
  )
57
56
  self.filters["json_dumps"] = json_dumps
58
57
  self.filters["react_setter"] = lambda state: f"set{state.capitalize()}"
reflex/compiler/utils.py CHANGED
@@ -10,16 +10,7 @@ from pathlib import Path
10
10
  from typing import Any, Callable, Dict, Optional, Type, Union
11
11
  from urllib.parse import urlparse
12
12
 
13
- from reflex.utils.exec import is_in_app_harness
14
- from reflex.utils.prerequisites import get_web_dir
15
- from reflex.vars.base import Var
16
-
17
- try:
18
- from pydantic.v1.fields import ModelField
19
- except ModuleNotFoundError:
20
- from pydantic.fields import (
21
- ModelField, # pyright: ignore [reportAttributeAccessIssue]
22
- )
13
+ from pydantic.v1.fields import ModelField
23
14
 
24
15
  from reflex import constants
25
16
  from reflex.components.base import (
@@ -39,7 +30,10 @@ from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
39
30
  from reflex.state import BaseState, _resolve_delta
40
31
  from reflex.style import Style
41
32
  from reflex.utils import console, format, imports, path_ops
33
+ from reflex.utils.exec import is_in_app_harness
42
34
  from reflex.utils.imports import ImportVar, ParsedImportDict
35
+ from reflex.utils.prerequisites import get_web_dir
36
+ from reflex.vars.base import Var
43
37
 
44
38
  # To re-export this function.
45
39
  merge_imports = imports.merge_imports
@@ -168,6 +162,22 @@ def get_import_dict(lib: str, default: str = "", rest: list[str] | None = None)
168
162
  }
169
163
 
170
164
 
165
+ def save_error(error: Exception) -> str:
166
+ """Save the error to a file.
167
+
168
+ Args:
169
+ error: The error to save.
170
+
171
+ Returns:
172
+ The path of the saved error.
173
+ """
174
+ timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
175
+ constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
176
+ log_path = constants.Reflex.LOGS_DIR / f"error_{timestamp}.log"
177
+ traceback.TracebackException.from_exception(error).print(file=log_path.open("w+"))
178
+ return str(log_path)
179
+
180
+
171
181
  def compile_state(state: Type[BaseState]) -> dict:
172
182
  """Compile the state of the app.
173
183
 
@@ -180,10 +190,7 @@ def compile_state(state: Type[BaseState]) -> dict:
180
190
  try:
181
191
  initial_state = state(_reflex_internal_init=True).dict(initial=True)
182
192
  except Exception as e:
183
- timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
184
- constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
185
- log_path = constants.Reflex.LOGS_DIR / f"state_compile_error_{timestamp}.log"
186
- traceback.TracebackException.from_exception(e).print(file=log_path.open("w+"))
193
+ log_path = save_error(e)
187
194
  console.warn(
188
195
  f"Failed to compile initial state with computed vars. Error log saved to {log_path}"
189
196
  )
@@ -510,6 +517,8 @@ def write_page(path: str | Path, code: str):
510
517
  """
511
518
  path = Path(path)
512
519
  path_ops.mkdir(path.parent)
520
+ if path.exists() and path.read_text(encoding="utf-8") == code:
521
+ return
513
522
  path.write_text(code, encoding="utf-8")
514
523
 
515
524
 
@@ -2,14 +2,54 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Iterator
5
+ from typing import Any, Iterator, Sequence
6
6
 
7
- from reflex.components.component import Component, LiteralComponentVar
7
+ from reflex.components.component import BaseComponent, Component, ComponentStyle
8
8
  from reflex.components.tags import Tag
9
9
  from reflex.components.tags.tagless import Tagless
10
+ from reflex.config import PerformanceMode, environment
11
+ from reflex.utils import console
12
+ from reflex.utils.decorator import once
10
13
  from reflex.utils.imports import ParsedImportDict
11
14
  from reflex.vars import BooleanVar, ObjectVar, Var
12
- from reflex.vars.base import VarData
15
+ from reflex.vars.base import GLOBAL_CACHE, VarData
16
+ from reflex.vars.sequence import LiteralStringVar
17
+
18
+
19
+ @once
20
+ def get_performance_mode():
21
+ """Get the performance mode.
22
+
23
+ Returns:
24
+ The performance mode.
25
+ """
26
+ return environment.REFLEX_PERF_MODE.get()
27
+
28
+
29
+ def validate_str(value: str):
30
+ """Validate a string value.
31
+
32
+ Args:
33
+ value: The value to validate.
34
+
35
+ Raises:
36
+ ValueError: If the value is a Var and the performance mode is set to raise.
37
+ """
38
+ perf_mode = get_performance_mode()
39
+ if perf_mode != PerformanceMode.OFF and value.startswith("reflex___state"):
40
+ if perf_mode == PerformanceMode.WARN:
41
+ console.warn(
42
+ f"Output includes {value!s} which will be displayed as a string. If you are calling `str` on a Var, consider using .to_string() instead."
43
+ )
44
+ elif perf_mode == PerformanceMode.RAISE:
45
+ raise ValueError(
46
+ f"Output includes {value!s} which will be displayed as a string. If you are calling `str` on a Var, consider using .to_string() instead."
47
+ )
48
+
49
+
50
+ def _components_from_var(var: Var) -> Sequence[BaseComponent]:
51
+ var_data = var._get_all_var_data()
52
+ return var_data.components if var_data else ()
13
53
 
14
54
 
15
55
  class Bare(Component):
@@ -28,9 +68,14 @@ class Bare(Component):
28
68
  The component.
29
69
  """
30
70
  if isinstance(contents, Var):
71
+ if isinstance(contents, LiteralStringVar):
72
+ validate_str(contents._var_value)
31
73
  return cls(contents=contents)
32
74
  else:
75
+ if isinstance(contents, str):
76
+ validate_str(contents)
33
77
  contents = str(contents) if contents is not None else ""
78
+
34
79
  return cls(contents=contents)
35
80
 
36
81
  def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
@@ -40,8 +85,9 @@ class Bare(Component):
40
85
  The hooks for the component.
41
86
  """
42
87
  hooks = super()._get_all_hooks_internal()
43
- if isinstance(self.contents, LiteralComponentVar):
44
- hooks |= self.contents._var_value._get_all_hooks_internal()
88
+ if isinstance(self.contents, Var):
89
+ for component in _components_from_var(self.contents):
90
+ hooks |= component._get_all_hooks_internal()
45
91
  return hooks
46
92
 
47
93
  def _get_all_hooks(self) -> dict[str, VarData | None]:
@@ -51,18 +97,22 @@ class Bare(Component):
51
97
  The hooks for the component.
52
98
  """
53
99
  hooks = super()._get_all_hooks()
54
- if isinstance(self.contents, LiteralComponentVar):
55
- hooks |= self.contents._var_value._get_all_hooks()
100
+ if isinstance(self.contents, Var):
101
+ for component in _components_from_var(self.contents):
102
+ hooks |= component._get_all_hooks()
56
103
  return hooks
57
104
 
58
- def _get_all_imports(self) -> ParsedImportDict:
105
+ def _get_all_imports(self, collapse: bool = False) -> ParsedImportDict:
59
106
  """Include the imports for the component.
60
107
 
108
+ Args:
109
+ collapse: Whether to collapse the imports.
110
+
61
111
  Returns:
62
112
  The imports for the component.
63
113
  """
64
- imports = super()._get_all_imports()
65
- if isinstance(self.contents, LiteralComponentVar):
114
+ imports = super()._get_all_imports(collapse=collapse)
115
+ if isinstance(self.contents, Var):
66
116
  var_data = self.contents._get_all_var_data()
67
117
  if var_data:
68
118
  imports |= {k: list(v) for k, v in var_data.imports}
@@ -75,8 +125,9 @@ class Bare(Component):
75
125
  The dynamic imports.
76
126
  """
77
127
  dynamic_imports = super()._get_all_dynamic_imports()
78
- if isinstance(self.contents, LiteralComponentVar):
79
- dynamic_imports |= self.contents._var_value._get_all_dynamic_imports()
128
+ if isinstance(self.contents, Var):
129
+ for component in _components_from_var(self.contents):
130
+ dynamic_imports |= component._get_all_dynamic_imports()
80
131
  return dynamic_imports
81
132
 
82
133
  def _get_all_custom_code(self) -> set[str]:
@@ -86,10 +137,24 @@ class Bare(Component):
86
137
  The custom code.
87
138
  """
88
139
  custom_code = super()._get_all_custom_code()
89
- if isinstance(self.contents, LiteralComponentVar):
90
- custom_code |= self.contents._var_value._get_all_custom_code()
140
+ if isinstance(self.contents, Var):
141
+ for component in _components_from_var(self.contents):
142
+ custom_code |= component._get_all_custom_code()
91
143
  return custom_code
92
144
 
145
+ def _get_all_app_wrap_components(self) -> dict[tuple[int, str], Component]:
146
+ """Get the components that should be wrapped in the app.
147
+
148
+ Returns:
149
+ The components that should be wrapped in the app.
150
+ """
151
+ app_wrap_components = super()._get_all_app_wrap_components()
152
+ if isinstance(self.contents, Var):
153
+ for component in _components_from_var(self.contents):
154
+ if isinstance(component, Component):
155
+ app_wrap_components |= component._get_all_app_wrap_components()
156
+ return app_wrap_components
157
+
93
158
  def _get_all_refs(self) -> set[str]:
94
159
  """Get the refs for the children of the component.
95
160
 
@@ -97,8 +162,9 @@ class Bare(Component):
97
162
  The refs for the children.
98
163
  """
99
164
  refs = super()._get_all_refs()
100
- if isinstance(self.contents, LiteralComponentVar):
101
- refs |= self.contents._var_value._get_all_refs()
165
+ if isinstance(self.contents, Var):
166
+ for component in _components_from_var(self.contents):
167
+ refs |= component._get_all_refs()
102
168
  return refs
103
169
 
104
170
  def _render(self) -> Tag:
@@ -108,6 +174,33 @@ class Bare(Component):
108
174
  return Tagless(contents=f"{{{self.contents!s}}}")
109
175
  return Tagless(contents=str(self.contents))
110
176
 
177
+ def _add_style_recursive(
178
+ self, style: ComponentStyle, theme: Component | None = None
179
+ ) -> Component:
180
+ """Add style to the component and its children.
181
+
182
+ Args:
183
+ style: The style to add.
184
+ theme: The theme to add.
185
+
186
+ Returns:
187
+ The component with the style added.
188
+ """
189
+ new_self = super()._add_style_recursive(style, theme)
190
+
191
+ are_components_touched = False
192
+
193
+ if isinstance(self.contents, Var):
194
+ for component in _components_from_var(self.contents):
195
+ if isinstance(component, Component):
196
+ component._add_style_recursive(style, theme)
197
+ are_components_touched = True
198
+
199
+ if are_components_touched:
200
+ GLOBAL_CACHE.clear()
201
+
202
+ return new_self
203
+
111
204
  def _get_vars(
112
205
  self, include_children: bool = False, ignore_ids: set[int] | None = None
113
206
  ) -> Iterator[Var]: