reflex 0.7.4a2__py3-none-any.whl → 0.7.5__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 (162) hide show
  1. reflex/__init__.py +1 -0
  2. reflex/__init__.pyi +1 -0
  3. reflex/app.py +10 -8
  4. reflex/app_mixins/middleware.py +13 -20
  5. reflex/compiler/compiler.py +10 -3
  6. reflex/compiler/utils.py +4 -4
  7. reflex/components/base/app_wrap.pyi +7 -3
  8. reflex/components/base/body.pyi +7 -3
  9. reflex/components/base/document.pyi +27 -7
  10. reflex/components/base/error_boundary.pyi +7 -3
  11. reflex/components/base/fragment.pyi +7 -3
  12. reflex/components/base/head.pyi +12 -4
  13. reflex/components/base/link.pyi +12 -4
  14. reflex/components/base/meta.pyi +22 -6
  15. reflex/components/base/script.pyi +7 -3
  16. reflex/components/base/strict_mode.pyi +7 -3
  17. reflex/components/component.py +64 -23
  18. reflex/components/core/auto_scroll.pyi +7 -3
  19. reflex/components/core/banner.py +6 -2
  20. reflex/components/core/banner.pyi +32 -8
  21. reflex/components/core/client_side_routing.pyi +12 -4
  22. reflex/components/core/clipboard.pyi +7 -3
  23. reflex/components/core/debounce.pyi +7 -3
  24. reflex/components/core/foreach.py +5 -1
  25. reflex/components/core/html.pyi +7 -3
  26. reflex/components/core/match.py +5 -5
  27. reflex/components/core/sticky.pyi +21 -6
  28. reflex/components/core/upload.pyi +27 -7
  29. reflex/components/datadisplay/code.pyi +12 -4
  30. reflex/components/datadisplay/dataeditor.py +2 -2
  31. reflex/components/datadisplay/dataeditor.pyi +17 -3
  32. reflex/components/datadisplay/shiki_code_block.pyi +17 -4
  33. reflex/components/el/__init__.pyi +1 -1
  34. reflex/components/el/element.pyi +7 -3
  35. reflex/components/el/elements/__init__.py +3 -1
  36. reflex/components/el/elements/__init__.pyi +3 -2
  37. reflex/components/el/elements/base.pyi +7 -3
  38. reflex/components/el/elements/forms.py +1 -1
  39. reflex/components/el/elements/forms.pyi +72 -16
  40. reflex/components/el/elements/inline.pyi +142 -30
  41. reflex/components/el/elements/media.pyi +127 -27
  42. reflex/components/el/elements/metadata.pyi +32 -8
  43. reflex/components/el/elements/other.pyi +37 -9
  44. reflex/components/el/elements/scripts.pyi +17 -5
  45. reflex/components/el/elements/sectioning.pyi +77 -17
  46. reflex/components/el/elements/tables.pyi +52 -12
  47. reflex/components/el/elements/typography.pyi +77 -17
  48. reflex/components/gridjs/datatable.py +2 -2
  49. reflex/components/gridjs/datatable.pyi +12 -4
  50. reflex/components/lucide/icon.py +7 -6
  51. reflex/components/lucide/icon.pyi +22 -7
  52. reflex/components/markdown/markdown.py +1 -1
  53. reflex/components/markdown/markdown.pyi +7 -3
  54. reflex/components/moment/moment.pyi +7 -3
  55. reflex/components/next/base.pyi +7 -3
  56. reflex/components/next/image.pyi +7 -3
  57. reflex/components/next/link.pyi +7 -3
  58. reflex/components/next/video.pyi +7 -3
  59. reflex/components/plotly/plotly.pyi +47 -11
  60. reflex/components/radix/primitives/accordion.pyi +37 -9
  61. reflex/components/radix/primitives/base.pyi +12 -4
  62. reflex/components/radix/primitives/drawer.pyi +57 -13
  63. reflex/components/radix/primitives/form.pyi +52 -12
  64. reflex/components/radix/primitives/progress.pyi +27 -7
  65. reflex/components/radix/primitives/slider.pyi +27 -7
  66. reflex/components/radix/themes/base.pyi +41 -10
  67. reflex/components/radix/themes/color_mode.py +2 -2
  68. reflex/components/radix/themes/color_mode.pyi +17 -5
  69. reflex/components/radix/themes/components/alert_dialog.pyi +36 -9
  70. reflex/components/radix/themes/components/aspect_ratio.pyi +7 -3
  71. reflex/components/radix/themes/components/avatar.pyi +6 -3
  72. reflex/components/radix/themes/components/badge.pyi +6 -3
  73. reflex/components/radix/themes/components/button.pyi +6 -3
  74. reflex/components/radix/themes/components/callout.pyi +26 -7
  75. reflex/components/radix/themes/components/card.pyi +6 -3
  76. reflex/components/radix/themes/components/checkbox.pyi +16 -5
  77. reflex/components/radix/themes/components/checkbox_cards.pyi +11 -4
  78. reflex/components/radix/themes/components/checkbox_group.pyi +11 -4
  79. reflex/components/radix/themes/components/context_menu.pyi +66 -15
  80. reflex/components/radix/themes/components/data_list.pyi +21 -6
  81. reflex/components/radix/themes/components/dialog.pyi +36 -9
  82. reflex/components/radix/themes/components/dropdown_menu.pyi +41 -10
  83. reflex/components/radix/themes/components/hover_card.pyi +21 -6
  84. reflex/components/radix/themes/components/icon_button.pyi +6 -3
  85. reflex/components/radix/themes/components/inset.pyi +6 -3
  86. reflex/components/radix/themes/components/popover.pyi +21 -6
  87. reflex/components/radix/themes/components/progress.pyi +6 -3
  88. reflex/components/radix/themes/components/radio.pyi +6 -3
  89. reflex/components/radix/themes/components/radio_cards.pyi +11 -4
  90. reflex/components/radix/themes/components/radio_group.py +6 -1
  91. reflex/components/radix/themes/components/radio_group.pyi +21 -6
  92. reflex/components/radix/themes/components/scroll_area.pyi +7 -3
  93. reflex/components/radix/themes/components/segmented_control.pyi +11 -4
  94. reflex/components/radix/themes/components/select.pyi +46 -11
  95. reflex/components/radix/themes/components/separator.pyi +6 -3
  96. reflex/components/radix/themes/components/skeleton.pyi +6 -3
  97. reflex/components/radix/themes/components/slider.pyi +6 -3
  98. reflex/components/radix/themes/components/spinner.pyi +6 -3
  99. reflex/components/radix/themes/components/switch.pyi +6 -3
  100. reflex/components/radix/themes/components/table.pyi +36 -9
  101. reflex/components/radix/themes/components/tabs.pyi +26 -7
  102. reflex/components/radix/themes/components/text_area.pyi +6 -3
  103. reflex/components/radix/themes/components/text_field.py +3 -2
  104. reflex/components/radix/themes/components/text_field.pyi +16 -5
  105. reflex/components/radix/themes/components/tooltip.pyi +7 -3
  106. reflex/components/radix/themes/layout/base.pyi +6 -3
  107. reflex/components/radix/themes/layout/box.pyi +7 -3
  108. reflex/components/radix/themes/layout/center.pyi +6 -3
  109. reflex/components/radix/themes/layout/container.pyi +6 -3
  110. reflex/components/radix/themes/layout/flex.pyi +6 -3
  111. reflex/components/radix/themes/layout/grid.pyi +6 -3
  112. reflex/components/radix/themes/layout/list.pyi +27 -7
  113. reflex/components/radix/themes/layout/section.pyi +6 -3
  114. reflex/components/radix/themes/layout/spacer.pyi +6 -3
  115. reflex/components/radix/themes/layout/stack.pyi +16 -5
  116. reflex/components/radix/themes/typography/blockquote.pyi +6 -3
  117. reflex/components/radix/themes/typography/code.pyi +6 -3
  118. reflex/components/radix/themes/typography/heading.pyi +6 -3
  119. reflex/components/radix/themes/typography/link.pyi +6 -3
  120. reflex/components/radix/themes/typography/text.pyi +36 -9
  121. reflex/components/react_player/audio.pyi +7 -3
  122. reflex/components/react_player/react_player.pyi +7 -3
  123. reflex/components/react_player/video.pyi +7 -3
  124. reflex/components/recharts/cartesian.pyi +97 -21
  125. reflex/components/recharts/charts.pyi +62 -14
  126. reflex/components/recharts/general.pyi +32 -8
  127. reflex/components/recharts/polar.py +1 -1
  128. reflex/components/recharts/polar.pyi +33 -9
  129. reflex/components/recharts/recharts.pyi +12 -4
  130. reflex/components/sonner/toast.pyi +7 -2
  131. reflex/components/suneditor/editor.pyi +7 -3
  132. reflex/config.py +18 -1
  133. reflex/constants/installer.py +22 -1
  134. reflex/custom_components/custom_components.py +12 -7
  135. reflex/event.py +26 -10
  136. reflex/experimental/__init__.py +17 -6
  137. reflex/experimental/layout.pyi +27 -7
  138. reflex/model.py +3 -3
  139. reflex/reflex.py +33 -18
  140. reflex/state.py +4 -4
  141. reflex/style.py +2 -2
  142. reflex/testing.py +17 -5
  143. reflex/utils/console.py +2 -3
  144. reflex/utils/exec.py +4 -0
  145. reflex/utils/imports.py +14 -7
  146. reflex/utils/net.py +107 -18
  147. reflex/utils/prerequisites.py +92 -13
  148. reflex/utils/processes.py +52 -19
  149. reflex/utils/pyi_generator.py +66 -53
  150. reflex/utils/redir.py +3 -1
  151. reflex/utils/registry.py +15 -5
  152. reflex/utils/serializers.py +1 -2
  153. reflex/utils/types.py +4 -4
  154. reflex/vars/base.py +58 -22
  155. reflex/vars/number.py +23 -6
  156. reflex/vars/sequence.py +2 -0
  157. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/METADATA +2 -2
  158. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/RECORD +162 -162
  159. /reflex/{experimental → utils}/misc.py +0 -0
  160. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/WHEEL +0 -0
  161. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/entry_points.txt +0 -0
  162. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/licenses/LICENSE +0 -0
