reflex 0.4.7a3__py3-none-any.whl → 0.4.8__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 (124) hide show
  1. reflex/.templates/web/utils/state.js +7 -1
  2. reflex/app.py +15 -1
  3. reflex/compiler/utils.py +1 -1
  4. reflex/components/base/body.pyi +0 -3
  5. reflex/components/base/document.pyi +0 -15
  6. reflex/components/base/fragment.pyi +0 -3
  7. reflex/components/base/head.pyi +0 -3
  8. reflex/components/base/link.pyi +0 -6
  9. reflex/components/base/meta.pyi +0 -12
  10. reflex/components/chakra/base.pyi +0 -6
  11. reflex/components/chakra/datadisplay/badge.pyi +0 -3
  12. reflex/components/chakra/datadisplay/code.pyi +0 -3
  13. reflex/components/chakra/datadisplay/divider.pyi +0 -3
  14. reflex/components/chakra/datadisplay/keyboard_key.pyi +0 -3
  15. reflex/components/chakra/datadisplay/list.pyi +0 -3
  16. reflex/components/chakra/datadisplay/stat.pyi +0 -15
  17. reflex/components/chakra/datadisplay/table.pyi +0 -12
  18. reflex/components/chakra/datadisplay/tag.pyi +0 -12
  19. reflex/components/chakra/disclosure/accordion.pyi +0 -12
  20. reflex/components/chakra/disclosure/tabs.pyi +0 -12
  21. reflex/components/chakra/disclosure/transition.pyi +0 -18
  22. reflex/components/chakra/disclosure/visuallyhidden.pyi +0 -3
  23. reflex/components/chakra/feedback/alert.pyi +0 -9
  24. reflex/components/chakra/feedback/circularprogress.pyi +0 -3
  25. reflex/components/chakra/feedback/progress.pyi +0 -3
  26. reflex/components/chakra/feedback/skeleton.pyi +0 -9
  27. reflex/components/chakra/feedback/spinner.pyi +0 -3
  28. reflex/components/chakra/forms/button.pyi +0 -6
  29. reflex/components/chakra/forms/checkbox.pyi +0 -6
  30. reflex/components/chakra/forms/colormodeswitch.pyi +0 -3
  31. reflex/components/chakra/forms/editable.pyi +0 -12
  32. reflex/components/chakra/forms/form.pyi +0 -9
  33. reflex/components/chakra/forms/iconbutton.pyi +0 -3
  34. reflex/components/chakra/forms/input.pyi +0 -15
  35. reflex/components/chakra/forms/numberinput.pyi +0 -12
  36. reflex/components/chakra/forms/pininput.py +1 -1
  37. reflex/components/chakra/forms/pininput.pyi +1 -4
  38. reflex/components/chakra/forms/radio.py +1 -1
  39. reflex/components/chakra/forms/radio.pyi +1 -1
  40. reflex/components/chakra/forms/rangeslider.py +1 -1
  41. reflex/components/chakra/forms/rangeslider.pyi +1 -10
  42. reflex/components/chakra/forms/slider.pyi +0 -12
  43. reflex/components/chakra/forms/switch.pyi +0 -3
  44. reflex/components/chakra/layout/aspect_ratio.pyi +0 -3
  45. reflex/components/chakra/layout/box.pyi +0 -3
  46. reflex/components/chakra/layout/card.pyi +0 -9
  47. reflex/components/chakra/layout/center.pyi +0 -9
  48. reflex/components/chakra/layout/container.pyi +0 -3
  49. reflex/components/chakra/layout/flex.pyi +0 -3
  50. reflex/components/chakra/layout/grid.pyi +0 -9
  51. reflex/components/chakra/layout/spacer.pyi +0 -3
  52. reflex/components/chakra/layout/stack.pyi +0 -9
  53. reflex/components/chakra/layout/wrap.pyi +0 -3
  54. reflex/components/chakra/media/avatar.pyi +0 -9
  55. reflex/components/chakra/media/icon.pyi +0 -3
  56. reflex/components/chakra/navigation/breadcrumb.pyi +0 -3
  57. reflex/components/chakra/navigation/linkoverlay.pyi +0 -6
  58. reflex/components/chakra/navigation/stepper.pyi +0 -24
  59. reflex/components/chakra/overlay/alertdialog.pyi +0 -18
  60. reflex/components/chakra/overlay/drawer.pyi +0 -18
  61. reflex/components/chakra/overlay/menu.pyi +0 -18
  62. reflex/components/chakra/overlay/modal.pyi +0 -18
  63. reflex/components/chakra/overlay/popover.pyi +0 -24
  64. reflex/components/chakra/overlay/tooltip.pyi +0 -3
  65. reflex/components/chakra/typography/heading.pyi +0 -3
  66. reflex/components/chakra/typography/highlight.pyi +0 -3
  67. reflex/components/chakra/typography/span.pyi +0 -3
  68. reflex/components/chakra/typography/text.pyi +0 -3
  69. reflex/components/component.py +61 -22
  70. reflex/components/core/client_side_routing.pyi +0 -6
  71. reflex/components/core/upload.py +3 -1
  72. reflex/components/core/upload.pyi +0 -3
  73. reflex/components/el/element.pyi +0 -3
  74. reflex/components/el/elements/base.pyi +0 -3
  75. reflex/components/el/elements/forms.pyi +0 -39
  76. reflex/components/el/elements/inline.pyi +0 -84
  77. reflex/components/el/elements/media.pyi +0 -42
  78. reflex/components/el/elements/metadata.pyi +0 -15
  79. reflex/components/el/elements/other.pyi +0 -21
  80. reflex/components/el/elements/scripts.pyi +0 -9
  81. reflex/components/el/elements/sectioning.pyi +0 -45
  82. reflex/components/el/elements/tables.pyi +0 -30
  83. reflex/components/el/elements/typography.pyi +0 -45
  84. reflex/components/gridjs/datatable.pyi +0 -3
  85. reflex/components/lucide/icon.pyi +0 -3
  86. reflex/components/next/base.pyi +0 -3
  87. reflex/components/next/link.pyi +0 -3
  88. reflex/components/plotly/plotly.pyi +0 -6
  89. reflex/components/radix/primitives/accordion.pyi +0 -3
  90. reflex/components/radix/primitives/base.pyi +0 -6
  91. reflex/components/radix/primitives/drawer.pyi +0 -21
  92. reflex/components/radix/primitives/form.pyi +0 -18
  93. reflex/components/radix/primitives/progress.pyi +0 -9
  94. reflex/components/radix/primitives/slider.pyi +0 -15
  95. reflex/components/radix/themes/base.pyi +0 -6
  96. reflex/components/react_player/audio.pyi +0 -3
  97. reflex/components/react_player/react_player.pyi +0 -3
  98. reflex/components/react_player/video.pyi +0 -3
  99. reflex/components/recharts/cartesian.pyi +0 -57
  100. reflex/components/recharts/general.pyi +0 -12
  101. reflex/components/recharts/polar.pyi +0 -18
  102. reflex/components/recharts/recharts.pyi +0 -3
  103. reflex/constants/__init__.py +2 -0
  104. reflex/constants/base.py +5 -0
  105. reflex/constants/compiler.py +2 -0
  106. reflex/constants/installer.py +4 -2
  107. reflex/event.py +7 -6
  108. reflex/experimental/__init__.py +2 -0
  109. reflex/experimental/misc.py +12 -0
  110. reflex/model.py +1 -1
  111. reflex/reflex.py +0 -1
  112. reflex/utils/compat.py +43 -0
  113. reflex/utils/console.py +10 -1
  114. reflex/utils/export.py +1 -3
  115. reflex/utils/imports.py +14 -1
  116. reflex/utils/prerequisites.py +71 -45
  117. reflex/utils/processes.py +41 -4
  118. reflex/utils/serializers.py +14 -0
  119. reflex/utils/types.py +1 -1
  120. {reflex-0.4.7a3.dist-info → reflex-0.4.8.dist-info}/METADATA +1 -1
  121. {reflex-0.4.7a3.dist-info → reflex-0.4.8.dist-info}/RECORD +124 -122
  122. {reflex-0.4.7a3.dist-info → reflex-0.4.8.dist-info}/WHEEL +1 -1
  123. {reflex-0.4.7a3.dist-info → reflex-0.4.8.dist-info}/LICENSE +0 -0
  124. {reflex-0.4.7a3.dist-info → reflex-0.4.8.dist-info}/entry_points.txt +0 -0
