reflex 0.8.13__py3-none-any.whl → 0.8.14__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 (40) hide show
  1. reflex/app.py +25 -5
  2. reflex/compiler/templates.py +4 -0
  3. reflex/components/core/upload.py +9 -13
  4. reflex/components/core/upload.pyi +27 -9
  5. reflex/components/plotly/plotly.py +9 -9
  6. reflex/components/radix/primitives/__init__.py +1 -1
  7. reflex/components/radix/primitives/__init__.pyi +2 -1
  8. reflex/components/radix/primitives/base.py +31 -0
  9. reflex/components/radix/primitives/base.pyi +44 -0
  10. reflex/components/radix/primitives/dialog.py +148 -0
  11. reflex/components/radix/primitives/dialog.pyi +749 -0
  12. reflex/components/radix/primitives/slider.py +3 -17
  13. reflex/components/radix/primitives/slider.pyi +2 -4
  14. reflex/components/radix/themes/components/slider.py +1 -2
  15. reflex/components/radix/themes/components/slider.pyi +3 -6
  16. reflex/constants/colors.py +1 -3
  17. reflex/constants/installer.py +5 -5
  18. reflex/custom_components/custom_components.py +18 -18
  19. reflex/environment.py +3 -0
  20. reflex/event.py +1 -1
  21. reflex/plugins/shared_tailwind.py +1 -1
  22. reflex/reflex.py +62 -24
  23. reflex/state.py +3 -2
  24. reflex/utils/exec.py +23 -4
  25. reflex/utils/frontend_skeleton.py +3 -5
  26. reflex/utils/js_runtimes.py +43 -33
  27. reflex/utils/prerequisites.py +5 -6
  28. reflex/utils/processes.py +10 -11
  29. reflex/utils/rename.py +3 -5
  30. reflex/utils/serializers.py +3 -7
  31. reflex/utils/templates.py +20 -22
  32. reflex/vars/base.py +3 -6
  33. reflex/vars/color.py +2 -68
  34. reflex/vars/object.py +1 -3
  35. reflex/vars/sequence.py +2 -2
  36. {reflex-0.8.13.dist-info → reflex-0.8.14.dist-info}/METADATA +1 -1
  37. {reflex-0.8.13.dist-info → reflex-0.8.14.dist-info}/RECORD +40 -38
  38. {reflex-0.8.13.dist-info → reflex-0.8.14.dist-info}/WHEEL +0 -0
  39. {reflex-0.8.13.dist-info → reflex-0.8.14.dist-info}/entry_points.txt +0 -0
  40. {reflex-0.8.13.dist-info → reflex-0.8.14.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,6 @@ import tempfile
6
6
  from collections.abc import Sequence
7
7
  from pathlib import Path
8
8
 
9
- import click
10
9
  from packaging import version
11
10
 
12
11
  from reflex import constants
@@ -30,22 +29,45 @@ def check_node_version() -> bool:
30
29
  )
31
30
 
32
31
 
33
- @once
34
- def get_node_version() -> version.Version | None:
35
- """Get the version of node.
32
+ def _get_version_of_executable(
33
+ executable_path: Path | None, version_arg: str = "--version"
34
+ ) -> version.Version | None:
35
+ """Get the version of an executable.
36
+
37
+ Args:
38
+ executable_path: The path to the executable.
39
+ version_arg: The argument to pass to the executable to get its version.
36
40
 
37
41
  Returns:
38
- The version of node.
42
+ The version of the executable.
39
43
  """
40
- node_path = path_ops.get_node_path()
41
- if node_path is None:
44
+ if executable_path is None:
42
45
  return None
43
46
  try:
44
- result = processes.new_process([node_path, "-v"], run=True)
45
- # The output will be in the form "vX.Y.Z", but version.parse() can handle it
46
- return version.parse(result.stdout)
47
+ result = processes.new_process([executable_path, version_arg], run=True)
48
+ if result.returncode != 0:
49
+ console.error(
50
+ f"Failed to run {executable_path} {version_arg} to get version. Return code: {result.returncode}. Standard error: {result.stderr!r}."
51
+ )
52
+ return None
53
+ return version.parse(result.stdout.strip())
47
54
  except (FileNotFoundError, TypeError):
48
55
  return None
56
+ except version.InvalidVersion as e:
57
+ console.warn(
58
+ f"The detected version of {executable_path} ({e.args[0]}) is not valid. Defaulting to None."
59
+ )
60
+ return None
61
+
62
+
63
+ @once
64
+ def get_node_version() -> version.Version | None:
65
+ """Get the version of node.
66
+
67
+ Returns:
68
+ The version of node.
69
+ """
70
+ return _get_version_of_executable(path_ops.get_node_path())
49
71
 
50
72
 
51
73
  def get_bun_version(bun_path: Path | None = None) -> version.Version | None:
@@ -57,20 +79,7 @@ def get_bun_version(bun_path: Path | None = None) -> version.Version | None:
57
79
  Returns:
58
80
  The version of bun.
59
81
  """
60
- bun_path = bun_path or path_ops.get_bun_path()
61
- if bun_path is None:
62
- return None
63
- try:
64
- # Run the bun -v command and capture the output
65
- result = processes.new_process([str(bun_path), "-v"], run=True)
66
- return version.parse(str(result.stdout))
67
- except FileNotFoundError:
68
- return None
69
- except version.InvalidVersion as e:
70
- console.warn(
71
- f"The detected bun version ({e.args[0]}) is not valid. Defaulting to None."
72
- )
73
- return None
82
+ return _get_version_of_executable(bun_path or path_ops.get_bun_path())
74
83
 
75
84
 
76
85
  def npm_escape_hatch() -> bool:
@@ -193,7 +202,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
193
202
  env: The environment variables to use.
194
203
 
195
204
  Raises:
196
- Exit: If the script fails to download.
205
+ SystemExit: If the script fails to download.
197
206
  """
198
207
  import httpx
199
208
 
@@ -206,7 +215,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
206
215
  console.error(
207
216
  f"Failed to download bun install script. You can install or update bun manually from https://bun.com \n{e}"
208
217
  )
209
- raise click.exceptions.Exit(1) from None
218
+ raise SystemExit(1) from None
210
219
 
211
220
  # Save the script to a temporary file.
212
221
  with tempfile.NamedTemporaryFile() as tempfile_file:
@@ -226,7 +235,7 @@ def install_bun():
226
235
 
227
236
  Raises:
228
237
  SystemPackageMissingError: If "unzip" is missing.
229
- Exit: If REFLEX_USE_NPM is set but Node.js is not installed.
238
+ SystemExit: If REFLEX_USE_NPM is set but Node.js is not installed.
230
239
  """
231
240
  if npm_escape_hatch():
232
241
  if get_node_version() is not None:
@@ -237,7 +246,7 @@ def install_bun():
237
246
  console.error(
238
247
  "REFLEX_USE_NPM is set, but Node.js is not installed. Please install Node.js to use npm."
239
248
  )
240
- raise click.exceptions.Exit(1)
249
+ raise SystemExit(1)
241
250
 
242
251
  bun_path = path_ops.get_bun_path()
243
252
 
@@ -290,7 +299,7 @@ def validate_bun(bun_path: Path | None = None):
290
299
  bun_path: The path to the bun executable. If None, the default bun path is used.
291
300
 
292
301
  Raises:
293
- Exit: If custom specified bun does not exist or does not meet requirements.
302
+ SystemExit: If custom specified bun does not exist or does not meet requirements.
294
303
  """
295
304
  bun_path = bun_path or path_ops.get_bun_path()
296
305
 
@@ -304,7 +313,7 @@ def validate_bun(bun_path: Path | None = None):
304
313
  console.error(
305
314
  "Failed to obtain bun version. Make sure the specified bun path in your config is correct."
306
315
  )
307
- raise click.exceptions.Exit(1)
316
+ raise SystemExit(1)
308
317
  if bun_version < version.parse(constants.Bun.MIN_VERSION):
309
318
  console.warn(
310
319
  f"Reflex requires bun version {constants.Bun.MIN_VERSION} or higher to run, but the detected version is "
@@ -320,20 +329,21 @@ def validate_frontend_dependencies(init: bool = True):
320
329
  init: whether running `reflex init`
321
330
 
322
331
  Raises:
323
- Exit: If the package manager is invalid.
332
+ SystemExit: If the package manager is invalid.
324
333
  """
325
334
  if not init:
326
335
  try:
327
336
  get_js_package_executor(raise_on_none=True)
328
337
  except FileNotFoundError as e:
329
- raise click.exceptions.Exit(1) from e
338
+ console.error(f"Failed to find a valid package manager due to {e}.")
339
+ raise SystemExit(1) from None
330
340
 
331
341
  if prefer_npm_over_bun() and not check_node_version():
332
342
  node_version = get_node_version()
333
343
  console.error(
334
344
  f"Reflex requires node version {constants.Node.MIN_VERSION} or higher to run, but the detected version is {node_version}",
335
345
  )
336
- raise click.exceptions.Exit(1)
346
+ raise SystemExit(1)
337
347
 
338
348
 
339
349
  def remove_existing_bun_installation():
@@ -15,7 +15,6 @@ from pathlib import Path
15
15
  from types import ModuleType
16
16
  from typing import NamedTuple
17
17
 
18
- import click
19
18
  from alembic.util.exc import CommandError
20
19
  from packaging import version
21
20
  from redis import Redis as RedisSync
@@ -444,7 +443,7 @@ def validate_app_name(app_name: str | None = None) -> str:
444
443
  The app name after validation.
445
444
 
446
445
  Raises:
447
- Exit: if the app directory name is reflex or if the name is not standard for a python package name.
446
+ SystemExit: if the app directory name is reflex or if the name is not standard for a python package name.
448
447
  """
449
448
  app_name = app_name if app_name else Path.cwd().name.replace("-", "_")
450
449
  # Make sure the app is not named "reflex".
@@ -452,14 +451,14 @@ def validate_app_name(app_name: str | None = None) -> str:
452
451
  console.error(
453
452
  f"The app directory cannot be named [bold]{constants.Reflex.MODULE_NAME}[/bold]."
454
453
  )
455
- raise click.exceptions.Exit(1)
454
+ raise SystemExit(1)
456
455
 
457
456
  # Make sure the app name is standard for a python package name.
458
457
  if not re.match(r"^[a-zA-Z][a-zA-Z0-9_]*$", app_name):
459
458
  console.error(
460
459
  "The app directory name must start with a letter and can contain letters, numbers, and underscores."
461
460
  )
462
- raise click.exceptions.Exit(1)
461
+ raise SystemExit(1)
463
462
 
464
463
  return app_name
465
464
 
@@ -499,13 +498,13 @@ def assert_in_reflex_dir():
499
498
  """Assert that the current working directory is the reflex directory.
500
499
 
501
500
  Raises:
502
- Exit: If the current working directory is not the reflex directory.
501
+ SystemExit: If the current working directory is not the reflex directory.
503
502
  """
504
503
  if not constants.Config.FILE.exists():
505
504
  console.error(
506
505
  f"[cyan]{constants.Config.FILE}[/cyan] not found. Move to the root folder of your project, or run [bold]{constants.Reflex.MODULE_NAME} init[/bold] to start a new project."
507
506
  )
508
- raise click.exceptions.Exit(1)
507
+ raise SystemExit(1)
509
508
 
510
509
 
511
510
  def needs_reinit() -> bool:
reflex/utils/processes.py CHANGED
@@ -15,7 +15,6 @@ from contextlib import closing
15
15
  from pathlib import Path
16
16
  from typing import Any, Literal, overload
17
17
 
18
- import click
19
18
  import rich.markup
20
19
  from redis.exceptions import RedisError
21
20
  from rich.progress import Progress
@@ -39,7 +38,7 @@ def get_num_workers() -> int:
39
38
  """Get the number of backend worker processes.