@@ -115,11 +115,13 @@ def check_latest_package_version(package_name: str):
115
115
  if environment.REFLEX_CHECK_LATEST_VERSION.get() is False:
116
116
  return
117
117
  try:
118
+ console.debug(f"Checking for the latest version of {package_name}...")
118
119
  # Get the latest version from PyPI
119
120
  current_version = importlib.metadata.version(package_name)
120
121
  url = f"https://pypi.org/pypi/{package_name}/json"
121
122
  response = net.get(url)
122
123
  latest_version = response.json()["info"]["version"]
124
+ console.debug(f"Latest version of {package_name}: {latest_version}")
123
125
  if get_or_set_last_reflex_version_check_datetime():
124
126
  # Versions were already checked and saved in reflex.json, no need to warn again
125
127
  return
@@ -129,6 +131,7 @@ def check_latest_package_version(package_name: str):
129
131
  f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
130
132
  )
131
133
  except Exception:
134
+ console.debug(f"Failed to check for the latest version of {package_name}.")
132
135
  pass
133
136
 
134
137
 
@@ -507,6 +510,9 @@ def compile_or_validate_app(compile: bool = False) -> bool:
507
510
  else:
508
511
  validate_app()
509
512
  except Exception as e:
513
+ if isinstance(e, typer.Exit):
514
+ return False
515
+
510
516
  import traceback
