reflex 0.7.3a2__py3-none-any.whl → 0.7.4__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 (39) hide show
  1. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +9 -1
  2. reflex/app.py +21 -5
  3. reflex/base.py +3 -3
  4. reflex/compiler/compiler.py +68 -8
  5. reflex/components/component.py +6 -3
  6. reflex/components/core/client_side_routing.py +3 -3
  7. reflex/components/core/cond.py +20 -12
  8. reflex/components/core/upload.py +1 -1
  9. reflex/components/dynamic.py +2 -4
  10. reflex/components/lucide/icon.py +20 -27
  11. reflex/components/plotly/plotly.py +9 -9
  12. reflex/components/recharts/recharts.py +2 -2
  13. reflex/components/sonner/toast.py +1 -1
  14. reflex/config.py +23 -23
  15. reflex/constants/__init__.py +1 -2
  16. reflex/constants/base.py +3 -0
  17. reflex/constants/installer.py +8 -105
  18. reflex/custom_components/custom_components.py +8 -3
  19. reflex/reflex.py +22 -4
  20. reflex/state.py +9 -1
  21. reflex/testing.py +7 -1
  22. reflex/utils/build.py +3 -4
  23. reflex/utils/exec.py +156 -75
  24. reflex/utils/net.py +107 -18
  25. reflex/utils/path_ops.py +15 -25
  26. reflex/utils/prerequisites.py +225 -189
  27. reflex/utils/processes.py +70 -35
  28. reflex/utils/redir.py +3 -1
  29. reflex/utils/registry.py +16 -8
  30. reflex/vars/base.py +2 -38
  31. reflex/vars/datetime.py +10 -34
  32. reflex/vars/number.py +16 -112
  33. reflex/vars/sequence.py +99 -108
  34. {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/METADATA +4 -2
  35. {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/RECORD +38 -39
  36. reflex/app_module_for_backend.py +0 -33
  37. {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/WHEEL +0 -0
  38. {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/entry_points.txt +0 -0
  39. {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/licenses/LICENSE +0 -0
@@ -45,7 +45,7 @@ from .config import (
45
45
  )
46
46
  from .custom_components import CustomComponents
47
47
  from .event import Endpoint, EventTriggers, SocketEvent
48
- from .installer import Bun, Fnm, Node, PackageJson
48
+ from .installer import Bun, Node, PackageJson
49
49
  from .route import (
50
50
  ROUTE_NOT_FOUND,
51
51
  ROUTER,
@@ -94,7 +94,6 @@ __all__ = [
94
94
  "EventTriggers",
95
95
  "Expiration",
96
96
  "Ext",
97
- "Fnm",
98
97
  "GitIgnore",
99
98
  "Hooks",
100
99
  "Imports",
reflex/constants/base.py CHANGED
@@ -88,6 +88,9 @@ class Reflex(SimpleNamespace):
88
88
 
89
89
  RELEASES_URL = "https://api.github.com/repos/reflex-dev/templates/releases"
90
90
 
91
+ # The reflex stylesheet language supported
92
+ STYLESHEETS_SUPPORTED = ["css", "sass", "scss"]
93
+
91
94
 
92
95
  class ReflexHostingCLI(SimpleNamespace):
93
96
  """Base constants concerning Reflex Hosting CLI."""
@@ -1,46 +1,22 @@
1
- """File for constants related to the installation process. (Bun/FNM/Node)."""
1
+ """File for constants related to the installation process. (Bun/Node)."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import platform
6
- from pathlib import Path
7
5
  from types import SimpleNamespace
8
6
 
9
7
  from .base import IS_WINDOWS
10
8
  from .utils import classproperty
11
9
 
12
10
 
13
- def get_fnm_name() -> str | None:
14
- """Get the appropriate fnm executable name based on the current platform.
15
-
16
- Returns:
17
- The fnm executable name for the current platform.
18
- """
19
- platform_os = platform.system()
20
-
21
- if platform_os == "Windows":
22
- return "fnm-windows"
23
- elif platform_os == "Darwin":
24
- return "fnm-macos"
25
- elif platform_os == "Linux":
26
- machine = platform.machine()
27
- if machine == "arm" or machine.startswith("armv7"):
28
- return "fnm-arm32"
29
- elif machine.startswith("aarch") or machine.startswith("armv8"):
30
- return "fnm-arm64"
31
- return "fnm-linux"
32
- return None
33
-
34
-
35
11
  # Bun config.
36
12
  class Bun(SimpleNamespace):
37
13
  """Bun constants."""
38
14
 
39
15
  # The Bun version.
40
- VERSION = "1.2.0"
16
+ VERSION = "1.2.4"
41
17
 
42
18
  # Min Bun Version
43
- MIN_VERSION = "1.1.0"
19
+ MIN_VERSION = "1.2.4"
44
20
 
45
21
  # URL to bun install script.
46
22
  INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
@@ -81,43 +57,6 @@ registry = "{registry}"
81
57
  """
82
58
 
83
59
 
84
- # FNM config.
85
- class Fnm(SimpleNamespace):
86
- """FNM constants."""
87
-
88
- # The FNM version.
89
- VERSION = "1.35.1"
90
-
91
- FILENAME = get_fnm_name()
92
-
93
- # The URL to the fnm release binary
94
- INSTALL_URL = (
95
- f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip"
96
- )
97
-
98
- @classproperty
99
- @classmethod
100
- def DIR(cls) -> Path:
101
- """The directory to store fnm.
102
-
103
- Returns:
104
- The directory to store fnm.
105
- """
106
- from reflex.config import environment
107
-
108
- return environment.REFLEX_DIR.get() / "fnm"
109
-
110
- @classproperty
111
- @classmethod
112
- def EXE(cls):
113
- """The fnm executable binary.
114
-
115
- Returns:
116
- The fnm executable binary.
117
- """
118
- return cls.DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
119
-
120
-
121
60
  # Node / NPM config
122
61
  class Node(SimpleNamespace):
123
62
  """Node/ NPM constants."""
@@ -127,42 +66,6 @@ class Node(SimpleNamespace):
127
66
  # The minimum required node version.
128
67
  MIN_VERSION = "18.18.0"
129
68
 
130
- @classproperty
131
- @classmethod
132
- def BIN_PATH(cls):
133
- """The node bin path.
134
-
135
- Returns:
136
- The node bin path.
137
- """
138
- return (
139
- Fnm.DIR
140
- / "node-versions"
141
- / f"v{cls.VERSION}"
142
- / "installation"
143
- / ("bin" if not IS_WINDOWS else "")
144
- )
145
-
146
- @classproperty
147
- @classmethod
148
- def PATH(cls):
149
- """The default path where node is installed.
150
-
151
- Returns:
152
- The default path where node is installed.
153
- """
154
- return cls.BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
155
-
156
- @classproperty
157
- @classmethod
158
- def NPM_PATH(cls):
159
- """The default path where npm is installed.
160
-
161
- Returns:
162
- The default path where npm is installed.
163
- """
164
- return cls.BIN_PATH / "npm"
165
-
166
69
 
167
70
  class PackageJson(SimpleNamespace):
168
71
  """Constants used to build the package.json file."""
@@ -179,11 +82,11 @@ class PackageJson(SimpleNamespace):
179
82
 
180
83
  DEPENDENCIES = {
181
84
  "@emotion/react": "11.14.0",
182
- "axios": "1.7.9",
85
+ "axios": "1.8.3",
183
86
  "json5": "2.2.3",
184
- "next": "15.1.7",
87
+ "next": "15.0.4",
185
88
  "next-sitemap": "4.2.3",
186
- "next-themes": "0.4.4",
89
+ "next-themes": "0.4.6",
187
90
  "react": "19.0.0",
188
91
  "react-dom": "19.0.0",
189
92
  "react-focus-lock": "2.13.6",
@@ -191,8 +94,8 @@ class PackageJson(SimpleNamespace):
191
94
  "universal-cookie": "7.2.2",
192
95
  }
193
96
  DEV_DEPENDENCIES = {
194
- "autoprefixer": "10.4.20",
195
- "postcss": "8.5.1",
97
+ "autoprefixer": "10.4.21",
98
+ "postcss": "8.5.3",
196
99
  "postcss-import": "16.1.0",
197
100
  }
198
101
  OVERRIDES = {
@@ -826,12 +826,19 @@ def _collect_details_for_gallery():
826
826
  Raises:
827
827
  Exit: If pyproject.toml file is ill-formed or the request to the backend services fails.
828
828
  """
829
+ import reflex_cli.constants
829
830
  from reflex_cli.utils import hosting
830
831
 
831
832
  console.rule("[bold]Authentication with Reflex Services")
832
833
  console.print("First let's log in to Reflex backend services.")
833
834
  access_token, _ = hosting.authenticated_token()
834
835
 
836
+ if not access_token:
837
+ console.error(
838
+ "Unable to authenticate with Reflex backend services. Make sure you are logged in."
839
+ )
840
+ raise typer.Exit(code=1)
841
+
835
842
  console.rule("[bold]Custom Component Information")
836
843
  params = {}
837
844
  package_name = None
@@ -845,10 +852,8 @@ def _collect_details_for_gallery():
845
852
  console.print(f"[ Custom component package name ] : {package_name}")
846
853
  params["package_name"] = package_name
847
854
 
848
- config = get_config()
849
-
850
855
  post_custom_components_gallery_endpoint = (
851
- f"{config.cp_backend_url}/custom-components/gallery"
856
+ f"{reflex_cli.constants.Hosting.HOSTING_SERVICE}/custom-components/gallery"
852
857
  )
853
858
 
854
859
  # Check the backend services if the user is allowed to update information of this package is already shared.
reflex/reflex.py CHANGED
@@ -7,13 +7,14 @@ from pathlib import Path
7
7
 
8
8
  import typer
9
9
  import typer.core
10
- from reflex_cli.v2.deployments import check_version, hosting_cli
10
+ from reflex_cli.v2.deployments import hosting_cli
11
11
 
12
12
  from reflex import constants
13
13
  from reflex.config import environment, get_config
14
14
  from reflex.custom_components.custom_components import custom_components_cli
15
15
  from reflex.state import reset_disk_state_manager
16
16
  from reflex.utils import console, redir, telemetry
17
+ from reflex.utils.exec import should_use_granian
17
18
 
18
19
  # Disable typer+rich integration for help panels
19
20
  typer.core.rich = None # pyright: ignore [reportPrivateImportUsage]
@@ -203,9 +204,23 @@ def _run(
203
204
 
204
205
  prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
205
206
 
206
- if frontend:
207
- # Get the app module.
208
- prerequisites.get_compiled_app()
207
+ # Get the app module.
208
+ app_task = prerequisites.compile_or_validate_app
209
+ args = (frontend,)
210
+
211
+ # Granian fails if the app is already imported.
212
+ if should_use_granian():
213
+ import concurrent.futures
214
+
215
+ compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
216
+ app_task,
217
+ *args,
218
+ )
219
+ validation_result = compile_future.result()
220
+ else:
221
+ validation_result = app_task(*args)
222
+ if not validation_result:
223
+ raise typer.Exit(1)
209
224
 
210
225
  # Warn if schema is not up to date.
211
226
  prerequisites.check_schema_up_to_date()
@@ -386,6 +401,7 @@ def export(
386
401
  def login(loglevel: constants.LogLevel | None = typer.Option(None)):
387
402
  """Authenticate with experimental Reflex hosting service."""
388
403
  from reflex_cli.v2 import cli as hosting_cli
404
+ from reflex_cli.v2.deployments import check_version
389
405
 
390
406
  loglevel = loglevel or get_config().loglevel
391
407
 
@@ -407,6 +423,7 @@ def logout(
407
423
  ):
408
424
  """Log out of access to Reflex hosting service."""
409
425
  from reflex_cli.v2.cli import logout
426
+ from reflex_cli.v2.deployments import check_version
410
427
 
411
428
  check_version()
412
429
 
@@ -567,6 +584,7 @@ def deploy(
567
584
  from reflex_cli.constants.base import LogLevel as HostingLogLevel
568
585
  from reflex_cli.utils import dependency
569
586
  from reflex_cli.v2 import cli as hosting_cli
587
+ from reflex_cli.v2.deployments import check_version
570
588
 
571
589
  from reflex.utils import export as export_utils
572
590
  from reflex.utils import prerequisites
reflex/state.py CHANGED
@@ -905,7 +905,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
905
905
  ]
906
906
  if len(parent_states) >= 2:
907
907
  raise ValueError(f"Only one parent state is allowed {parent_states}.")
908
- return parent_states[0] if len(parent_states) == 1 else None
908
+ # The first non-mixin state in the mro is our parent.
909
+ for base in cls.mro()[1:]:
910
+ if not issubclass(base, BaseState) or base._mixin:
911
+ continue
912
+ if base is BaseState:
913
+ break
914
+ return base
915
+ return None # No known parent
909
916
 
910
917
  @classmethod
911
918
  @functools.lru_cache()
@@ -1664,6 +1671,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1664
1671
 
1665
1672
  raise TypeError(
1666
1673
  f"Your handler {handler.fn.__qualname__} must only return/yield: None, Events or other EventHandlers referenced by their class (i.e. using `type(self)` or other class references)."
1674
+ f" Returned events of types {', '.join(map(str, map(type, events)))!s}."
1667
1675
  )
1668
1676
 
1669
1677
  async def _as_state_update(
reflex/testing.py CHANGED
@@ -371,7 +371,13 @@ class AppHarness:
371
371
 
372
372
  # Start the frontend.
373
373
  self.frontend_process = reflex.utils.processes.new_process(
374
- [reflex.utils.prerequisites.get_package_manager(), "run", "dev"],
374
+ [
375
+ *reflex.utils.prerequisites.get_js_package_executor(raise_on_none=True)[
376
+ 0
377
+ ],
378
+ "run",
379
+ "dev",
380
+ ],
375
381
  cwd=self.app_path / reflex.utils.prerequisites.get_web_dir(),
376
382
  env={"PORT": "0"},
377
383
  **FRONTEND_POPEN_ARGS,
reflex/utils/build.py CHANGED
@@ -212,7 +212,7 @@ def build(
212
212
 
213
213
  # Start the subprocess with the progress bar.
214
214
  process = processes.new_process(
215
- [prerequisites.get_package_manager(), "run", command],
215
+ [*prerequisites.get_js_package_executor(raise_on_none=True)[0], "run", command],
216
216
  cwd=wdir,
217
217
  shell=constants.IS_WINDOWS,
218
218
  )
@@ -231,11 +231,10 @@ def setup_frontend(
231
231
  """
232
232
  # Create the assets dir if it doesn't exist.
233
233
  path_ops.mkdir(constants.Dirs.APP_ASSETS)
234
-
235
- # Copy asset files to public folder.
236
234
  path_ops.cp(
237
235
  src=str(root / constants.Dirs.APP_ASSETS),
238
236
  dest=str(root / prerequisites.get_web_dir() / constants.Dirs.PUBLIC),
237
+ ignore=tuple(f"*.{ext}" for ext in constants.Reflex.STYLESHEETS_SUPPORTED),
239
238
  )
240
239
 
241
240
  # Set the environment variables in client (env.json).
@@ -248,7 +247,7 @@ def setup_frontend(
248
247
  if disable_telemetry:
249
248
  processes.new_process(
250
249
  [
251
- prerequisites.get_package_manager(),
250
+ *prerequisites.get_js_package_executor(raise_on_none=True)[0],
252
251
  "run",
253
252
  "next",
254
253
  "telemetry",