@@ -19,7 +19,7 @@ from datetime import datetime
19
19
  from fileinput import FileInput
20
20
  from pathlib import Path
21
21
  from types import ModuleType
22
- from typing import Callable, Optional
22
+ from typing import Callable, List, Optional
23
23
 
24
24
  import httpx
25
25
  import pkg_resources
@@ -35,6 +35,7 @@ from reflex.base import Base
35
35
  from reflex.compiler import templates
36
36
  from reflex.config import Config, get_config
37
37
  from reflex.utils import console, path_ops, processes
38
+ from reflex.utils.format import format_library_name
38
39
 
39
40
  CURRENTLY_INSTALLING_NODE = False
40
41
 
@@ -166,16 +167,13 @@ def get_bun_version() -> version.Version | None:
166
167
 
167
168
  def get_install_package_manager() -> str | None:
168
169
  """Get the package manager executable for installation.
169
- Currently on unix systems, bun is used for installation only.
170
+ Currently, bun is used for installation only.
170
171
 
171
172
  Returns:
172
173
  The path to the package manager.
173
174
  """
174
- # On Windows, we use npm instead of bun.
175
- if constants.IS_WINDOWS:
175
+ if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
176
176
  return get_package_manager()
177
-
178
- # On other platforms, we use bun.
179
177
  return get_config().bun_path