511
517
 
512
518
  sys_exception = sys.exception()
@@ -902,11 +908,12 @@ def initialize_app_directory(
902
908
 
903
909
  console.debug(f"Using {template_name=} {template_dir=} {template_code_dir_name=}.")
904
910
 
905
- # Remove all pyc and __pycache__ dirs in template directory.
906
- for pyc_file in template_dir.glob("**/*.pyc"):
907
- pyc_file.unlink()
908
- for pycache_dir in template_dir.glob("**/__pycache__"):
909
- pycache_dir.rmdir()
911
+ # Remove __pycache__ dirs in template directory and current directory.
912
+ for pycache_dir in [
913
+ *template_dir.glob("**/__pycache__"),
914
+ *Path.cwd().glob("**/__pycache__"),
915
+ ]:
916
+ shutil.rmtree(pycache_dir, ignore_errors=True)
910
917
 
911
918
  for file in template_dir.iterdir():
912
919
  # Copy the file to current directory but keep the name the same.
@@ -950,16 +957,25 @@ def initialize_web_directory():
950
957
  # Reuse the hash if one is already created, so we don't over-write it when running reflex init
951
958
  project_hash = get_project_hash()
952
959
 
960
+ console.debug(f"Copying {constants.Templates.Dirs.WEB_TEMPLATE} to {get_web_dir()}")
953
961
  path_ops.cp(constants.Templates.Dirs.WEB_TEMPLATE, str(get_web_dir()))
954
962
 
963
+ console.debug("Initializing the web directory.")
955
964
  initialize_package_json()
956
965
 
966
+ console.debug("Initializing the bun config file.")
957
967
  initialize_bun_config()
958
968
 
969
+ console.debug("Initializing the .npmrc file.")
970
+ initialize_npmrc()
971
+
972
+ console.debug("Initializing the public directory.")
959
973
  path_ops.mkdir(get_web_dir() / constants.Dirs.PUBLIC)
960
974
 
975
+ console.debug("Initializing the next.config.js file.")
961
976
  update_next_config()
962
977
 
978
+ console.debug("Initializing the reflex.json file.")
963
979
  # Initialize the reflex json file.
964
980
  init_reflex_json(project_hash=project_hash)
965
981
 
@@ -1002,6 +1018,20 @@ def initialize_bun_config():
1002
1018
  bun_config_path.write_text(bunfig_content)
1003
1019
 
1004
1020
 
1021
+ def initialize_npmrc():
1022
+ """Initialize the .npmrc file."""
1023
+ npmrc_path = get_web_dir() / constants.Node.CONFIG_PATH
1024
+
1025
+ if (custom_npmrc := Path(constants.Node.CONFIG_PATH)).exists():
1026
+ npmrc_content = custom_npmrc.read_text()
1027
+ console.info(f"Copying custom .npmrc inside {get_web_dir()} folder")
1028
+ else:
1029
+ best_registry = get_npm_registry()
1030
+ npmrc_content = constants.Node.DEFAULT_CONFIG.format(registry=best_registry)
1031
+
1032
+ npmrc_path.write_text(npmrc_content)
1033
+
1034
+
1005
1035
  def init_reflex_json(project_hash: int | None):
1006
1036
  """Write the hash of the Reflex project to a REFLEX_JSON.
1007
1037
 
@@ -1057,6 +1087,7 @@ def _update_next_config(
1057
1087
  "compress": config.next_compression,
1058
1088
  "trailingSlash": True,
1059
1089
  "staticPageGenerationTimeout": config.static_page_generation_timeout,
1090
+ "devIndicators": config.next_dev_indicators,
1060
1091
  }
1061
1092
  if transpile_packages:
1062
1093
  next_config["transpilePackages"] = list(
@@ -1170,26 +1201,39 @@ def _clear_cached_procedure_file(cache_file: str | Path):
1170
1201
  cache_file.unlink()
1171
1202
 
1172
1203
 
1173
- def cached_procedure(cache_file: str, payload_fn: Callable[..., str]):
1204
+ def cached_procedure(
1205
+ cache_file: str | None,
1206
+ payload_fn: Callable[..., str],
1207
+ cache_file_fn: Callable[[], str] | None = None,
1208
+ ):
1174
1209
  """Decorator to cache the runs of a procedure on disk. Procedures should not have
1175
1210
  a return value.
1176
1211
 
1177
1212
  Args:
1178
1213
  cache_file: The file to store the cache payload in.
1179
- payload_fn: Function that computes cache payload from function args
1214
+ payload_fn: Function that computes cache payload from function args.
1215
+ cache_file_fn: Function that computes the cache file name at runtime.
1180
1216
 
1181
1217
  Returns:
1182
1218
  The decorated function.
1219
+
1220
+ Raises:
1221
+ ValueError: If both cache_file and cache_file_fn are provided.
1183
1222
  """
1223
+ if cache_file and cache_file_fn is not None:
1224
+ raise ValueError("cache_file and cache_file_fn cannot both be provided.")
1184
1225
 
1185
1226
  def _inner_decorator(func: Callable):
1186
1227
  def _inner(*args, **kwargs):
1187
- payload = _read_cached_procedure_file(cache_file)
1228
+ _cache_file = cache_file_fn() if cache_file_fn is not None else cache_file
1229
+ if not _cache_file:
1230
+ raise ValueError("Unknown cache file, cannot cache result.")
1231
+ payload = _read_cached_procedure_file(_cache_file)
1188
1232
  new_payload = payload_fn(*args, **kwargs)
1189
1233
  if payload != new_payload:
1190
- _clear_cached_procedure_file(cache_file)
1234
+ _clear_cached_procedure_file(_cache_file)
1191
1235
  func(*args, **kwargs)
1192
- _write_cached_procedure_file(new_payload, cache_file)
1236
+ _write_cached_procedure_file(new_payload, _cache_file)
1193
1237
 
1194
1238
  return _inner
1195
1239
 
@@ -1197,8 +1241,11 @@ def cached_procedure(cache_file: str, payload_fn: Callable[..., str]):
1197
1241
 
1198
1242
 
1199
1243
  @cached_procedure(
1200
- cache_file=str(get_web_dir() / "reflex.install_frontend_packages.cached"),
1244
+ cache_file_fn=lambda: str(
1245
+ get_web_dir() / "reflex.install_frontend_packages.cached"
1246
+ ),
1201
1247
  payload_fn=lambda p, c: f"{sorted(p)!r},{c.json()}",
1248
+ cache_file=None,
1202
1249
  )
1203
1250
  def install_frontend_packages(packages: set[str], config: Config):
1204
1251
  """Installs the base and custom frontend packages.
@@ -1214,6 +1261,14 @@ def install_frontend_packages(packages: set[str], config: Config):
1214
1261
  raise_on_none=True
1215
1262
  )