40
39
 
41
40
  Raises:
42
- Exit: If unable to connect to Redis.
41
+ SystemExit: If unable to connect to Redis.
43
42
 
44
43
  Returns:
45
44
  The number of backend worker processes.
@@ -50,7 +49,7 @@ def get_num_workers() -> int:
50
49
  redis_client.ping()
51
50
  except RedisError as re:
52
51
  console.error(f"Unable to connect to Redis: {re}")
53
- raise click.exceptions.Exit(1) from re
52
+ raise SystemExit(1) from None
54
53
  return (os.cpu_count() or 1) * 2 + 1
55
54
 
56
55
 
@@ -131,7 +130,7 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
131
130
  The port to run the service on.
132
131
 
133
132
  Raises:
134
- Exit:when the port is in use.
133
+ SystemExit:when the port is in use.
135
134
  """
136
135
  console.debug(f"Checking if {service_name.capitalize()} port: {port} is in use.")
137
136
 
@@ -146,7 +145,7 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
146
145
  f"Unable to bind to any port for {service_name}. "
147
146
  "Please check your network configuration."
148
147
  )
149
- raise click.exceptions.Exit(1)
148
+ raise SystemExit(1)
150
149
 
151
150
  console.debug(
152
151
  f"Checking if {service_name.capitalize()} port: {port} is in use for families: {families}."
@@ -172,7 +171,7 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
172
171
  else:
173
172
  console.error(f"{service_name.capitalize()} port: {port} is already in use.")
174
173
 
175
- raise click.exceptions.Exit(1)
174
+ raise SystemExit(1)
176
175
 
177
176
 
178
177
  @overload
@@ -211,13 +210,13 @@ def new_process(
211
210
  Execute a child program in a new process.
212
211
 
213
212
  Raises:
214
- Exit: When attempting to run a command with a None value.
213
+ SystemExit: When attempting to run a command with a None value.
215
214
  """
216
215
  # Check for invalid command first.
217
216
  non_empty_args = list(filter(None, args)) if isinstance(args, list) else [args]
218
217
  if isinstance(args, list) and len(non_empty_args) != len(args):
219
218
  console.error(f"Invalid command: {args}")
220
- raise click.exceptions.Exit(1)
219
+ raise SystemExit(1)
221
220
 
222
221
  path_env: str = os.environ.get("PATH", "")
223
222
 