180
178
 
181
179
 
@@ -227,11 +225,12 @@ def get_app(reload: bool = False) -> ModuleType:
227
225
  return app
228
226
 
229
227
 
230
- def get_compiled_app(reload: bool = False) -> ModuleType:
228
+ def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
231
229
  """Get the app module based on the default config after first compiling it.
232
230
 
233
231
  Args:
234
232
  reload: Re-import the app module from disk
233
+ export: Compile the app for export
235
234
 
236
235
  Returns:
237
236
  The compiled app based on the default config.
@@ -241,7 +240,7 @@ def get_compiled_app(reload: bool = False) -> ModuleType:
241
240
  # For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
242
241
  # before compiling the app in a thread to avoid event loop error (REF-2172).
243
242
  app._apply_decorated_pages()
244
- app.compile_()
243
+ app.compile_(export=export)
245
244
  return app_module
246
245
 
247
246
 
@@ -562,28 +561,39 @@ def init_reflex_json(project_hash: int | None):
562
561
  path_ops.update_json_file(constants.Reflex.JSON, reflex_json)
563
562
 
564
563
 
565
- def update_next_config(export=False):
564
+ def update_next_config(export=False, transpile_packages: Optional[List[str]] = None):
566
565
  """Update Next.js config from Reflex config.
567
566
 
568
567
  Args:
569
568
  export: if the method run during reflex export.