1216
1263
 
1264
+ env = (
1265
+ {
1266
+ "NODE_TLS_REJECT_UNAUTHORIZED": "0",
1267
+ }
1268
+ if environment.SSL_NO_VERIFY.get()
1269
+ else {}
1270
+ )
1271
+
1217
1272
  primary_package_manager = install_package_managers[0]
1218
1273
  fallbacks = install_package_managers[1:]
1219
1274
 
@@ -1224,6 +1279,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1224
1279
  show_status_message="Installing base frontend packages",
1225
1280
  cwd=get_web_dir(),
1226
1281
  shell=constants.IS_WINDOWS,
1282
+ env=env,
1227
1283
  )
1228
1284
 
1229
1285
  if config.tailwind is not None:
@@ -1241,6 +1297,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1241
1297
  show_status_message="Installing tailwind",
1242
1298
  cwd=get_web_dir(),
1243
1299
  shell=constants.IS_WINDOWS,
1300
+ env=env,
1244
1301
  )
1245
1302
 
1246
1303
  # Install custom packages defined in frontend_packages
@@ -1252,6 +1309,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1252
1309
  show_status_message="Installing frontend packages from config and components",
1253
1310
  cwd=get_web_dir(),
1254
1311
  shell=constants.IS_WINDOWS,
1312
+ env=env,
1255
1313
  )
1256
1314
 
1257
1315
 
@@ -1392,6 +1450,7 @@ def ensure_reflex_installation_id() -> int | None:
1392
1450
  Distinct id.
