reflex 0.7.0a3__py3-none-any.whl → 0.7.0a5__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/app.py CHANGED
@@ -99,7 +99,15 @@ from reflex.state import (
99
99
  _substate_key,
100
100
  code_uses_state_contexts,
101
101
  )
102
- from reflex.utils import codespaces, console, exceptions, format, prerequisites, types
102
+ from reflex.utils import (
103
+ codespaces,
104
+ console,
105
+ exceptions,
106
+ format,
107
+ path_ops,
108
+ prerequisites,
109
+ types,
110
+ )
103
111
  from reflex.utils.exec import is_prod_mode, is_testing_env
104
112
  from reflex.utils.imports import ImportVar
105
113
 
@@ -974,9 +982,10 @@ class App(MiddlewareMixin, LifespanMixin):
974
982
  should_compile = self._should_compile()
975
983
 
976
984
  if not should_compile:
977
- for route in self._unevaluated_pages:
978
- console.debug(f"Evaluating page: {route}")
979
- self._compile_page(route, save_page=should_compile)
985
+ with console.timing("Evaluate Pages (Backend)"):
986
+ for route in self._unevaluated_pages:
987
+ console.debug(f"Evaluating page: {route}")
988
+ self._compile_page(route, save_page=should_compile)
980
989
 
981
990
  # Add the optional endpoints (_upload)
982
991
  self._add_optional_endpoints()
@@ -1002,10 +1011,11 @@ class App(MiddlewareMixin, LifespanMixin):
1002
1011
  + adhoc_steps_without_executor,
1003
1012
  )
1004
1013
 
1005
- for route in self._unevaluated_pages:
1006
- console.debug(f"Evaluating page: {route}")
1007
- self._compile_page(route, save_page=should_compile)
1008
- progress.advance(task)
1014
+ with console.timing("Evaluate Pages (Frontend)"):
1015
+ for route in self._unevaluated_pages:
1016
+ console.debug(f"Evaluating page: {route}")
1017
+ self._compile_page(route, save_page=should_compile)
1018
+ progress.advance(task)
1009
1019
 
1010
1020
  # Add the optional endpoints (_upload)
1011
1021
  self._add_optional_endpoints()
@@ -1013,7 +1023,7 @@ class App(MiddlewareMixin, LifespanMixin):
1013
1023
  self._validate_var_dependencies()
1014
1024
  self._setup_overlay_component()
1015
1025
  self._setup_error_boundary()
1016
- if config.show_built_with_reflex:
1026
+ if is_prod_mode() and config.show_built_with_reflex:
1017
1027
  self._setup_sticky_badge()
1018
1028
 
1019
1029
  progress.advance(task)
@@ -1040,13 +1050,13 @@ class App(MiddlewareMixin, LifespanMixin):
1040
1050
  custom_components |= component._get_all_custom_components()
1041
1051
 
1042
1052
  # Perform auto-memoization of stateful components.
1043
- (
1044
- stateful_components_path,
1045
- stateful_components_code,
1046
- page_components,
1047
- ) = compiler.compile_stateful_components(self._pages.values())
1048
-
1049
- progress.advance(task)
1053
+ with console.timing("Auto-memoize StatefulComponents"):
1054
+ (
1055
+ stateful_components_path,
1056
+ stateful_components_code,
1057
+ page_components,
1058
+ ) = compiler.compile_stateful_components(self._pages.values())
1059
+ progress.advance(task)
1050
1060
 
1051
1061
  # Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State.
1052
1062
  if code_uses_state_contexts(stateful_components_code) and self._state is None:
@@ -1069,6 +1079,17 @@ class App(MiddlewareMixin, LifespanMixin):
1069
1079
 
1070
1080
  progress.advance(task)
1071
1081
 
1082
+ # Copy the assets.
1083
+ assets_src = Path.cwd() / constants.Dirs.APP_ASSETS
1084
+ if assets_src.is_dir():
1085
+ with console.timing("Copy assets"):
1086
+ path_ops.update_directory_tree(
1087
+ src=assets_src,
1088
+ dest=(
1089
+ Path.cwd() / prerequisites.get_web_dir() / constants.Dirs.PUBLIC
1090
+ ),
1091
+ )
1092
+
1072
1093
  # Use a forking process pool, if possible. Much faster, especially for large sites.