569
+ transpile_packages: list of packages to transpile via next.config.js.
570
570
  """
571
- next_config_file = os.path.join(constants.Dirs.WEB, constants.Next.CONFIG_FILE)
571
+ next_config_file = Path(constants.Dirs.WEB, constants.Next.CONFIG_FILE)
572
572
 
573
- next_config = _update_next_config(get_config(), export=export)
573
+ next_config = _update_next_config(
574
+ get_config(), export=export, transpile_packages=transpile_packages
575
+ )
574
576
 
575
- with open(next_config_file, "w") as file:
576
- file.write(next_config)
577
- file.write("\n")
577
+ # Overwriting the next.config.js triggers a full server reload, so make sure
578
+ # there is actually a diff.
579
+ orig_next_config = next_config_file.read_text() if next_config_file.exists() else ""
580
+ if orig_next_config != next_config:
581
+ next_config_file.write_text(next_config)
578
582
 
579
583
 
580
- def _update_next_config(config, export=False):
584
+ def _update_next_config(
585
+ config: Config, export: bool = False, transpile_packages: Optional[List[str]] = None
586
+ ):
581
587
  next_config = {
582
588
  "basePath": config.frontend_path or "",
583
589
  "compress": config.next_compression,
584
590
  "reactStrictMode": True,
585
591
  "trailingSlash": True,
586
592
  }
593
+ if transpile_packages:
594
+ next_config["transpilePackages"] = list(
595
+ set((format_library_name(p) for p in transpile_packages))
596
+ )
587
597
  if export:
588
598
  next_config["output"] = "export"
589
599
  next_config["distDir"] = constants.Dirs.STATIC
@@ -718,10 +728,10 @@ def install_bun():
718
728
  Raises:
719
729
  FileNotFoundError: If required packages are not found.
720
730
  """
721
- # Bun is not supported on Windows.
722
- if constants.IS_WINDOWS:
723
- console.debug("Skipping bun installation on Windows.")
724
- return
731
+ if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
732
+ console.warn(
733
+ "Bun for Windows is currently only available for x86 64-bit Windows. Installation will fall back on npm."
734
+ )
725
735
 
726
736
  # Skip if bun is already installed.