1393
1451
  """
1394
1452
  try:
1453
+ console.debug("Ensuring reflex installation id.")
1395
1454
  initialize_reflex_user_directory()
1396
1455
  installation_id_file = environment.REFLEX_DIR.get() / "installation_id"
1397
1456
 
@@ -1418,6 +1477,7 @@ def ensure_reflex_installation_id() -> int | None:
1418
1477
 
1419
1478
  def initialize_reflex_user_directory():
1420
1479
  """Initialize the reflex user directory."""
1480
+ console.debug(f"Creating {environment.REFLEX_DIR.get()}")
1421
1481
  # Create the reflex directory.
1422
1482
  path_ops.mkdir(environment.REFLEX_DIR.get())
1423
1483
 
@@ -1425,9 +1485,11 @@ def initialize_reflex_user_directory():
1425
1485
  def initialize_frontend_dependencies():
1426
1486
  """Initialize all the frontend dependencies."""
1427
1487
  # validate dependencies before install
1488
+ console.debug("Validating frontend dependencies.")
1428
1489
  validate_frontend_dependencies()
1429
1490
  # Install the frontend dependencies.
1430
- processes.run_concurrently(install_bun)
1491
+ console.debug("Installing or validating bun.")
1492
+ install_bun()
1431
1493
  # Set up the web directory.
1432
1494
  initialize_web_directory()
1433
1495
 
@@ -1496,6 +1558,9 @@ def prompt_for_template_options(templates: list[Template]) -> str:
1496
1558
 
1497
1559
  Returns:
1498
1560
  The template name the user selects.
1561
+
1562
+ Raises:
1563
+ Exit: If the user does not select a template.
1499
1564
  """
1500
1565
  # Show the user the URLs of each template to preview.
1501
1566
  console.print("\nGet started with a template:")
@@ -1520,8 +1585,22 @@ def prompt_for_template_options(templates: list[Template]) -> str:
1520
1585
  default="0",
1521
1586
  )
1522
1587
 
1588
+ if not template:
1589
+ console.error("No template selected.")
1590
+ raise typer.Exit(1)
1591
+
1592
+ try:
1593
+ template_index = int(template)
1594
+ except ValueError:
1595
+ console.error("Invalid template selected.")
1596
+ raise typer.Exit(1) from None
1597
+
1598
+ if template_index < 0 or template_index >= len(templates):
1599
+ console.error("Invalid template selected.")
1600
+ raise typer.Exit(1)
1601
+
1523
1602
  # Return the template.
1524
- return templates[int(template)].name # pyright: ignore [reportArgumentType]
1603
+ return templates[template_index].name
1525
1604
 
1526
1605
 
1527
1606
  def fetch_app_templates(version: str) -> dict[str, Template]:
reflex/utils/processes.py CHANGED
@@ -20,6 +20,7 @@ from rich.progress import Progress
20
20
  from reflex import constants
21
21
  from reflex.config import environment
22
22
  from reflex.utils import console, path_ops, prerequisites
23
+ from reflex.utils.registry import get_npm_registry
23
24
 
24
25
 
25
26
  def kill(pid: int):
@@ -276,6 +277,7 @@ def stream_logs(
276
277
  progress: Progress | None = None,
277
278
  suppress_errors: bool = False,
278
279
  analytics_enabled: bool = False,
280
+ prior_logs: Tuple[tuple[str, ...], ...] = (),
279
281
  ):
280
282
  """Stream the logs for a process.
281
283
 
@@ -285,6 +287,7 @@ def stream_logs(
285
287
  progress: The ongoing progress bar if one is being used.
286
288
  suppress_errors: If True, do not exit if errors are encountered (for fallback).
287
289
  analytics_enabled: Whether analytics are enabled for this command.
290
+ prior_logs: The logs of the prior processes that have been run.
288
291
 
289
292
  Yields:
290
293
  The lines of the process output.
@@ -312,8 +315,31 @@ def stream_logs(
312
315
  accepted_return_codes = [0, -2, 15] if constants.IS_WINDOWS else [0, -2]
313
316
  if process.returncode not in accepted_return_codes and not suppress_errors:
314
317
  console.error(f"{message} failed with exit code {process.returncode}")
315
- for line in logs:
316
- console.error(line, end="")
318
+ if "".join(logs).count("CERT_HAS_EXPIRED") > 0:
319
+ bunfig = prerequisites.get_web_dir() / constants.Bun.CONFIG_PATH
320
+ npm_registry_line = next(
321
+ (
322
+ line
323
+ for line in bunfig.read_text().splitlines()
324
+ if line.startswith("registry")
325
+ ),
326
+ None,
327
+ )
328
+ if not npm_registry_line or "=" not in npm_registry_line:
329
+ npm_registry = get_npm_registry()
330
+ else:
331
+ npm_registry = npm_registry_line.split("=")[1].strip()
332
+ console.error(
333
+ f"Failed to fetch securely from [bold]{npm_registry}[/bold]. Please check your network connection. "
334
+ "You can try running the command again or changing the registry by setting the "
335
+ "NPM_CONFIG_REGISTRY environment variable. If TLS is the issue, and you know what "
336
+ "you are doing, you can disable it by setting the SSL_NO_VERIFY environment variable."
337
+ )
338
+ raise typer.Exit(1)
339
+ for set_of_logs in (*prior_logs, tuple(logs)):
340
+ for line in set_of_logs:
341
+ console.error(line, end="")
342
+ console.error("\n\n")
317
343
  if analytics_enabled:
318
344
  telemetry.send("error", context=message)
319
345
  console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
@@ -336,8 +362,8 @@ def show_status(
336
362
  process: subprocess.Popen,
337
363
  suppress_errors: bool = False,
338
364
  analytics_enabled: bool = False,
339
- prior_processes: Tuple[subprocess.Popen, ...] = (),
340
- ):
365
+ prior_logs: Tuple[tuple[str, ...], ...] = (),
366
+ ) -> list[str]:
341
367
  """Show the status of a process.
