reflex 0.8.0a2__py3-none-any.whl → 0.8.0a4__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.

@@ -2,7 +2,7 @@
2
2
  {% from "web/pages/macros.js.jinja2" import renderHooks %}
3
3
 
4
4
  {% block early_imports %}
5
- import '$/styles/__reflex_global_styles.css'
5
+ import reflexGlobalStyles from '$/styles/__reflex_global_styles.css?url';
6
6
  {% endblock %}
7
7
 
8
8
  {% block declaration %}
@@ -20,6 +20,10 @@ import * as {{library_alias}} from "{{library_path}}";
20
20
  {% endblock %}
21
21
 
22
22
  {% block export %}
23
+ export const links = () => [
24
+ { rel: 'stylesheet', href: reflexGlobalStyles, type: 'text/css' }
25
+ ];
26
+
23
27
  function AppWrap({children}) {
24
28
  {{ renderHooks(hooks) }}
25
29
 
@@ -0,0 +1,399 @@
1
+ @layer __reflex_base {
2
+ /*
3
+ 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
4
+ 2. Remove default margins and padding
5
+ 3. Reset all borders.
6
+ */
7
+
8
+ *,
9
+ ::after,
10
+ ::before,
11
+ ::backdrop,
12
+ ::file-selector-button {
13
+ box-sizing: border-box; /* 1 */
14
+ margin: 0; /* 2 */
15
+ padding: 0; /* 2 */
16
+ border: 0 solid; /* 3 */
17
+ }
18
+
19
+ /*
20
+ 1. Use a consistent sensible line-height in all browsers.
21
+ 2. Prevent adjustments of font size after orientation changes in iOS.
22
+ 3. Use a more readable tab size.
23
+ 4. Use the user's configured `sans` font-family by default.
24
+ 5. Use the user's configured `sans` font-feature-settings by default.
25
+ 6. Use the user's configured `sans` font-variation-settings by default.
26
+ 7. Disable tap highlights on iOS.
27
+ */
28
+
29
+ html,
30
+ :host {
31
+ line-height: 1.5; /* 1 */
32
+ -webkit-text-size-adjust: 100%; /* 2 */
33
+ tab-size: 4; /* 3 */
34
+ font-family: --theme(
35
+ --default-font-family,
36
+ ui-sans-serif,
37
+ system-ui,
38
+ sans-serif,
39
+ "Apple Color Emoji",
40
+ "Segoe UI Emoji",
41
+ "Segoe UI Symbol",
42
+ "Noto Color Emoji"
43
+ ); /* 4 */
44
+ font-feature-settings: --theme(
45
+ --default-font-feature-settings,
46
+ normal
47
+ ); /* 5 */
48
+ font-variation-settings: --theme(
49
+ --default-font-variation-settings,
50
+ normal
51
+ ); /* 6 */
52
+ -webkit-tap-highlight-color: transparent; /* 7 */
53
+ }
54
+
55
+ /*
56
+ 1. Add the correct height in Firefox.
57
+ 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
58
+ 3. Reset the default border style to a 1px solid border.
59
+ */
60
+
61
+ hr {
62
+ height: 0; /* 1 */
63
+ color: inherit; /* 2 */
64
+ border-top-width: 1px; /* 3 */
65
+ }
66
+
67
+ /*
68
+ Add the correct text decoration in Chrome, Edge, and Safari.
69
+ */
70
+
71
+ abbr:where([title]) {
72
+ -webkit-text-decoration: underline dotted;
73
+ text-decoration: underline dotted;
74
+ }
75
+
76
+ /*
77
+ Remove the default font size and weight for headings.
78
+ */
79
+
80
+ h1,
81
+ h2,
82
+ h3,
83
+ h4,
84
+ h5,
85
+ h6 {
86
+ font-size: inherit;
87
+ font-weight: inherit;
88
+ }
89
+
90
+ /*
91
+ Reset links to optimize for opt-in styling instead of opt-out.
92
+ */
93
+
94
+ a {
95
+ color: inherit;
96
+ -webkit-text-decoration: inherit;
97
+ text-decoration: inherit;
98
+ }
99
+
100
+ /*
101
+ Add the correct font weight in Edge and Safari.
102
+ */
103
+
104
+ b,
105
+ strong {
106
+ font-weight: bolder;
107
+ }
108
+
109
+ /*
110
+ 1. Use the user's configured `mono` font-family by default.
111
+ 2. Use the user's configured `mono` font-feature-settings by default.
112
+ 3. Use the user's configured `mono` font-variation-settings by default.
113
+ 4. Correct the odd `em` font sizing in all browsers.
114
+ */
115
+
116
+ code,
117
+ kbd,
118
+ samp,
119
+ pre {
120
+ font-family: --theme(
121
+ --default-mono-font-family,
122
+ ui-monospace,
123
+ SFMono-Regular,
124
+ Menlo,
125
+ Monaco,
126
+ Consolas,
127
+ "Liberation Mono",
128
+ "Courier New",
129
+ monospace
130
+ ); /* 1 */
131
+ font-feature-settings: --theme(
132
+ --default-mono-font-feature-settings,
133
+ normal
134
+ ); /* 2 */
135
+ font-variation-settings: --theme(
136
+ --default-mono-font-variation-settings,
137
+ normal
138
+ ); /* 3 */
139
+ font-size: 1em; /* 4 */
140
+ }
141
+
142
+ /*
143
+ Add the correct font size in all browsers.
144
+ */
145
+
146
+ small {
147
+ font-size: 80%;
148
+ }
149
+
150
+ /*
151
+ Prevent `sub` and `sup` elements from affecting the line height in all browsers.
152
+ */
153
+
154
+ sub,
155
+ sup {
156
+ font-size: 75%;
157
+ line-height: 0;
158
+ position: relative;
159
+ vertical-align: baseline;
160
+ }
161
+
162
+ sub {
163
+ bottom: -0.25em;
164
+ }
165
+
166
+ sup {
167
+ top: -0.5em;
168
+ }
169
+
170
+ /*
171
+ 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
172
+ 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
173
+ 3. Remove gaps between table borders by default.
174
+ */
175
+
176
+ table {
177
+ text-indent: 0; /* 1 */
178
+ border-color: inherit; /* 2 */
179
+ border-collapse: collapse; /* 3 */
180
+ }
181
+
182
+ /*
183
+ Use the modern Firefox focus style for all focusable elements.
184
+ */
185
+
186
+ :-moz-focusring {
187
+ outline: auto;
188
+ }
189
+
190
+ /*
191
+ Add the correct vertical alignment in Chrome and Firefox.
192
+ */
193
+
194
+ progress {
195
+ vertical-align: baseline;
196
+ }
197
+
198
+ /*
199
+ Add the correct display in Chrome and Safari.
200
+ */
201
+
202
+ summary {
203
+ display: list-item;
204
+ }
205
+
206
+ /*
207
+ Make lists unstyled by default.
208
+ */
209
+
210
+ ol,
211
+ ul,
212
+ menu {
213
+ list-style: none;
214
+ }
215
+
216
+ /*
217
+ 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
218
+ 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
219
+ This can trigger a poorly considered lint error in some tools but is included by design.
220
+ */
221
+
222
+ img,
223
+ svg,
224
+ video,
225
+ canvas,
226
+ audio,
227
+ iframe,
228
+ embed,
229
+ object {
230
+ display: block; /* 1 */
231
+ vertical-align: middle; /* 2 */
232
+ }
233
+
234
+ /*
235
+ Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
236
+ */
237
+
238
+ img,
239
+ video {
240
+ max-width: 100%;
241
+ height: auto;
242
+ }
243
+
244
+ /*
245
+ 1. Inherit font styles in all browsers.
246
+ 2. Remove border radius in all browsers.
247
+ 3. Remove background color in all browsers.
248
+ 4. Ensure consistent opacity for disabled states in all browsers.
249
+ */
250
+
251
+ button,
252
+ input,
253
+ select,
254
+ optgroup,
255
+ textarea,
256
+ ::file-selector-button {
257
+ font: inherit; /* 1 */
258
+ font-feature-settings: inherit; /* 1 */
259
+ font-variation-settings: inherit; /* 1 */
260
+ letter-spacing: inherit; /* 1 */
261
+ color: inherit; /* 1 */
262
+ border-radius: 0; /* 2 */
263
+ background-color: transparent; /* 3 */
264
+ opacity: 1; /* 4 */
265
+ }
266
+
267
+ /*
268
+ Restore default font weight.
269
+ */
270
+
271
+ :where(select:is([multiple], [size])) optgroup {
272
+ font-weight: bolder;
273
+ }
274
+
275
+ /*
276
+ Restore indentation.
277
+ */
278
+
279
+ :where(select:is([multiple], [size])) optgroup option {
280
+ padding-inline-start: 20px;
281
+ }
282
+
283
+ /*
284
+ Restore space after button.
285
+ */
286
+
287
+ ::file-selector-button {
288
+ margin-inline-end: 4px;
289
+ }
290
+
291
+ /*
292
+ Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
293
+ */
294
+
295
+ ::placeholder {
296
+ opacity: 1;
297
+ }
298
+
299
+ /*
300
+ Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not
301
+ crash when using `color-mix(…)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194)
302
+ */
303
+
304
+ @supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or
305
+ (contain-intrinsic-size: 1px) /* Safari 17+ */ {
306
+ ::placeholder {
307
+ color: color-mix(in oklab, currentcolor 50%, transparent);
308
+ }
309
+ }
310
+
311
+ /*
312
+ Prevent resizing textareas horizontally by default.
313
+ */
314
+
315
+ textarea {
316
+ resize: vertical;
317
+ }
318
+
319
+ /*
320
+ Remove the inner padding in Chrome and Safari on macOS.
321
+ */
322
+
323
+ ::-webkit-search-decoration {
324
+ -webkit-appearance: none;
325
+ }
326
+
327
+ /*
328
+ 1. Ensure date/time inputs have the same height when empty in iOS Safari.
329
+ 2. Ensure text alignment can be changed on date/time inputs in iOS Safari.
330
+ */
331
+
332
+ ::-webkit-date-and-time-value {
333
+ min-height: 1lh; /* 1 */
334
+ text-align: inherit; /* 2 */
335
+ }
336
+
337
+ /*
338
+ Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`.
339
+ */
340
+
341
+ ::-webkit-datetime-edit {
342
+ display: inline-flex;
343
+ }
344
+
345
+ /*
346
+ Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers.
347
+ */
348
+
349
+ ::-webkit-datetime-edit-fields-wrapper {
350
+ padding: 0;
351
+ }
352
+
353
+ ::-webkit-datetime-edit,
354
+ ::-webkit-datetime-edit-year-field,
355
+ ::-webkit-datetime-edit-month-field,
356
+ ::-webkit-datetime-edit-day-field,
357
+ ::-webkit-datetime-edit-hour-field,
358
+ ::-webkit-datetime-edit-minute-field,
359
+ ::-webkit-datetime-edit-second-field,
360
+ ::-webkit-datetime-edit-millisecond-field,
361
+ ::-webkit-datetime-edit-meridiem-field {
362
+ padding-block: 0;
363
+ }
364
+
365
+ /*
366
+ Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
367
+ */
368
+
369
+ :-moz-ui-invalid {
370
+ box-shadow: none;
371
+ }
372
+
373
+ /*
374
+ Correct the inability to style the border radius in iOS Safari.
375
+ */
376
+
377
+ button,
378
+ input:where([type="button"], [type="reset"], [type="submit"]),
379
+ ::file-selector-button {
380
+ appearance: button;
381
+ }
382
+
383
+ /*
384
+ Correct the cursor style of increment and decrement buttons in Safari.
385
+ */
386
+
387
+ ::-webkit-inner-spin-button,
388
+ ::-webkit-outer-spin-button {
389
+ height: auto;
390
+ }
391
+
392
+ /*
393
+ Make elements with the HTML hidden attribute stay hidden by default.
394
+ */
395
+
396
+ [hidden]:where(:not([hidden="until-found"])) {
397
+ display: none !important;
398
+ }
399
+ }
@@ -11,6 +11,12 @@ export default defineConfig((config) => ({
11
11
  },
12
12
  server: {
13
13
  port: process.env.PORT,
14
+ watch: {
15
+ ignored: [
16
+ "**/.web/backend/**",
17
+ "**/.web/reflex.install_frontend_packages.cached",
18
+ ],
19
+ },
14
20
  },
15
21
  resolve: {
16
22
  mainFields: ["browser", "module", "jsnext"],
reflex/app.py CHANGED
@@ -77,6 +77,7 @@ from reflex.event import (
77
77
  EventType,
78
78
  IndividualEventType,
79
79
  get_hydrate_event,
80
+ noop,
80
81
  )
81
82
  from reflex.model import Model, get_db_status
82
83
  from reflex.page import DECORATED_PAGES
@@ -213,17 +214,21 @@ def default_overlay_component() -> Component:
213
214
  return Fragment.create(memo(default_overlay_components)())
214
215
 
215
216
 
216
- def default_error_boundary(*children: Component) -> Component:
217
+ def default_error_boundary(*children: Component, **props) -> Component:
217
218
  """Default error_boundary attribute for App.
218
219
 
219
220
  Args:
220
221
  *children: The children to render in the error boundary.
222
+ **props: The props to pass to the error boundary.
221
223
 
222
224
  Returns:
223
225
  The default error_boundary, which is an ErrorBoundary.
224
226
 
225
227
  """
226
- return ErrorBoundary.create(*children)
228
+ return ErrorBoundary.create(
229
+ *children,
230
+ **props,
231
+ )
227
232
 
228
233
 
229
234
  class OverlayFragment(Fragment):
@@ -332,6 +337,9 @@ class App(MiddlewareMixin, LifespanMixin):
332
337
  # A list of URLs to [stylesheets](https://reflex.dev/docs/styling/custom-stylesheets/) to include in the app.
333
338
  stylesheets: list[str] = dataclasses.field(default_factory=list)
334
339
 
340
+ # Whether to include CSS reset for margin and padding (defaults to True).
341
+ reset_style: bool = dataclasses.field(default=True)
342
+
335
343
  # A component that is present on every page (defaults to the Connection Error banner).
336
344
  overlay_component: Component | ComponentCallable | None = dataclasses.field(
337
345
  default=None
@@ -342,7 +350,9 @@ class App(MiddlewareMixin, LifespanMixin):
342
350
  dataclasses.field(
343
351
  default_factory=lambda: {
344
352
  (55, "ErrorBoundary"): (
345
- lambda stateful: default_error_boundary() if stateful else None
353
+ lambda stateful: default_error_boundary(
354
+ **({"on_error": noop()} if not stateful else {})
355
+ )
346
356
  ),
347
357
  (5, "Overlay"): (
348
358
  lambda stateful: default_overlay_component() if stateful else None
@@ -1358,7 +1368,9 @@ class App(MiddlewareMixin, LifespanMixin):
1358
1368
  )
1359
1369
 
1360
1370
  # Compile the root stylesheet with base styles.
1361
- _submit_work(compiler.compile_root_stylesheet, self.stylesheets)
1371
+ _submit_work(
1372
+ compiler.compile_root_stylesheet, self.stylesheets, self.reset_style
1373
+ )
1362
1374
 
1363
1375
  # Compile the theme.
1364
1376
  _submit_work(compile_theme, self.style)
@@ -19,7 +19,7 @@ from reflex.components.component import (
19
19
  StatefulComponent,
20
20
  )
21
21
  from reflex.config import get_config
22
- from reflex.constants.compiler import PageNames
22
+ from reflex.constants.compiler import PageNames, ResetStylesheet
23
23
  from reflex.constants.state import FIELD_MARKER
24
24
  from reflex.environment import environment
25
25
  from reflex.state import BaseState
@@ -171,18 +171,21 @@ def _compile_page(
171
171
  )
172
172
 
173
173
 
174
- def compile_root_stylesheet(stylesheets: list[str]) -> tuple[str, str]:
174
+ def compile_root_stylesheet(
175
+ stylesheets: list[str], reset_style: bool = True
176
+ ) -> tuple[str, str]:
175
177
  """Compile the root stylesheet.
176
178
 
177
179
  Args:
178
180
  stylesheets: The stylesheets to include in the root stylesheet.
181
+ reset_style: Whether to include CSS reset for margin and padding.
179
182
 
180
183
  Returns:
181
184
  The path and code of the compiled root stylesheet.
182
185
  """
183
186
  output_path = utils.get_root_stylesheet_path()
184
187
 
185
- code = _compile_root_stylesheet(stylesheets)
188
+ code = _compile_root_stylesheet(stylesheets, reset_style)
186
189
 
187
190
  return output_path, code
188
191
 
@@ -224,11 +227,12 @@ def _validate_stylesheet(stylesheet_full_path: Path, assets_app_path: Path) -> N
224
227
  RADIX_THEMES_STYLESHEET = "@radix-ui/themes/styles.css"
225
228
 
226
229
 
227
- def _compile_root_stylesheet(stylesheets: list[str]) -> str:
230
+ def _compile_root_stylesheet(stylesheets: list[str], reset_style: bool = True) -> str:
228
231
  """Compile the root stylesheet.
229
232
 
230
233
  Args:
231
234
  stylesheets: The stylesheets to include in the root stylesheet.
235
+ reset_style: Whether to include CSS reset for margin and padding.
232
236
 
233
237
  Returns:
234
238
  The compiled root stylesheet.
@@ -237,11 +241,21 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
237
241
  FileNotFoundError: If a specified stylesheet in assets directory does not exist.
238
242
  """
239
243
  # Add stylesheets from plugins.
240
- sheets = [RADIX_THEMES_STYLESHEET] + [
241
- sheet
242
- for plugin in get_config().plugins
243
- for sheet in plugin.get_stylesheet_paths()
244
- ]
244
+ sheets = []
245
+
246
+ # Add CSS reset if enabled
247
+ if reset_style:
248
+ # Reference the vendored style reset file (automatically copied from .templates/web)
249
+ sheets.append(f"./{ResetStylesheet.FILENAME}")
250
+
251
+ sheets.extend(
252
+ [RADIX_THEMES_STYLESHEET]
253
+ + [
254
+ sheet
255
+ for plugin in get_config().plugins
256
+ for sheet in plugin.get_stylesheet_paths()
257
+ ]
258
+ )
245
259
 
246
260
  failed_to_import_sass = False
247
261
  assets_app_path = Path.cwd() / constants.Dirs.APP_ASSETS
@@ -3,11 +3,11 @@
3
3
  # ------------------- DO NOT EDIT ----------------------
4
4
  # This file was generated by `reflex/utils/pyi_generator.py`!
5
5
  # ------------------------------------------------------
6
- import dataclasses
7
6
  from collections.abc import Mapping, Sequence
8
7
  from enum import Enum
9
8
  from typing import Any, Literal, TypedDict, overload
10
9
 
10
+ from reflex.base import Base
11
11
  from reflex.components.component import NoSSRComponent
12
12
  from reflex.components.core.breakpoints import Breakpoints
13
13
  from reflex.event import EventType, PointerEventInfo
@@ -43,8 +43,7 @@ class GridColumnIcons(Enum):
43
43
  Uri = "uri"
44
44
  VideoUri = "video_uri"
45
45
 
46
- @dataclasses.dataclass
47
- class DataEditorThemeBase:
46
+ class DataEditorTheme(Base):
48
47
  accent_color: str | None
49
48
  accent_fg: str | None
50
49
  accent_light: str | None
@@ -78,9 +77,6 @@ class DataEditorThemeBase:
78
77
  text_light: str | None
79
78
  text_medium: str | None
80
79
 
81
- @dataclasses.dataclass(init=False)
82
- class DataEditorTheme(DataEditorThemeBase): ...
83
-
84
80
  class Bounds(TypedDict):
85
81
  x: int
86
82
  y: int
@@ -3,10 +3,10 @@
3
3
  # ------------------- DO NOT EDIT ----------------------
4
4
  # This file was generated by `reflex/utils/pyi_generator.py`!
5
5
  # ------------------------------------------------------
6
- import dataclasses
7
6
  from collections.abc import Mapping, Sequence
8
7
  from typing import Any, Literal, overload
9
8
 
9
+ from reflex.base import Base
10
10
  from reflex.components.component import Component, ComponentNamespace
11
11
  from reflex.components.core.breakpoints import Breakpoints
12
12
  from reflex.components.lucide.icon import Icon
@@ -32,8 +32,7 @@ toast_ref = Var(
32
32
  _var_data=VarData(imports={f"$/{Dirs.STATE_PATH}": [ImportVar(tag="refs")]}),
33
33
  )
34
34
 
35
- @dataclasses.dataclass
36
- class ToastAction:
35
+ class ToastAction(Base):
37
36
  label: str
38
37
  on_click: Any
39
38
 
@@ -204,3 +204,10 @@ class SpecialAttributes(enum.Enum):
204
204
  True if the attribute is special.
205
205
  """
206
206
  return attr.startswith(SPECIAL_ATTRS)
207
+
208
+
209
+ class ResetStylesheet(SimpleNamespace):
210
+ """Constants for CSS reset stylesheet."""
211
+
212
+ # The filename of the CSS reset file.
213
+ FILENAME = "__reflex_style_reset.css"
@@ -130,6 +130,7 @@ class PackageJson(SimpleNamespace):
130
130
  "@react-router/node": cls._react_router_version,
131
131
  "serve": "14.2.4",
132
132
  "react": cls._react_version,
133
+ "react-helmet": "6.1.0",
133
134
  "react-dom": cls._react_version,
134
135
  "isbot": "5.1.26",
135
136
  "socket.io-client": "4.8.1",
reflex/environment.py CHANGED
@@ -69,7 +69,7 @@ def interpret_boolean_env(value: str, field_name: str) -> bool:
69
69
  return True
70
70
  if value.lower() in false_values:
71
71
  return False
72
- msg = f"Invalid boolean value: {value} for {field_name}"
72
+ msg = f"Invalid boolean value: {value!r} for {field_name}"
73
73
  raise EnvironmentVarValueError(msg)
74
74
 
75
75
 
@@ -89,7 +89,7 @@ def interpret_int_env(value: str, field_name: str) -> int:
89
89
  try:
90
90
  return int(value)
91
91
  except ValueError as ve:
92
- msg = f"Invalid integer value: {value} for {field_name}"
92
+ msg = f"Invalid integer value: {value!r} for {field_name}"
93
93
  raise EnvironmentVarValueError(msg) from ve
94
94
 
95
95
 
@@ -108,7 +108,7 @@ def interpret_existing_path_env(value: str, field_name: str) -> ExistingPath:
108
108
  """
109
109
  path = Path(value)
110
110
  if not path.exists():
111
- msg = f"Path does not exist: {path} for {field_name}"
111
+ msg = f"Path does not exist: {path!r} for {field_name}"
112
112
  raise EnvironmentVarValueError(msg)
113
113
  return path
114
114
 
@@ -143,7 +143,7 @@ def interpret_enum_env(value: str, field_type: GenericType, field_name: str) ->
143
143
  try:
144
144
  return field_type(value)
145
145
  except ValueError as ve:
146
- msg = f"Invalid enum value: {value} for {field_name}"
146
+ msg = f"Invalid enum value: {value!r} for {field_name}"
147
147
  raise EnvironmentVarValueError(msg) from ve
148
148
 
149
149
 
@@ -169,6 +169,8 @@ def interpret_env_var_value(
169
169
  msg = f"Union types are not supported for environment variables: {field_name}."
170
170
  raise ValueError(msg)
171
171
 
172
+ value = value.strip()
173
+
172
174
  if field_type is bool:
173
175
  return interpret_boolean_env(value, field_name)
174
176
  if field_type is str:
reflex/testing.py CHANGED
@@ -22,7 +22,7 @@ import types
22
22
  from collections.abc import AsyncIterator, Callable, Coroutine, Sequence
23
23
  from http.server import SimpleHTTPRequestHandler
24
24
  from pathlib import Path
25
- from typing import TYPE_CHECKING, Any, TypeVar
25
+ from typing import TYPE_CHECKING, Any, Literal, TypeVar
26
26
 
27
27
  import psutil
28
28
  import uvicorn
@@ -526,7 +526,7 @@ class AppHarness:
526
526
  target: Callable[[], T],
527
527
  timeout: TimeoutType = None,
528
528
  step: TimeoutType = None,
529
- ) -> T | bool:
529
+ ) -> T | Literal[False]:
530
530
  """Generic polling logic.
531
531
 
532
532
  Args:
@@ -544,9 +544,10 @@ class AppHarness:
544
544
  step = POLL_INTERVAL
545
545
  deadline = time.time() + timeout
546
546
  while time.time() < deadline:
547
- success = target()
548
- if success:
549
- return success
547
+ with contextlib.suppress(Exception):
548
+ success = target()
549
+ if success:
550
+ return success
550
551
  time.sleep(step)
551
552
  return False
552
553
 
@@ -850,35 +851,55 @@ class AppHarness:
850
851
  return state_manager.states
851
852
 
852
853
  @staticmethod
853
- def poll_for_result(
854
- f: Callable[[], T],
855
- exception: type[Exception] = Exception,
856
- max_attempts: int = 5,
857
- seconds_between_attempts: int = 1,
854
+ def poll_for_or_raise_timeout(
855
+ target: Callable[[], T],
856
+ timeout: TimeoutType = None,
857
+ step: TimeoutType = None,
858
858
  ) -> T:
859
- """Poll for a result from a function.
859
+ """Poll target callable for a truthy return value.
860
+
861
+ Like `_poll_for`, but raises a `TimeoutError` if the target does not
862
+ return a truthy value within the timeout.
860
863
 
861
864
  Args:
862
- f: function to call
863
- exception: exception to catch
864
- max_attempts: maximum number of attempts
865
- seconds_between_attempts: seconds to wait between
865
+ target: callable that returns truthy if polling condition is met.
866
+ timeout: max polling time
867
+ step: interval between checking target()
866
868
 
867
869
  Returns:
868
- Result of the function
870
+ return value of target() if truthy within timeout
869
871
 
870
872
  Raises:
871
- AssertionError: if the function does not return a value
873
+ TimeoutError: when target does not return a truthy value within timeout
872
874
  """
873
- attempts = 0
874
- while attempts < max_attempts:
875
- try:
876
- return f()
877
- except exception: # noqa: PERF203
878
- attempts += 1
879
- time.sleep(seconds_between_attempts)
880
- msg = "Function did not return a value"
881
- raise AssertionError(msg)
875
+ result = AppHarness._poll_for(
876
+ target=target,
877
+ timeout=timeout,
878
+ step=step,
879
+ )
880
+ if result is False:
881
+ msg = "Target did not return a truthy value while polling."
882
+ raise TimeoutError(msg)
883
+ return result
884
+
885
+ @staticmethod
886
+ def expect(
887
+ target: Callable[[], T],
888
+ timeout: TimeoutType = None,
889
+ step: TimeoutType = None,
890
+ ):
891
+ """Expect a target callable to return a truthy value within the timeout.
892
+
893
+ Args:
894
+ target: callable that returns truthy if polling condition is met.
895
+ timeout: max polling time
896
+ step: interval between checking target()
897
+ """
898
+ AppHarness.poll_for_or_raise_timeout(
899
+ target=target,
900
+ timeout=timeout,
901
+ step=step,
902
+ )
882
903
 
883
904
 
884
905
  class SimpleHTTPRequestHandlerCustomErrors(SimpleHTTPRequestHandler):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex
3
- Version: 0.8.0a2
3
+ Version: 0.8.0a4
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
@@ -2,11 +2,11 @@ reflex/__init__.py,sha256=S_nJPFaTYwyxSzfOpACFxlSe2Vc8rQGr5ZDeyRSDiYQ,10264
2
2
  reflex/__init__.pyi,sha256=xyNthKRk7NquzHFlg3FgBccSFya-YmmDmlh8SFecTIo,11167
3
3
  reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
4
4
  reflex/admin.py,sha256=Nbc38y-M8iaRBvh1W6DQu_D3kEhO8JFvxrog4q2cB_E,434
5
- reflex/app.py,sha256=_echcweBHf0Ys4V93XdoF5D_6JcnP4Zz2qGQmi-Pkas,75083
5
+ reflex/app.py,sha256=BNnBsOXZEgjsSl6qloKieYCES02_DDsr_5P9S7SZDVA,75447
6
6
  reflex/assets.py,sha256=l5O_mlrTprC0lF7Rc_McOe3a0OtSLnRdNl_PqCpDCBA,3431
7
7
  reflex/base.py,sha256=Oh664QL3fZEHErhUasFqP7fE4olYf1y-9Oj6uZI2FCU,1173
8
8
  reflex/config.py,sha256=7-OHwPa9UGlz8fxQx6SumT4netp6NgWRHJ3UvUL-opg,16631
9
- reflex/environment.py,sha256=kxgF-jvM5_PCuPWDdhZK-Zvsjdi9SOCRsWOrBP3yi-A,19750
9
+ reflex/environment.py,sha256=0Olf4Z0m6lZI0EnUBWXUPQtzd7ggKWkKKvwL5CcsnZo,19785
10
10
  reflex/event.py,sha256=IDjHAbbzMo7mNUiFKvgiR7sGlQ883B00rvmncVy5I-Q,69724
11
11
  reflex/model.py,sha256=xED7blemoiKxPFaOkCMrSayjjon7AJp8t5g459p7dGs,17646
12
12
  reflex/page.py,sha256=Bn8FTlUtjjKwUtpQA5r5eaWE_ZUb8i4XgrQi8FWbzNA,1880
@@ -15,7 +15,7 @@ reflex/reflex.py,sha256=eUP0GevShUc1nodfA5_ewB3hgefWU0_x166HGCY8QTs,21606
15
15
  reflex/route.py,sha256=7JXP7-dpqdbUS3iSEqQ5UjOHV3pNxD0wKn6BBCRQggQ,4078
16
16
  reflex/state.py,sha256=yM9bvTISBXpZqhP7gNcIBjBtAC9LCyyDSco9rlXDaNc,90976
17
17
  reflex/style.py,sha256=JxbXXA4MTnXrk0XHEoMBoNC7J-M2oL5Hl3W_QmXvmBg,13222
18
- reflex/testing.py,sha256=Qx7StvOsFn47ToE8vy97zb4e-kANiTDTjjHEbdhtgyg,38678
18
+ reflex/testing.py,sha256=KZ1MEagf3nR_KRug343aH8n5QSRmLQ2p-Pv-huApoZw,39414
19
19
  reflex/.templates/apps/blank/assets/favicon.ico,sha256=baxxgDAQ2V4-G5Q4S2yK5uUJTUGkv-AOWBQ0xd6myUo,4286
20
20
  reflex/.templates/apps/blank/code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  reflex/.templates/apps/blank/code/blank.py,sha256=UmGz7aDxGULYINwLgotQoj-9qqpy7EOfAEpLmOT7C_k,917
@@ -26,7 +26,7 @@ reflex/.templates/jinja/custom_components/demo_app.py.jinja2,sha256=ipbKtObNqQLc
26
26
  reflex/.templates/jinja/custom_components/pyproject.toml.jinja2,sha256=HG-k3pruUlMy7xYz339hgFkNMTLqB-C_FTLKkOgfBPM,630
27
27
  reflex/.templates/jinja/custom_components/src.py.jinja2,sha256=e80PwMI6NoeQtGJ0NXWhYrkqUe7jvvJTFuztYQe-R5w,2403
28
28
  reflex/.templates/jinja/web/package.json.jinja2,sha256=cS9M6ADYDoYL2Kc8m5dYhV8eDaehOXb6qK_IOijT3N0,673
29
- reflex/.templates/jinja/web/pages/_app.js.jinja2,sha256=SxG94qVWuP8VZrRvGiPIirhvP9HqNopzQg2AdDSaOfg,1451
29
+ reflex/.templates/jinja/web/pages/_app.js.jinja2,sha256=10Wdl_7klhhisXfSY604iK0z10HsW_2E4aY2_MJvPeE,1581
30
30
  reflex/.templates/jinja/web/pages/_document.js.jinja2,sha256=v_r79GPGKnw1g9Bg4lK9o_ow5AzBnvKdz0nv3OgJyzU,166
31
31
  reflex/.templates/jinja/web/pages/base_page.js.jinja2,sha256=nteivFZgOhgwxlPvejgaoxKTPGvDRb7_JAXhsZDZeLM,361
32
32
  reflex/.templates/jinja/web/pages/component.js.jinja2,sha256=1Pui62uSL7LYA7FXZrh9ZmhKH8vHYu663eR134hhsAY,86
@@ -43,11 +43,12 @@ reflex/.templates/web/.gitignore,sha256=3tT0CtVkCL09D_Y3Hd4myUgGcBuESeavCa0WHU5i
43
43
  reflex/.templates/web/jsconfig.json,sha256=rhQZZRBYxBWclFYTeU6UakzbGveM4qyRQZUpEAVhyqY,118
44
44
  reflex/.templates/web/postcss.config.js,sha256=6Hf540Ny078yfmJ_-tniZtmgHW6euyEyxO0zH-Y1EtQ,86
45
45
  reflex/.templates/web/react-router.config.js,sha256=5K1FBryYdPusn1nE513GwB5_5UdPzoyH8ZMANUbpodQ,84
46
- reflex/.templates/web/vite.config.js,sha256=rfhF8ttx3q6j6JzEAw_VqwauqvrAP8IMC27FLF47Zm4,755
46
+ reflex/.templates/web/vite.config.js,sha256=48pSybaKFRmbeR2n7ead5ppJZxEpDPJQUB8jD9jbfEM,890
47
47
  reflex/.templates/web/app/entry.client.js,sha256=2Jv-5SQWHhHmA07BP50f1ew1V-LOsX5VoLtSInnFDj8,264
48
48
  reflex/.templates/web/app/routes.js,sha256=GerImlcrkF3qnKxHBS_dgTEHmXOBVtSUHt1BvQWN1KI,315
49
49
  reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha256=dnDHW49imtdalZJQqj7J_u7cj2z8Sve7OlhtOO0FbKE,916
50
50
  reflex/.templates/web/components/shiki/code.js,sha256=4Es1pxsr-lX4hTQ5mglrwwC6O_SI-z-O60k03z8VFzQ,1144
51
+ reflex/.templates/web/styles/__reflex_style_reset.css,sha256=qbC6JIT643YEsvSQ0D7xBmWE5vXy94JGrKNihRuEjnA,8913
51
52
  reflex/.templates/web/utils/client_side_routing.js,sha256=zK_Se1BMjrAHvYqcGH1cu3_UfUhXJ5KxeSt8Xgg2-70,1619
52
53
  reflex/.templates/web/utils/react-theme.js,sha256=4CNLOcjLS5tiRp0TIgKK7trf8bSLWtmeDVhFP6BLe80,2349
53
54
  reflex/.templates/web/utils/state.js,sha256=Bz_D4G8faACDYY3AFtjyCrr8VniDSpV3dDcXVoIhG3g,34146
@@ -61,7 +62,7 @@ reflex/app_mixins/lifespan.py,sha256=9rrdVUY0nHyk3gj31WJm7mw6I7KHBNtvSs9tZdwUm4I
61
62
  reflex/app_mixins/middleware.py,sha256=BKhe0jUFO1_TylEC48LUZyaeYyPmAYW-NV4H5Rw221k,2848
62
63
  reflex/app_mixins/mixin.py,sha256=R1YncalqDrbdPZvpKVbm72ZKmQZxYAWfuFq9JknzTqQ,305
63
64
  reflex/compiler/__init__.py,sha256=r8jqmDSFf09iV2lHlNhfc9XrTLjNxfDNwPYlxS4cmHE,27
64
- reflex/compiler/compiler.py,sha256=YRVoN2FqHZEZ8B6wOSYrTXjA-7nIjDJEgP3v2FtGIiU,29307
65
+ reflex/compiler/compiler.py,sha256=FI3E2n4gO-NJYwc02V9vDIKmnto9tyy0gV6pq0XZSok,29804
65
66
  reflex/compiler/templates.py,sha256=mQifVgvE7cKyzMFL9F5jxdJb9KFxucWJa7nuOp09ZUo,6002
66
67
  reflex/compiler/utils.py,sha256=FrO_nnWab847kwvkKSWUA2tXcd766Q9H0ZEALdH7f2E,18239
67
68
  reflex/components/__init__.py,sha256=55uockd2mEBsaA-fmDO_R4vJewzGPZUk-6UZFNHBSdc,568
@@ -124,7 +125,7 @@ reflex/components/datadisplay/__init__.pyi,sha256=rYMwO_X4NvUex6IL2MMTnhdFRp8Lz5
124
125
  reflex/components/datadisplay/code.py,sha256=jmt5pCFnHbbx8JzU5LvevwDL6omlIsdf_AbPsW7s5TI,12418
125
126
  reflex/components/datadisplay/code.pyi,sha256=fp-__tDq6lfjDetBsKq5KVZv2SXzFuK8Z3E41_FGwsA,41575
126
127
  reflex/components/datadisplay/dataeditor.py,sha256=SxvIDyKl9TILOlx6Zga9jCcu0LBc4E1WhrUFJGO6lKs,13496
127
- reflex/components/datadisplay/dataeditor.pyi,sha256=-Z1CmQSf7bsuaMC0okNqsALx8bF76UHkxlwMyVZcWSQ,12470
128
+ reflex/components/datadisplay/dataeditor.pyi,sha256=URCSl_0xAj0AF2yObFenNc76kO14YO9Xikq5Ec347lA,12375
128
129
  reflex/components/datadisplay/logo.py,sha256=xvg5TRVRSi2IKn7Kg4oYzWcaFMHfXxUaCp0cQmuKSn0,1993
129
130
  reflex/components/datadisplay/shiki_code_block.py,sha256=KmohJnAYo6gPERhBT_6o90bzgi6TLQ-AajRVeEcavbQ,24392
130
131
  reflex/components/datadisplay/shiki_code_block.pyi,sha256=iU3sH_KEGBg5R3qwvh0fXG2gP2bw8uX_83--KE2gxQg,57393
@@ -323,7 +324,7 @@ reflex/components/recharts/recharts.py,sha256=jrKDiTpIYVDli2s58xmD-ZvCvQupoRilsm
323
324
  reflex/components/recharts/recharts.pyi,sha256=2RoCZ3gbIcSXOVflgHcL8slbgZvL4KeICquG4edpd3A,7414
324
325
  reflex/components/sonner/__init__.py,sha256=L_mdRIy7-ccRGSz5VK6J8O-c-e-D1p9xWw29_ErrvGg,68
325
326
  reflex/components/sonner/toast.py,sha256=3wEwvI_2OyTdDcWJwwpyVeNox902iDQGv6Itgqv1Okw,12392
326
- reflex/components/sonner/toast.pyi,sha256=At5H-1ONwJ76E5R1TeyqM2j4FerXAeJOmM4cYYrCSRM,7835
327
+ reflex/components/sonner/toast.pyi,sha256=eL0uaBTRer4cqDYs2a6k1cmyxVVzOSYjdl8z6b8aCwM,7828
327
328
  reflex/components/tags/__init__.py,sha256=Pc0JU-Tv_W7KCsydXgbKmu7w2VtHNkI6Cx2hTkNhW_Q,152
328
329
  reflex/components/tags/cond_tag.py,sha256=YHxqq34PD-1D88YivO7kn7FsbW8SfPS2McNg7j_nncI,588
329
330
  reflex/components/tags/iter_tag.py,sha256=R7bOI3Xx3mHcSmr6tz8qUlBoDwXsAh2Q6Esd3nsBros,4410
@@ -333,11 +334,11 @@ reflex/components/tags/tagless.py,sha256=qO7Gm4V0ITDyymHkyltfz53155ZBt-W_WIPDYy9
333
334
  reflex/constants/__init__.py,sha256=q2Jf-LBbNcGrOmx5M7QotIAYW_t3m02TsmmdtJ5_IhM,2190
334
335
  reflex/constants/base.py,sha256=sFv9DhRZtEM2fix6U8SwTcBn05zl5Z_X8X-bqr3fh2E,9065
335
336
  reflex/constants/colors.py,sha256=n-FN7stNrvk5rCN0TAvE28dqwUeQZHue-b5q1CO0EyQ,2048
336
- reflex/constants/compiler.py,sha256=JjUL7myEoRi6-VRo5vxiND2WFaDTBbplfy6iLswazqk,5814
337
+ reflex/constants/compiler.py,sha256=y72_HbyHGyCVv_Xqr3hB3_Nu1p8NA4gUebBqL8cxY6Y,5987
337
338
  reflex/constants/config.py,sha256=8OIjiBdZZJrRVHsNBheMwopE9AwBFFzau0SXqXKcrPg,1715
338
339
  reflex/constants/custom_components.py,sha256=joJt4CEt1yKy7wsBH6vYo7_QRW0O_fWXrrTf0VY2q14,1317
339
340
  reflex/constants/event.py,sha256=tgoynWQi2L0_Kqc3XhXo7XXL76A-OKhJGHRrNjm7gFw,2885
340
- reflex/constants/installer.py,sha256=f4JgHgC0BiMEf72kykKjONBo62oURJvzt5hVYsvPw9A,4098
341
+ reflex/constants/installer.py,sha256=JjZcvXYxiABnnZnBBMMePr8C4279cECzfTRKxe7rHXs,4135
341
342
  reflex/constants/route.py,sha256=ZClrIF6Wog7tV3R2gLBrfLyO8Wc_jGZy2b1toy1f1Lk,2619
342
343
  reflex/constants/state.py,sha256=uF_7-M9Gid-P3DjAOq4F1ERplyZhiNccowo_jLrdJrg,323
343
344
  reflex/constants/utils.py,sha256=e1ChEvbHfmE_V2UJvCSUhD_qTVAIhEGPpRJSqdSd6PA,780
@@ -394,8 +395,8 @@ reflex/vars/number.py,sha256=tO7pnvFaBsedq1HWT4skytnSqHWMluGEhUbjAUMx8XQ,28190
394
395
  reflex/vars/object.py,sha256=BDmeiwG8v97s_BnR1Egq3NxOKVjv9TfnREB3cz0zZtk,17322
395
396
  reflex/vars/sequence.py,sha256=1kBrqihspyjyQ1XDqFPC8OpVGtZs_EVkOdIKBro5ilA,55249
396
397
  scripts/hatch_build.py,sha256=-4pxcLSFmirmujGpQX9UUxjhIC03tQ_fIQwVbHu9kc0,1861
397
- reflex-0.8.0a2.dist-info/METADATA,sha256=FpZZUmZMmqtA836969_GROu1CweV7js-7MVlmnEge8I,12344
398
- reflex-0.8.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
399
- reflex-0.8.0a2.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
400
- reflex-0.8.0a2.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
401
- reflex-0.8.0a2.dist-info/RECORD,,
398
+ reflex-0.8.0a4.dist-info/METADATA,sha256=GuSwEKBfkDC4zsLAodrNYn4J3INDnUcbhuf62Eu41vo,12344
399
+ reflex-0.8.0a4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
400
+ reflex-0.8.0a4.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
401
+ reflex-0.8.0a4.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
402
+ reflex-0.8.0a4.dist-info/RECORD,,