1073
1094
  # Fallback to ThreadPoolExecutor as something that will always work.
1074
1095
  executor = None
@@ -1121,9 +1142,10 @@ class App(MiddlewareMixin, LifespanMixin):
1121
1142
  _submit_work(compiler.remove_tailwind_from_postcss)
1122
1143
 
1123
1144
  # Wait for all compilation tasks to complete.
1124
- for future in concurrent.futures.as_completed(result_futures):
1125
- compile_results.append(future.result())
1126
- progress.advance(task)
1145
+ with console.timing("Compile to Javascript"):
1146
+ for future in concurrent.futures.as_completed(result_futures):
1147
+ compile_results.append(future.result())
1148
+ progress.advance(task)
1127
1149
 
1128
1150
  app_root = self._app_root(app_wrappers=app_wrappers)
1129
1151
 
@@ -1158,7 +1180,8 @@ class App(MiddlewareMixin, LifespanMixin):
1158
1180
  progress.stop()
1159
1181
 
1160
1182
  # Install frontend packages.
1161
- self._get_frontend_packages(all_imports)
1183
+ with console.timing("Install Frontend Packages"):
1184
+ self._get_frontend_packages(all_imports)
1162
1185
 
1163
1186
  # Setup the next.config.js
1164
1187
  transpile_packages = [
@@ -1184,8 +1207,9 @@ class App(MiddlewareMixin, LifespanMixin):
1184
1207
  # Remove pages that are no longer in the app.
1185
1208
  p.unlink()
1186
1209
 
1187
- for output_path, code in compile_results:
1188
- compiler_utils.write_page(output_path, code)
1210
+ with console.timing("Write to Disk"):
1211
+ for output_path, code in compile_results:
1212
+ compiler_utils.write_page(output_path, code)
1189
1213
 
1190
1214
  @contextlib.asynccontextmanager
1191
1215
  async def modify_state(self, token: str) -> AsyncIterator[BaseState]:
reflex/compiler/utils.py CHANGED
@@ -119,24 +119,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
119
119
  validate_imports(collapsed_import_dict)
120
120
  import_dicts = []
121
121
  for lib, fields in collapsed_import_dict.items():
122
- default, rest = compile_import_statement(fields)
123
-
124
122
  # prevent lib from being rendered on the page if all imports are non rendered kind
125
123
  if not any(f.render for f in fields):
126
124
  continue
127
125
 
128
- if not lib:
129
- if default:
130
- raise ValueError("No default field allowed for empty library.")
131
- if rest is None or len(rest) == 0:
132
- raise ValueError("No fields to import.")
133
- import_dicts.extend(get_import_dict(module) for module in sorted(rest))
134
- continue
126
+ lib_paths: dict[str, list[ImportVar]] = {}
127
+
128
+ for field in fields:
129
+ lib_paths.setdefault(field.package_path, []).append(field)
135
130
 
136
- # remove the version before rendering the package imports
137
- lib = format.format_library_name(lib)
131
+ compiled = {
132
+ path: compile_import_statement(fields) for path, fields in lib_paths.items()
133
+ }
134
+
135
+ for path, (default, rest) in compiled.items():
136
+ if not lib:
137
+ if default:
138
+ raise ValueError("No default field allowed for empty library.")
139
+ if rest is None or len(rest) == 0:
140
+ raise ValueError("No fields to import.")
141
+ import_dicts.extend(get_import_dict(module) for module in sorted(rest))
142
+ continue
143
+
144
+ # remove the version before rendering the package imports
145
+ formatted_lib = format.format_library_name(lib) + (
146
+ path if path != "/" else ""
147
+ )
138
148
 
139
- import_dicts.append(get_import_dict(lib, default, rest))
149
+ import_dicts.append(get_import_dict(formatted_lib, default, rest))
140
150
  return import_dicts
141
151
 
142
152
 
@@ -2,14 +2,12 @@
2
2
 
3
3
  from reflex.components.component import ComponentNamespace
4
4
  from reflex.components.core.colors import color
5
- from reflex.components.core.cond import color_mode_cond, cond
6
- from reflex.components.core.responsive import tablet_and_desktop
5
+ from reflex.components.core.cond import color_mode_cond
6
+ from reflex.components.core.responsive import desktop_only
7
7
  from reflex.components.el.elements.inline import A
8
8
  from reflex.components.el.elements.media import Path, Rect, Svg
9
9
  from reflex.components.radix.themes.typography.text import Text
10
- from reflex.experimental.client_state import ClientStateVar
11
10
  from reflex.style import Style
12
- from reflex.vars.base import Var, VarData
13
11
 
14
12
 
15
13
  class StickyLogo(Svg):
@@ -87,7 +85,7 @@ class StickyBadge(A):
87
85
  """
88
86
  return super().create(
89
87
  StickyLogo.create(),
90
- tablet_and_desktop(StickyLabel.create()),
88
+ desktop_only(StickyLabel.create()),
91
89
  href="https://reflex.dev",
92
90
  target="_blank",
93
91
  width="auto",
@@ -102,36 +100,12 @@ class StickyBadge(A):
102
100
  Returns:
103
101
  The style of the component.
104
102
  """
105
- is_localhost_cs = ClientStateVar.create(
106
- "is_localhost",
107
- default=True,
108
- global_ref=False,
109
- )
110
- localhost_hostnames = Var.create(
111
- ["localhost", "127.0.0.1", "[::1]"]
112
- ).guess_type()
113
- is_localhost_expr = localhost_hostnames.contains(
114
- Var("window.location.hostname", _var_type=str).guess_type(),
115
- )
116
- check_is_localhost = Var(
117
- f"useEffect(({is_localhost_cs}) => {is_localhost_cs.set}({is_localhost_expr}), [])",
118
- _var_data=VarData(
119
- imports={"react": "useEffect"},
120
- ),
121
- )
122
- is_localhost = is_localhost_cs.value._replace(
123
- merge_var_data=VarData.merge(
124
- check_is_localhost._get_all_var_data(),
125
- VarData(hooks={str(check_is_localhost): None}),
126
- ),
127
- )
128
103
  return Style(
129
104
  {
130
105
  "position": "fixed",
131
106
  "bottom": "1rem",
132
107
  "right": "1rem",
133
- # Do not show the badge on localhost.
134
- "display": cond(is_localhost, "none", "flex"),
108
+ "display": "flex",
135
109
  "flex-direction": "row",
136
110
  "gap": "0.375rem",
137
111
  "align-items": "center",
@@ -1,5 +1,32 @@
1
1
  """Plotly components."""
2
2
 
3
- from .plotly import Plotly
3
+ from reflex.components.component import ComponentNamespace
4
4
 
5
- plotly = Plotly.create
5
+ from .plotly import (
6
+ Plotly,
7
+ PlotlyBasic,
8
+ PlotlyCartesian,
9
+ PlotlyFinance,
10
+ PlotlyGeo,
11
+ PlotlyGl2d,
12
+ PlotlyGl3d,
13
+ PlotlyMapbox,
14
+ PlotlyStrict,
15
+ )
16
+
17
+
18
+ class PlotlyNamespace(ComponentNamespace):
19
+ """Plotly namespace."""
20
+
21
+ __call__ = Plotly.create
22
+ basic = PlotlyBasic.create
23
+ cartesian = PlotlyCartesian.create
24
+ geo = PlotlyGeo.create
25
+ gl2d = PlotlyGl2d.create
26
+ gl3d = PlotlyGl3d.create
27
+ finance = PlotlyFinance.create
28
+ mapbox = PlotlyMapbox.create
29
+ strict = PlotlyStrict.create
30
+
31
+
32
+ plotly = PlotlyNamespace()
@@ -10,6 +10,7 @@ from reflex.components.component import Component, NoSSRComponent
10
10
  from reflex.components.core.cond import color_mode_cond
11
11
  from reflex.event import EventHandler, no_args_event_spec
12
12
  from reflex.utils import console
13
+ from reflex.utils.imports import ImportDict, ImportVar
13
14
  from reflex.vars.base import LiteralVar, Var
14
15
 
15
16
  try:
@@ -278,3 +279,237 @@ const extractPoints = (points) => {
278
279
  # Spread the figure dict over props, nothing to merge.
279
280
  tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}"))
280
281
  return tag
282
+
283
+
284
+ CREATE_PLOTLY_COMPONENT: ImportDict = {
285
+ "react-plotly.js": [
286
+ ImportVar(
287
+ tag="createPlotlyComponent",
288
+ is_default=True,
289
+ package_path="/factory",
290
+ ),
291
+ ]
292
+ }
293
+
294
+
295
+ def dynamic_plotly_import(name: str, package: str) -> str:
296
+ """Create a dynamic import for a plotly component.
297
+
298
+ Args:
299
+ name: The name of the component.
300
+ package: The package path of the component.
301
+
302
+ Returns:
303
+ The dynamic import for the plotly component.
304
+ """
305
+ return f"""
306
+ const {name} = dynamic(() => import('{package}').then(mod => createPlotlyComponent(mod)), {{ssr: false}})
307
+ """
308
+
309
+
310
+ class PlotlyBasic(Plotly):
311
+ """Display a basic plotly graph."""
312
+
313
+ tag: str = "BasicPlotlyPlot"
314
+
315
+ library = "react-plotly.js@2.6.0"
316
+
317
+ lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.0"]
318
+
319
+ def add_imports(self) -> ImportDict | list[ImportDict]:
320
+ """Add imports for the plotly basic component.
321
+
322
+ Returns:
323
+ The imports for the plotly basic component.
324
+ """
325
+ return CREATE_PLOTLY_COMPONENT
326
+
327
+ def _get_dynamic_imports(self) -> str:
328
+ """Get the dynamic imports for the plotly basic component.
329
+
330
+ Returns:
331
+ The dynamic imports for the plotly basic component.
332
+ """
333
+ return dynamic_plotly_import(self.tag, "plotly.js-basic-dist-min")
334
+
335
+
336
+ class PlotlyCartesian(Plotly):
337
+ """Display a plotly cartesian graph."""
338
+
339
+ tag: str = "CartesianPlotlyPlot"
340
+
341
+ library = "react-plotly.js@2.6.0"
342
+
343
+ lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.0"]
344
+
345
+ def add_imports(self) -> ImportDict | list[ImportDict]:
346
+ """Add imports for the plotly cartesian component.
347
+
348
+ Returns:
349
+ The imports for the plotly cartesian component.
350
+ """
351
+ return CREATE_PLOTLY_COMPONENT
352
+
353
+ def _get_dynamic_imports(self) -> str:
354
+ """Get the dynamic imports for the plotly cartesian component.
355
+
356
+ Returns:
357
+ The dynamic imports for the plotly cartesian component.
358
+ """
359
+ return dynamic_plotly_import(self.tag, "plotly.js-cartesian-dist-min")
360
+
361
+
362
+ class PlotlyGeo(Plotly):
363
+ """Display a plotly geo graph."""
364
+
365
+ tag: str = "GeoPlotlyPlot"
366
+
367
+ library = "react-plotly.js@2.6.0"
368
+
369
+ lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.0"]
370
+
371
+ def add_imports(self) -> ImportDict | list[ImportDict]:
372
+ """Add imports for the plotly geo component.
373
+
374
+ Returns:
375
+ The imports for the plotly geo component.
376
+ """
377
+ return CREATE_PLOTLY_COMPONENT
378
+
379
+ def _get_dynamic_imports(self) -> str:
380
+ """Get the dynamic imports for the plotly geo component.
381
+
382
+ Returns:
383
+ The dynamic imports for the plotly geo component.
384
+ """
385
+ return dynamic_plotly_import(self.tag, "plotly.js-geo-dist-min")
386
+
387
+
388
+ class PlotlyGl3d(Plotly):
389
+ """Display a plotly 3d graph."""
390
+
391
+ tag: str = "Gl3dPlotlyPlot"
392
+
393
+ library = "react-plotly.js@2.6.0"
394
+
395
+ lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.0"]
396
+
397
+ def add_imports(self) -> ImportDict | list[ImportDict]:
398
+ """Add imports for the plotly 3d component.
399
+
400
+ Returns:
401
+ The imports for the plotly 3d component.
402
+ """
403
+ return CREATE_PLOTLY_COMPONENT
404
+
405
+ def _get_dynamic_imports(self) -> str:
406
+ """Get the dynamic imports for the plotly 3d component.
407
+
408
+ Returns:
409
+ The dynamic imports for the plotly 3d component.
410
+ """
411
+ return dynamic_plotly_import(self.tag, "plotly.js-gl3d-dist-min")
412
+
413
+
414
+ class PlotlyGl2d(Plotly):
415
+ """Display a plotly 2d graph."""
416
+
417
+ tag: str = "Gl2dPlotlyPlot"
418
+
419
+ library = "react-plotly.js@2.6.0"
420
+
421
+ lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.0"]
422
+
423
+ def add_imports(self) -> ImportDict | list[ImportDict]:
424
+ """Add imports for the plotly 2d component.
425
+
426
+ Returns:
427
+ The imports for the plotly 2d component.
428
+ """
429
+ return CREATE_PLOTLY_COMPONENT
430
+
431
+ def _get_dynamic_imports(self) -> str:
432
+ """Get the dynamic imports for the plotly 2d component.
433
+
434
+ Returns:
435
+ The dynamic imports for the plotly 2d component.
436
+ """
437
+ return dynamic_plotly_import(self.tag, "plotly.js-gl2d-dist-min")
438
+
439
+
440
+ class PlotlyMapbox(Plotly):
441
+ """Display a plotly mapbox graph."""
442
+
443
+ tag: str = "MapboxPlotlyPlot"
444
+
445
+ library = "react-plotly.js@2.6.0"
446
+
447
+ lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.0"]
448
+
449
+ def add_imports(self) -> ImportDict | list[ImportDict]:
450
+ """Add imports for the plotly mapbox component.
451
+
452
+ Returns:
453
+ The imports for the plotly mapbox component.
454
+ """
455
+ return CREATE_PLOTLY_COMPONENT
456
+
457
+ def _get_dynamic_imports(self) -> str:
458
+ """Get the dynamic imports for the plotly mapbox component.
459
+
460
+ Returns:
461
+ The dynamic imports for the plotly mapbox component.
462
+ """
463
+ return dynamic_plotly_import(self.tag, "plotly.js-mapbox-dist-min")
464
+
465
+
466
+ class PlotlyFinance(Plotly):
467
+ """Display a plotly finance graph."""
468
+
469
+ tag: str = "FinancePlotlyPlot"
470
+
471
+ library = "react-plotly.js@2.6.0"
472
+
473
+ lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.0"]
474
+
475
+ def add_imports(self) -> ImportDict | list[ImportDict]:
476
+ """Add imports for the plotly finance component.
477
+
478
+ Returns:
479
+ The imports for the plotly finance component.
480
+ """
481
+ return CREATE_PLOTLY_COMPONENT
482
+
483
+ def _get_dynamic_imports(self) -> str:
484
+ """Get the dynamic imports for the plotly finance component.
485
+
486
+ Returns:
487
+ The dynamic imports for the plotly finance component.
488
+ """
489
+ return dynamic_plotly_import(self.tag, "plotly.js-finance-dist-min")
490
+
491
+
492
+ class PlotlyStrict(Plotly):
493
+ """Display a plotly strict graph."""
494
+
495
+ tag: str = "StrictPlotlyPlot"
496
+
497
+ library = "react-plotly.js@2.6.0"
498
+
499
+ lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.0"]
500
+
501
+ def add_imports(self) -> ImportDict | list[ImportDict]:
502
+ """Add imports for the plotly strict component.
503
+
504
+ Returns:
505
+ The imports for the plotly strict component.
506
+ """
507
+ return CREATE_PLOTLY_COMPONENT
508
+
509
+ def _get_dynamic_imports(self) -> str:
510
+ """Get the dynamic imports for the plotly strict component.
511
+
512
+ Returns:
513
+ The dynamic imports for the plotly strict component.
514
+ """
515
+ return dynamic_plotly_import(self.tag, "plotly.js-strict-dist-min")