342
368
 
343
369
  Args:
@@ -345,17 +371,24 @@ def show_status(
345
371
  process: The process.
346
372
  suppress_errors: If True, do not exit if errors are encountered (for fallback).
347
373
  analytics_enabled: Whether analytics are enabled for this command.
348
- prior_processes: The prior processes that have been run.
374
+ prior_logs: The logs of the prior processes that have been run.
375
+
376
+ Returns:
377
+ The lines of the process output.
349
378
  """
350
- for one_process in (*prior_processes, process):
351
- with console.status(message) as status:
352
- for line in stream_logs(
353
- message,
354
- one_process,
355
- suppress_errors=suppress_errors,
356
- analytics_enabled=analytics_enabled,
357
- ):
358
- status.update(f"{message} {line}")
379
+ lines = []
380
+
381
+ with console.status(message) as status:
382
+ for line in stream_logs(
383
+ message,
384
+ process,
385
+ suppress_errors=suppress_errors,
386
+ analytics_enabled=analytics_enabled,
387
+ prior_logs=prior_logs,
388
+ ):
389
+ status.update(f"{message} {line}")
390
+ lines.append(line)
391
+ return lines
359
392
 
360
393
 
361
394
  def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str]):
@@ -409,7 +442,7 @@ def run_process_with_fallbacks(
409
442
  show_status_message: str,
410
443
  fallbacks: str | Sequence[str] | Sequence[Sequence[str]] | None = None,
411
444
  analytics_enabled: bool = False,
412
- prior_processes: Tuple[subprocess.Popen, ...] = (),
445
+ prior_logs: Tuple[tuple[str, ...], ...] = (),
413
446
  **kwargs,
414
447
  ):
415
448
  """Run subprocess and retry using fallback command if initial command fails.
@@ -419,7 +452,7 @@ def run_process_with_fallbacks(
419
452
  show_status_message: The status message to be displayed in the console.
420
453
  fallbacks: The fallback command to run if the initial command fails.
421
454
  analytics_enabled: Whether analytics are enabled for this command.
422
- prior_processes: The prior processes that have been run.
455
+ prior_logs: The logs of the prior processes that have been run.
423
456
  **kwargs: Kwargs to pass to new_process function.
424
457
  """
425
458
  process = new_process(get_command_with_loglevel(args), **kwargs)
@@ -429,11 +462,11 @@ def run_process_with_fallbacks(
429
462
  show_status_message,
430
463
  process,
431
464
  analytics_enabled=analytics_enabled,
432
- prior_processes=prior_processes,
465
+ prior_logs=prior_logs,
433
466
  )
434
467
  else:
435
468
  # Suppress errors for initial command, because we will try to fallback
436
- show_status(show_status_message, process, suppress_errors=True)
469
+ logs = show_status(show_status_message, process, suppress_errors=True)
437
470
 
438
471
  current_fallback = fallbacks[0] if not isinstance(fallbacks, str) else fallbacks
439
472
  next_fallbacks = fallbacks[1:] if not isinstance(fallbacks, str) else None
@@ -453,7 +486,7 @@ def run_process_with_fallbacks(
453
486
  show_status_message=show_status_message,
454
487
  fallbacks=next_fallbacks,
455
488
  analytics_enabled=analytics_enabled,
456
- prior_processes=(*prior_processes, process),
489
+ prior_logs=(*prior_logs, tuple(logs)),
457
490
  **kwargs,
458
491
  )
459
492
 
@@ -55,6 +55,10 @@ EXCLUDED_PROPS = [
55
55
  "State",
56
56
  ]
57
57
 
58
+ OVERWRITE_TYPES = {
59
+ "style": "Sequence[Mapping[str, Any]] | Mapping[str, Any] | Var[Mapping[str, Any]] | Breakpoints | None",
60
+ }
61
+
58
62
  DEFAULT_TYPING_IMPORTS = {
59
63
  "overload",
60
64
  "Any",
@@ -62,6 +66,7 @@ DEFAULT_TYPING_IMPORTS = {
62
66
  "Dict",
63
67
  # "List",
64
68
  "Sequence",
69
+ "Mapping",
65
70
  "Literal",
66
71
  "Optional",
67
72
  "Union",
@@ -377,7 +382,9 @@ def _extract_class_props_as_ast_nodes(
377
382
  ast.arg(
378
383
  arg=name,
379
384
  annotation=ast.Name(
380
- id=_get_type_hint(value, type_hint_globals)
385
+ id=OVERWRITE_TYPES.get(
386
+ name, _get_type_hint(value, type_hint_globals)
387
+ )
381
388
  ),
382
389
  ),
383
390
  ast.Constant(value=default),
@@ -386,7 +393,7 @@ def _extract_class_props_as_ast_nodes(
386
393
  return kwargs
387
394
 
388
395
 
389
- def type_to_ast(typ: Any, cls: type) -> ast.AST:
396
+ def type_to_ast(typ: Any, cls: type) -> ast.expr:
390
397
  """Converts any type annotation into its AST representation.
391
398
  Handles nested generic types, unions, etc.
392
399
 
@@ -439,11 +446,11 @@ def type_to_ast(typ: Any, cls: type) -> ast.AST:
439
446
  if len(arg_nodes) == 1:
440
447
  slice_value = arg_nodes[0]
441
448
  else:
442
- slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load()) # pyright: ignore [reportArgumentType]
449
+ slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
443
450
 
444
451
  return ast.Subscript(
445
452
  value=ast.Name(id=base_name),
446
- slice=ast.Index(value=slice_value), # pyright: ignore [reportArgumentType]
453
+ slice=slice_value,
447
454
  ctx=ast.Load(),
448
455
  )
449
456
 
@@ -463,16 +470,18 @@ def _get_parent_imports(func: Callable):
463
470
 
464
471
 
465
472
  def _generate_component_create_functiondef(
466
- node: ast.FunctionDef | None,
467
- clz: type[Component] | type[SimpleNamespace],
473
+ clz: type[Component],
468
474
  type_hint_globals: dict[str, Any],
475
+ lineno: int,
476
+ decorator_list: Sequence[ast.expr] = (ast.Name(id="classmethod"),),
469
477
  ) -> ast.FunctionDef:
470
478
  """Generate the create function definition for a Component.
471
479
 
472
480
  Args:
473
- node: The existing create functiondef node from the ast
474
481
  clz: The Component class to generate the create functiondef for.
475
482
  type_hint_globals: The globals to use to resolving a type hint str.
483
+ lineno: The line number to use for the ast nodes.
484
+ decorator_list: The list of decorators to apply to the create functiondef.
476
485
 
477
486
  Returns:
478
487
  The create functiondef node for the ast.
@@ -584,28 +593,26 @@ def _generate_component_create_functiondef(
584
593
  arg=trigger,
585
594
  annotation=ast.Subscript(
586
595
  ast.Name("Optional"),
587
- ast.Index( # pyright: ignore [reportArgumentType]
588
- value=ast.Name(
589
- id=ast.unparse(
590
- figure_out_return_type(
591
- inspect.signature(event_specs).return_annotation
592
- )
593
- if not isinstance(
594
- event_specs := event_triggers[trigger], Sequence
595
- )
596
- else ast.Subscript(
597
- ast.Name("Union"),
598
- ast.Tuple(
599
- [
600
- figure_out_return_type(
601
- inspect.signature(
602
- event_spec
603
- ).return_annotation
604
- )
605
- for event_spec in event_specs
606
- ]
607
- ),
608
- )
596
+ ast.Name(
597
+ id=ast.unparse(
598
+ figure_out_return_type(
599
+ inspect.signature(event_specs).return_annotation
600
+ )
601
+ if not isinstance(
602
+ event_specs := event_triggers[trigger], Sequence
603
+ )
604
+ else ast.Subscript(
605
+ ast.Name("Union"),
606
+ ast.Tuple(
607
+ [
608
+ figure_out_return_type(
609
+ inspect.signature(
610
+ event_spec
611
+ ).return_annotation
612
+ )
613
+ for event_spec in event_specs
614
+ ]
615
+ ),
609
616
  )
610
617
  )
611
618
  ),
@@ -630,7 +637,7 @@ def _generate_component_create_functiondef(
630
637
  definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
631
638
  name="create",
632
639
  args=create_args,
633
- body=[ # pyright: ignore [reportArgumentType]
640
+ body=[
634
641
  ast.Expr(
635
642
  value=ast.Constant(
636
643
  value=_generate_docstrings(
@@ -644,25 +651,19 @@ def _generate_component_create_functiondef(
644
651
  ],
645
652
  decorator_list=[
646
653
  ast.Name(id="overload"),
647
- *(
648
- node.decorator_list
649
- if node is not None
650
- else [ast.Name(id="classmethod")]
651
- ),
654
+ *decorator_list,
652
655
  ],
653
- lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
656
+ lineno=lineno,
654
657
  returns=ast.Constant(value=clz.__name__),
655
658
  )
656
659
  return definition
657
660
 
658
661
 
659
662
  def _generate_staticmethod_call_functiondef(
660
- node: ast.FunctionDef | None,
663
+ node: ast.ClassDef,
661
664
  clz: type[Component] | type[SimpleNamespace],
662
665
  type_hint_globals: dict[str, Any],
663
666
  ) -> ast.FunctionDef | None:
664
- ...
665
-
666
667
  fullspec = getfullargspec(clz.__call__)
667
668
 
668
669
  call_args = ast.arguments(
@@ -699,7 +700,7 @@ def _generate_staticmethod_call_functiondef(
699
700
  ),
700
701
  ],
701
702
  decorator_list=[ast.Name(id="staticmethod")],
702
- lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
703
+ lineno=node.lineno,
703
704
  returns=ast.Constant(
704
705
  value=_get_type_hint(
705
706
  typing.get_type_hints(clz.__call__).get("return", None),
@@ -712,7 +713,7 @@ def _generate_staticmethod_call_functiondef(
712
713
 
713
714
 
714
715
  def _generate_namespace_call_functiondef(
715
- node: ast.ClassDef | None,
716
+ node: ast.ClassDef,
716
717
  clz_name: str,
717
718
  classes: dict[str, type[Component] | type[SimpleNamespace]],
718
719
  type_hint_globals: dict[str, Any],
@@ -736,7 +737,7 @@ def _generate_namespace_call_functiondef(
736
737
  clz = classes[clz_name]
737
738
 
738
739
  if not hasattr(clz.__call__, "__self__"):
739
- return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) # pyright: ignore [reportArgumentType]
740
+ return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals)
740
741
 
741
742
  # Determine which class is wrapped by the namespace __call__ method
742
743
  component_clz = clz.__call__.__self__
@@ -744,10 +745,14 @@ def _generate_namespace_call_functiondef(
744
745
  if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess]
745
746
  return None
746
747
 
748
+ if not issubclass(component_clz, Component):
749
+ return None
750
+
747
751
  definition = _generate_component_create_functiondef(
748
- node=None,
749
- clz=component_clz, # pyright: ignore [reportArgumentType]
752
+ clz=component_clz,
750
753
  type_hint_globals=type_hint_globals,
754
+ lineno=node.lineno,
755
+ decorator_list=[],
751
756
  )
752
757
  definition.name = "__call__"
753
758
 
@@ -804,17 +809,18 @@ class StubGenerator(ast.NodeTransformer):
804
809
  node.body.pop(0)
805
810
  return node
806
811
 
807
- def _current_class_is_component(self) -> bool:
812
+ def _current_class_is_component(self) -> type[Component] | None:
808
813
  """Check if the current class is a Component.
809
814
 
810
815
  Returns:
811
816
  Whether the current class is a Component.
812
817
  """
813
- return (
818
+ if (
814
819
  self.current_class is not None
815
820
  and self.current_class in self.classes
816
- and issubclass(self.classes[self.current_class], Component)
817
- )
821
+ and issubclass((clz := self.classes[self.current_class]), Component)
822
+ ):
823
+ return clz
818
824
 
819
825
  def visit_Module(self, node: ast.Module) -> ast.Module:
820
826
  """Visit a Module node and remove docstring from body.
@@ -916,14 +922,14 @@ class StubGenerator(ast.NodeTransformer):
916
922
  isinstance(child, ast.FunctionDef) and child.name == "create"
917
923
  for child in node.body
918
924
  )