727
737
  if os.path.exists(get_config().bun_path) and get_bun_version() == version.parse(
@@ -731,16 +741,25 @@ def install_bun():
731
741
  return
732
742
 
733
743
  # if unzip is installed
734
- unzip_path = path_ops.which("unzip")
735
- if unzip_path is None:
736
- raise FileNotFoundError("Reflex requires unzip to be installed.")
737
-
738
- # Run the bun install script.
739
- download_and_run(
740
- constants.Bun.INSTALL_URL,
741
- f"bun-v{constants.Bun.VERSION}",
742
- BUN_INSTALL=constants.Bun.ROOT_PATH,
743
- )
744
+ if constants.IS_WINDOWS:
745
+ processes.new_process(
746
+ ["powershell", "-c", f"irm {constants.Bun.INSTALL_URL}.ps1|iex"],
747
+ env={"BUN_INSTALL": constants.Bun.ROOT_PATH},
748
+ shell=True,
749
+ run=True,
750
+ show_logs=console.is_debug(),
751
+ )
752
+ else:
753
+ unzip_path = path_ops.which("unzip")
754
+ if unzip_path is None:
755
+ raise FileNotFoundError("Reflex requires unzip to be installed.")
756
+
757
+ # Run the bun install script.
758
+ download_and_run(
759
+ constants.Bun.INSTALL_URL,
760
+ f"bun-v{constants.Bun.VERSION}",
761
+ BUN_INSTALL=constants.Bun.ROOT_PATH,
762
+ )
744
763
 
745
764
 
746
765
  def _write_cached_procedure_file(payload: str, cache_file: str):
@@ -802,18 +821,22 @@ def install_frontend_packages(packages: set[str], config: Config):
802
821
  Example:
803
822
  >>> install_frontend_packages(["react", "react-dom"], get_config())
804
823
  """
805
- # Install the base packages.
806
- process = processes.new_process(
824
+ # unsupported archs will use npm anyway. so we dont have to run npm twice
825
+ fallback_command = (
826
+ get_package_manager()
827
+ if constants.IS_WINDOWS and constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE
828
+ else None
829
+ )
830
+ processes.run_process_with_fallback(
807
831
  [get_install_package_manager(), "install", "--loglevel", "silly"],
832
+ fallback=fallback_command,
833
+ show_status_message="Installing base frontend packages",
808
834
  cwd=constants.Dirs.WEB,
809
835
  shell=constants.IS_WINDOWS,
810
836
  )
811
837
 
812
- processes.show_status("Installing base frontend packages", process)
813
-
814
838
  if config.tailwind is not None:
815
- # install tailwind and tailwind plugins as dev dependencies.
816
- process = processes.new_process(
839
+ processes.run_process_with_fallback(
817
840
  [
818
841
  get_install_package_manager(),
819
842
  "add",
@@ -821,21 +844,21 @@ def install_frontend_packages(packages: set[str], config: Config):
821
844
  constants.Tailwind.VERSION,
822
845
  *((config.tailwind or {}).get("plugins", [])),
823
846
  ],
847
+ fallback=fallback_command,
848
+ show_status_message="Installing tailwind",
824
849
  cwd=constants.Dirs.WEB,
825
850
  shell=constants.IS_WINDOWS,
826
851
  )
827
- processes.show_status("Installing tailwind", process)
828
852
 
829
853
  # Install custom packages defined in frontend_packages
830
854
  if len(packages) > 0:
831
- process = processes.new_process(
855
+ processes.run_process_with_fallback(
832
856
  [get_install_package_manager(), "add", *packages],
857
+ fallback=fallback_command,
858
+ show_status_message="Installing frontend packages from config and components",
833
859
  cwd=constants.Dirs.WEB,
834
860
  shell=constants.IS_WINDOWS,
835
861
  )
836
- processes.show_status(
837
- "Installing frontend packages from config and components", process
838
- )
839
862
 
840
863
 
841
864
  def needs_reinit(frontend: bool = True) -> bool:
@@ -856,12 +879,16 @@ def needs_reinit(frontend: bool = True) -> bool:
856
879
  )
857
880
  raise typer.Exit(1)
858
881
 
882
+ # Don't need to reinit if not running in frontend mode.
883
+ if not frontend:
884
+ return False
885
+
859
886
  # Make sure the .reflex directory exists.
860
887
  if not os.path.exists(constants.Reflex.DIR):
861
888
  return True
862
889
 
863
890
  # Make sure the .web directory exists in frontend mode.
864
- if frontend and not os.path.exists(constants.Dirs.WEB):
891
+ if not os.path.exists(constants.Dirs.WEB):
865
892
  return True
866
893
 
867
894
  if constants.IS_WINDOWS:
@@ -938,9 +965,6 @@ def validate_frontend_dependencies(init=True):
938
965
  )
939
966
  raise typer.Exit(1)
940
967
 
941
- if constants.IS_WINDOWS:
942
- return
943
-
944
968
  if init:
945
969
  # we only need bun for package install on `reflex init`.
946
970
  validate_bun()
@@ -1369,7 +1393,9 @@ def initialize_app(app_name: str, template: str | None = None):
1369
1393
  else:
1370
1394
  # Check if the template is a github repo.
1371
1395
  if template.startswith("https://github.com"):
1372
- template_url = f"{template.strip('/')}/archive/main.zip"
1396
+ template_url = (
1397
+ f"{template.strip('/').replace('.git', '')}/archive/main.zip"
1398
+ )
1373
1399
  else:
1374
1400
  console.error(f"Template `{template}` not found.")
1375
1401
  raise typer.Exit(1)
reflex/utils/processes.py CHANGED
@@ -202,13 +202,19 @@ def run_concurrently(*fns: Union[Callable, Tuple]) -> None:
202
202
  pass
203
203
 
204
204
 
205
- def stream_logs(message: str, process: subprocess.Popen, progress=None):
205
+ def stream_logs(
206
+ message: str,
207
+ process: subprocess.Popen,
208
+ progress=None,
209
+ suppress_errors: bool = False,
210
+ ):
206
211
  """Stream the logs for a process.
207
212
 
208
213
  Args:
209
214
  message: The message to display.
210
215
  process: The process.
211
216
  progress: The ongoing progress bar if one is being used.
217
+ suppress_errors: If True, do not exit if errors are encountered (for fallback).
212
218
 
213
219
  Yields:
214
220
  The lines of the process output.
@@ -232,7 +238,7 @@ def stream_logs(message: str, process: subprocess.Popen, progress=None):
232
238
  # Windows uvicorn bug
233
239
  # https://github.com/reflex-dev/reflex/issues/2335
234
240
  accepted_return_codes = [0, -2, 15] if constants.IS_WINDOWS else [0, -2]
235
- if process.returncode not in accepted_return_codes:
241
+ if process.returncode not in accepted_return_codes and not suppress_errors:
236
242
  console.error(f"{message} failed with exit code {process.returncode}")
237
243
  for line in logs:
238
244
  console.error(line, end="")
@@ -251,15 +257,16 @@ def show_logs(message: str, process: subprocess.Popen):
251
257
  pass
252
258
 
253
259
 
254
- def show_status(message: str, process: subprocess.Popen):
260
+ def show_status(message: str, process: subprocess.Popen, suppress_errors: bool = False):
255
261
  """Show the status of a process.
256
262
 
257
263
  Args:
258
264
  message: The initial message to display.
259
265
  process: The process.
266
+ suppress_errors: If True, do not exit if errors are encountered (for fallback).
260
267
  """
261
268
  with console.status(message) as status:
262
- for line in stream_logs(message, process):
269
+ for line in stream_logs(message, process, suppress_errors=suppress_errors):
263
270
  status.update(f"{message} {line}")
264
271
 
265
272
 
@@ -287,3 +294,33 @@ def show_progress(message: str, process: subprocess.Popen, checkpoints: List[str
287
294
  def atexit_handler():
288
295
  """Display a custom message with the current time when exiting an app."""
289
296
  console.log("Reflex app stopped.")
297
+
298
+
299
+ def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwargs):
300
+ """Run subprocess and retry using fallback command if initial command fails.
301
+
302
+ Args:
303
+ args: A string, or a sequence of program arguments.
304
+ show_status_message: The status message to be displayed in the console.
305
+ fallback: The fallback command to run.
306
+ kwargs: Kwargs to pass to new_process function.
307
+ """
308
+ process = new_process(args, **kwargs)
309
+ if fallback is None:
310
+ # No fallback given, or this _is_ the fallback command.
311
+ show_status(show_status_message, process)
312
+ else:
313
+ # Suppress errors for initial command, because we will try to fallback
314
+ show_status(show_status_message, process, suppress_errors=True)
315
+ if process.returncode != 0:
316
+ # retry with fallback command.
317
+ fallback_args = [fallback, *args[1:]]
318
+ console.warn(
319
+ f"There was an error running command: {args}. Falling back to: {fallback_args}."
320
+ )
321
+ run_process_with_fallback(
322
+ fallback_args,
323
+ show_status_message=show_status_message,
324
+ fallback=None,
325
+ **kwargs,
326
+ )
@@ -6,6 +6,7 @@ import json
6
6
  import types as builtin_types
7
7
  import warnings
8
8
  from datetime import date, datetime, time, timedelta
9
+ from enum import Enum
9
10
  from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union, get_type_hints
10
11
 
11
12
  from reflex.base import Base
@@ -232,6 +233,19 @@ def serialize_datetime(dt: Union[date, datetime, time, timedelta]) -> str:
232
233
  return str(dt)
233
234
 
234
235
 
236
+ @serializer
237
+ def serialize_enum(en: Enum) -> str:
238
+ """Serialize a enum to a JSON string.
239
+
240
+ Args:
241
+ en: The enum to serialize.
242
+
243
+ Returns:
244
+ The serialized enum.
245
+ """
246
+ return en.value
247
+
248
+
235
249
  @serializer
236
250
  def serialize_color(color: Color) -> str:
237
251
  """Serialize a color.
reflex/utils/types.py CHANGED
@@ -29,7 +29,7 @@ try:
29
29
  # reflex-hosting-cli tools are compatible with pydantic v2
30
30
 
31
31
  if not TYPE_CHECKING:
32
- import pydantic.v1.fields as ModelField
32
+ from pydantic.v1.fields import ModelField
33
33
  else:
34
34
  raise ModuleNotFoundError
35
35
  except ModuleNotFoundError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex
3
- Version: 0.4.7a3
3
+ Version: 0.4.8
4
4
  Summary: Web apps in pure Python.
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0