@@ -325,7 +324,7 @@ def stream_logs(
325
324
  The lines of the process output.
326
325
 
327
326
  Raises:
328
- Exit: If the process failed.
327
+ SystemExit: If the process failed.
329
328
  ValueError: If the process stdout pipe is closed, but the process remains running.
330
329
  """
331
330
  from reflex.utils import telemetry
@@ -376,7 +375,7 @@ def stream_logs(
376
375
  "NPM_CONFIG_REGISTRY environment variable. If TLS is the issue, and you know what "
377
376
  "you are doing, you can disable it by setting the SSL_NO_VERIFY environment variable."
378
377
  )
379
- raise click.exceptions.Exit(1)
378
+ raise SystemExit(1)
380
379
  for set_of_logs in (*prior_logs, tuple(logs)):
381
380
  for line in set_of_logs:
382
381
  console.error(line, end="")
@@ -384,7 +383,7 @@ def stream_logs(
384
383
  if analytics_enabled:
385
384
  telemetry.send("error", context=message)
386
385
  console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
387
- raise click.exceptions.Exit(1)
386
+ raise SystemExit(1)
388
387
 
389
388
 
390
389
  def show_logs(message: str, process: subprocess.Popen):
reflex/utils/rename.py CHANGED
@@ -4,8 +4,6 @@ import re
4
4
  import sys
5
5
  from pathlib import Path
6
6
 
7
- import click
8
-
9
7
  from reflex import constants
10
8
  from reflex.config import get_config
11
9
  from reflex.utils import console
@@ -57,7 +55,7 @@ def rename_app(new_app_name: str, loglevel: constants.LogLevel):
57
55
  loglevel: The log level to use.
58
56
 
59
57
  Raises:
60
- Exit: If the command is not ran in the root dir or the app module cannot be imported.
58
+ SystemExit: If the command is not ran in the root dir or the app module cannot be imported.
61
59
  """
62
60
  # Set the log level.
63
61
  console.set_log_level(loglevel)
@@ -66,7 +64,7 @@ def rename_app(new_app_name: str, loglevel: constants.LogLevel):
66
64
  console.error(
67
65
  "No rxconfig.py found. Make sure you are in the root directory of your app."
68
66
  )
69
- raise click.exceptions.Exit(1)
67
+ raise SystemExit(1)
70
68
 
71
69
  sys.path.insert(0, str(Path.cwd()))
72
70
 
@@ -74,7 +72,7 @@ def rename_app(new_app_name: str, loglevel: constants.LogLevel):
74
72
  module_path = get_module_path(config.module)
75
73
  if module_path is None:
76
74
  console.error(f"Could not find module {config.module}.")
77
- raise click.exceptions.Exit(1)
75
+ raise SystemExit(1)
78
76
 
79
77
  console.info(f"Renaming app directory to {new_app_name}.")
80
78
  process_directory(
@@ -413,8 +413,8 @@ def serialize_decimal(value: decimal.Decimal) -> float:
413
413
  return float(value)
414
414
 
415
415
 
416
- @serializer(to=dict)
417
- def serialize_color(color: Color) -> dict:
416
+ @serializer(to=str)
417
+ def serialize_color(color: Color) -> str:
418
418
  """Serialize a color.
419
419
 
420
420
  Args:
@@ -423,11 +423,7 @@ def serialize_color(color: Color) -> dict:
423
423
  Returns:
424
424
  The serialized color.
425
425
  """
426
- return {
427
- "color": color.color,
428
- "shade": color.shade,
429
- "alpha": color.alpha,
430
- }
426
+ return color.__format__("")
431
427
 
432
428
 
433
429
  with contextlib.suppress(ImportError):
reflex/utils/templates.py CHANGED
@@ -7,8 +7,6 @@ import zipfile
7
7
  from pathlib import Path
8
8
  from urllib.parse import urlparse
9
9
 
10
- import click
11
-
12
10
  from reflex import constants
13
11
  from reflex.config import get_config
14
12
  from reflex.utils import console, net, path_ops, redir
@@ -51,7 +49,7 @@ def initialize_app_directory(
51
49
  template_dir: The directory of the template source files.
52
50
 
53
51
  Raises:
54
- Exit: If template_name, template_code_dir_name, template_dir combination is not supported.
52
+ SystemExit: If template_name, template_code_dir_name, template_dir combination is not supported.
55
53
  """
56
54
  console.log("Initializing the app directory.")
57
55
 
@@ -61,7 +59,7 @@ def initialize_app_directory(
61
59
  console.error(
62
60
  f"Only {template_name=} should be provided, got {template_code_dir_name=}, {template_dir=}."
63
61
  )
64
- raise click.exceptions.Exit(1)
62
+ raise SystemExit(1)
65
63
  template_code_dir_name = constants.Templates.Dirs.CODE
66
64
  template_dir = Path(constants.Templates.Dirs.BASE, "apps", template_name)
67
65
  else:
@@ -69,7 +67,7 @@ def initialize_app_directory(
69
67
  console.error(
70
68
  f"For `{template_name}` template, `template_code_dir_name` and `template_dir` should both be provided."
71
69
  )
72
- raise click.exceptions.Exit(1)
70
+ raise SystemExit(1)
73
71
 
74
72
  console.debug(f"Using {template_name=} {template_dir=} {template_code_dir_name=}.")
75
73
 
@@ -117,7 +115,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
117
115
  template_url: The path to the template source code as a zip file.
118
116
 
119
117
  Raises:
120
- Exit: If any download, file operations fail or unexpected zip file format.
118
+ SystemExit: If any download, file operations fail or unexpected zip file format.
121
119
 
122
120
  """
123
121
  import httpx
@@ -127,7 +125,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
127
125
  temp_dir = tempfile.mkdtemp()
128
126
  except OSError as ose:
129
127
  console.error(f"Failed to create temp directory for download: {ose}")
130
- raise click.exceptions.Exit(1) from ose
128
+ raise SystemExit(1) from None
131
129
 
132
130
  # Use httpx GET with redirects to download the zip file.
133
131
  zip_file_path: Path = Path(temp_dir) / "template.zip"
@@ -138,20 +136,20 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
138
136
  response.raise_for_status()
139
137
  except httpx.HTTPError as he:
140
138
  console.error(f"Failed to download the template: {he}")
141
- raise click.exceptions.Exit(1) from he
139
+ raise SystemExit(1) from None
142
140
  try:
143
141
  zip_file_path.write_bytes(response.content)
144
142
  console.debug(f"Downloaded the zip to {zip_file_path}")
145
143
  except OSError as ose:
146
144
  console.error(f"Unable to write the downloaded zip to disk {ose}")
147
- raise click.exceptions.Exit(1) from ose
145
+ raise SystemExit(1) from None
148
146
 
149
147
  # Create a temp directory for the zip extraction.
150
148
  try:
151
149
  unzip_dir = Path(tempfile.mkdtemp())
152
150
  except OSError as ose:
153
151
  console.error(f"Failed to create temp directory for extracting zip: {ose}")
154
- raise click.exceptions.Exit(1) from ose
152
+ raise SystemExit(1) from None
155
153
 
156
154
  try:
157
155
  zipfile.ZipFile(zip_file_path).extractall(path=unzip_dir)
@@ -159,11 +157,11 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
159
157
  # repo-name-branch/**/*, so we need to remove the top level directory.
160
158
  except Exception as uze:
161
159
  console.error(f"Failed to unzip the template: {uze}")
162
- raise click.exceptions.Exit(1) from uze
160
+ raise SystemExit(1) from None
163
161
 
164
162
  if len(subdirs := list(unzip_dir.iterdir())) != 1:
165
163
  console.error(f"Expected one directory in the zip, found {subdirs}")
166
- raise click.exceptions.Exit(1)
164
+ raise SystemExit(1)
167
165
 
168
166
  template_dir = unzip_dir / subdirs[0]
169
167
  console.debug(f"Template folder is located at {template_dir}")
@@ -204,7 +202,7 @@ def validate_and_create_app_using_remote_template(
204
202
  templates: The available templates.
205
203
 
206
204
  Raises:
207
- Exit: If the template is not found.
205
+ SystemExit: If the template is not found.
208
206
  """
209
207
  # If user selects a template, it needs to exist.
210
208
  if template in templates:
@@ -215,7 +213,7 @@ def validate_and_create_app_using_remote_template(
215
213
  console.print(
216
214
  f"Please use `reflex login` to access the '{template}' template."
217
215
  )
218
- raise click.exceptions.Exit(3)
216
+ raise SystemExit(3)
219
217
 
220
218
  template_url = templates[template].code_url
221
219
  else:
@@ -226,7 +224,7 @@ def validate_and_create_app_using_remote_template(
226
224
  template_url = f"https://github.com/{path}/archive/main.zip"
227
225
  else:
228
226
  console.error(f"Template `{template}` not found or invalid.")
229
- raise click.exceptions.Exit(1)
227
+ raise SystemExit(1)
230
228
 
231
229
  if template_url is None:
232
230
  return
@@ -327,7 +325,7 @@ def prompt_for_template_options(templates: list[Template]) -> str:
327
325
  The template name the user selects.
328
326
 
329
327
  Raises:
330
- Exit: If the user does not select a template.
328
+ SystemExit: If the user does not select a template.
331
329
  """
332
330
  # Show the user the URLs of each template to preview.
333
331
  console.print("\nGet started with a template:")
@@ -345,17 +343,17 @@ def prompt_for_template_options(templates: list[Template]) -> str:
345
343
 
346
344
  if not template:
347
345
  console.error("No template selected.")
348
- raise click.exceptions.Exit(1)
346
+ raise SystemExit(1)
349
347
 
350
348
  try:
351
349
  template_index = int(template)
352
350
  except ValueError:
353
351
  console.error("Invalid template selected.")
354
- raise click.exceptions.Exit(1) from None
352
+ raise SystemExit(1) from None
355
353
 
356
354
  if template_index < 0 or template_index >= len(templates):
357
355
  console.error("Invalid template selected.")
358
- raise click.exceptions.Exit(1)
356
+ raise SystemExit(1)
359
357
 
360
358
  # Return the template.
361
359
  return templates[template_index].name
@@ -372,7 +370,7 @@ def initialize_app(app_name: str, template: str | None = None) -> str | None:
372
370
  The name of the template.
373
371
 
374
372
  Raises:
375
- Exit: If the template is not valid or unspecified.
373
+ SystemExit: If the template is not valid or unspecified.
376
374
  """
377
375
  # Local imports to avoid circular imports.
378
376
  from reflex.utils import telemetry
@@ -393,11 +391,11 @@ def initialize_app(app_name: str, template: str | None = None) -> str | None:
393
391
 
394
392
  if template == constants.Templates.CHOOSE_TEMPLATES:
395
393
  redir.reflex_templates()
396
- raise click.exceptions.Exit(0)
394
+ raise SystemExit(0)
397
395
 
398
396
  if template == constants.Templates.AI:
399
397
  redir.reflex_build_redirect()
400
- raise click.exceptions.Exit(0)
398
+ raise SystemExit(0)
401
399
 
402
400
  # If the blank template is selected, create a blank app.
403
401
  if template == constants.Templates.DEFAULT:
reflex/vars/base.py CHANGED
@@ -1135,17 +1135,14 @@ class Var(Generic[VAR_TYPE], metaclass=MetaclassVar):
1135
1135
  Returns:
1136
1136
  The reference to the var.
1137
1137
  """
1138
- from .object import ObjectVar
1139
-
1140
- refs = Var(
1141
- _js_expr="refs",
1138
+ return Var(
1139
+ _js_expr=f"refs[{Var.create(str(self))}]",
1142
1140
  _var_data=VarData(
1143
1141
  imports={
1144
1142
  f"$/{constants.Dirs.STATE_PATH}": [imports.ImportVar(tag="refs")]
1145
1143
  }
1146
1144
  ),
1147
- ).to(ObjectVar, Mapping[str, str])
1148
- return refs[LiteralVar.create(str(self))]
1145
+ ).to(str)
1149
1146
 
1150
1147
  def js_type(self) -> StringVar:
1151
1148
  """Returns the javascript type of the object.
reflex/vars/color.py CHANGED
@@ -10,72 +10,14 @@ from reflex.vars.base import (
10
10
  VarData,
11
11
  cached_property_no_lock,
12
12
  get_python_literal,
13
- transform,
14
13
  )
15
- from reflex.vars.number import BooleanVar, NumberVar, ternary_operation
16
- from reflex.vars.object import LiteralObjectVar
14
+ from reflex.vars.number import ternary_operation
17
15
  from reflex.vars.sequence import ConcatVarOperation, LiteralStringVar, StringVar
18
16
 
19
17
 
20
- @transform
21
- def evaluate_color(js_dict: Var[dict]) -> Var[Color]:
22
- """Evaluate a color var.
23
-
24
- Args:
25
- js_dict: The color var as a dict.
26
-
27
- Returns:
28
- The color var as a string.
29
- """
30
- js_color_dict = js_dict.to(dict)
31
- str_part = ConcatVarOperation.create(
32
- LiteralStringVar.create("var(--"),
33
- js_color_dict.color,
34
- LiteralStringVar.create("-"),
35
- ternary_operation(
36
- js_color_dict.alpha,
37
- LiteralStringVar.create("a"),
38
- LiteralStringVar.create(""),
39
- ),
40
- js_color_dict.shade.to_string(use_json=False),
41
- LiteralStringVar.create(")"),
42
- )
43
- return js_dict._replace(
44
- _js_expr=f"Object.assign(new String({str_part!s}), {js_dict!s})",
45
- _var_type=Color,
46
- )
47
-
48
-
49
18
  class ColorVar(StringVar[Color], python_types=Color):
50
19
  """Base class for immutable color vars."""
51
20
 
52
- @property
53
- def color(self) -> StringVar:
54
- """Get the color of the color var.
55
-
56
- Returns:
57
- The color of the color var.
58
- """
59
- return self.to(dict).color.to(str)
60
-
61
- @property
62
- def alpha(self) -> BooleanVar:
63
- """Get the alpha of the color var.
64
-
65
- Returns:
66
- The alpha of the color var.
67
- """
68
- return self.to(dict).alpha.to(bool)
69
-
70
- @property
71
- def shade(self) -> NumberVar:
72
- """Get the shade of the color var.
73
-
74
- Returns:
75
- The shade of the color var.
76
- """
77
- return self.to(dict).shade.to(int)
78
-
79
21
 
80
22
  @dataclasses.dataclass(
81
23
  eq=False,
@@ -150,7 +92,7 @@ class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
150
92
  if isinstance(shade, Var)
151
93
  else LiteralStringVar.create(str(shade))
152
94
  )
153
- string_part = str(
95
+ return str(
154
96
  ConcatVarOperation.create(
155
97
  LiteralStringVar.create("var(--"),
156
98
  self._var_value.color,
@@ -160,14 +102,6 @@ class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
160
102
  LiteralStringVar.create(")"),
161
103
  )
162
104
  )
163
- dict_part = LiteralObjectVar.create(
164
- {
165
- "color": self._var_value.color,
166
- "alpha": self._var_value.alpha,
167
- "shade": self._var_value.shade,
168
- }
169
- )
170
- return f"Object.assign(new String({string_part!s}), {dict_part!s})"
171
105
 
172
106
  @cached_property_no_lock
173
107
  def _cached_get_all_var_data(self) -> VarData | None:
reflex/vars/object.py CHANGED
@@ -557,9 +557,7 @@ class ObjectItemOperation(CachedVarOperation, Var):
557
557
  Returns:
558
558
  The name of the operation.
559
559
  """
560
- if types.is_optional(self._object._var_type):
561
- return f"{self._object!s}?.[{self._key!s}]"
562
- return f"{self._object!s}[{self._key!s}]"
560
+ return f"{self._object!s}?.[{self._key!s}]"
563
561
 
564
562
  @classmethod
565
563
  def create(
reflex/vars/sequence.py CHANGED
@@ -1056,7 +1056,7 @@ def string_item_operation(string: StringVar[Any], index: NumberVar | int):
1056
1056
  Returns:
1057
1057
  The item from the string.
1058
1058
  """
1059
- return var_operation_return(js_expression=f"{string}.at({index})", var_type=str)
1059
+ return var_operation_return(js_expression=f"{string}?.at?.({index})", var_type=str)
1060
1060
 
1061
1061
 
1062
1062
  @var_operation
@@ -1619,7 +1619,7 @@ def array_item_operation(array: ArrayVar, index: NumberVar | int):
1619
1619
  )
1620
1620
 
1621
1621
  return var_operation_return(
1622
- js_expression=f"{array!s}.at({index!s})",
1622
+ js_expression=f"{array!s}?.at?.({index!s})",
1623
1623
  var_type=element_type,
1624
1624
  )
1625
1625