919
- and self._current_class_is_component()
925
+ and (clz := self._current_class_is_component()) is not None
920
926
  ):
921
927
  # Add a new .create FunctionDef since one does not exist.
922
928
  node.body.append(
923
929
  _generate_component_create_functiondef(
924
- node=None,
925
- clz=self.classes[self.current_class],
930
+ clz=clz,
926
931
  type_hint_globals=self.type_hint_globals,
932
+ lineno=node.lineno,
927
933
  )
928
934
  )
929
935
  if call_definition is not None:
@@ -949,9 +955,16 @@ class StubGenerator(ast.NodeTransformer):
949
955
  Returns:
950
956
  The modified FunctionDef node (or None).
951
957
  """
952
- if node.name == "create" and self.current_class in self.classes:
958
+ if (
959
+ node.name == "create"
960
+ and self.current_class in self.classes
961
+ and issubclass((clz := self.classes[self.current_class]), Component)
962
+ ):
953
963
  node = _generate_component_create_functiondef(
954
- node, self.classes[self.current_class], self.type_hint_globals
964
+ clz=clz,
965
+ type_hint_globals=self.type_hint_globals,
966
+ lineno=node.lineno,
967
+ decorator_list=node.decorator_list,
955
968
  )
956
969
  else:
957
970
  if node.name.startswith("_") and node.name != "__call__":
reflex/utils/redir.py CHANGED
@@ -5,6 +5,8 @@ import webbrowser
5
5
 
6
6
  import httpx
7
7
 
8
+ from reflex.utils import net
9
+
8
10
  from .. import constants
9
11
  from . import console
10
12
 
@@ -38,7 +40,7 @@ def open_browser_and_wait(
38
40
  console.info("[b]Complete the workflow in the browser to continue.[/b]")
39
41
  while True:
40
42
  try:
41
- response = httpx.get(poll_url, follow_redirects=True)
43
+ response = net.get(poll_url, follow_redirects=True)
42
44
  if response.is_success:
43
45
  break
44
46
  except httpx.RequestError as err: