reflex 0.7.3a1__py3-none-any.whl → 0.7.4a0__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.

@@ -456,7 +456,7 @@ export const connect = async (
456
456
  console.log("Disconnect websocket on unload");
457
457
  socket.current.disconnect();
458
458
  }
459
- }
459
+ };
460
460
 
461
461
  const pagehideHandler = (event) => {
462
462
  if (event.persisted && socket.current?.connected) {
reflex/app.py CHANGED
@@ -1063,7 +1063,7 @@ class App(MiddlewareMixin, LifespanMixin):
1063
1063
  with stateful_pages_marker.open("r") as f:
1064
1064
  stateful_pages = json.load(f)
1065
1065
  for route in stateful_pages:
1066
- console.info(f"BE Evaluating stateful page: {route}")
1066
+ console.debug(f"BE Evaluating stateful page: {route}")
1067
1067
  self._compile_page(route, save_page=False)
1068
1068
  self._enable_state()
1069
1069
  self._add_optional_endpoints()
@@ -74,6 +74,7 @@ class MiddlewareMixin(AppMixin):
74
74
  Returns:
75
75
  The state update to return.
76
76
  """
77
+ out = update
77
78
  for middleware in self._middlewares:
78
79
  if asyncio.iscoroutinefunction(middleware.postprocess):
79
80
  out = await middleware.postprocess(
@@ -89,6 +90,4 @@ class MiddlewareMixin(AppMixin):
89
90
  event=event,
90
91
  update=update,
91
92
  )
92
- if out is not None:
93
- return out # pyright: ignore [reportReturnType]
94
- return update
93
+ return out # pyright: ignore[reportReturnType]
@@ -19,6 +19,7 @@ from reflex.components.component import (
19
19
  from reflex.config import environment, get_config
20
20
  from reflex.state import BaseState
21
21
  from reflex.style import SYSTEM_COLOR_MODE
22
+ from reflex.utils import console, path_ops
22
23
  from reflex.utils.exec import is_prod_mode
23
24
  from reflex.utils.imports import ImportVar
24
25
  from reflex.utils.prerequisites import get_web_dir
@@ -190,18 +191,74 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
190
191
  if get_config().tailwind is not None
191
192
  else []
192
193
  )
194
+
195
+ failed_to_import_sass = False
193
196
  for stylesheet in stylesheets:
194
197
  if not utils.is_valid_url(stylesheet):
195
198
  # check if stylesheet provided exists.
196
- stylesheet_full_path = (
197
- Path.cwd() / constants.Dirs.APP_ASSETS / stylesheet.strip("/")
198
- )
199
+ assets_app_path = Path.cwd() / constants.Dirs.APP_ASSETS
200
+ stylesheet_full_path = assets_app_path / stylesheet.strip("/")
201
+
199
202
  if not stylesheet_full_path.exists():
200
203
  raise FileNotFoundError(
201
204
  f"The stylesheet file {stylesheet_full_path} does not exist."
202
205
  )
203
- stylesheet = f"../{constants.Dirs.PUBLIC}/{stylesheet.strip('/')}"
206
+
207
+ if stylesheet_full_path.is_dir():
208
+ # NOTE: this can create an infinite loop, for example:
209
+ # assets/
210
+ # | dir_a/
211
+ # | | dir_c/ (symlink to "assets/dir_a")
212
+ # | dir_b/
213
+ # so to avoid the infinite loop, we don't include symbolic links
214
+ stylesheets += [
215
+ str(p.relative_to(assets_app_path))
216
+ for p in stylesheet_full_path.iterdir()
217
+ if not (p.is_symlink() and p.is_dir())
218
+ ]
219
+ continue
220
+
221
+ if (
222
+ stylesheet_full_path.suffix[1:].lower()
223
+ in constants.Reflex.STYLESHEETS_SUPPORTED
224
+ ):
225
+ target = (
226
+ Path.cwd()
227
+ / constants.Dirs.WEB
228
+ / constants.Dirs.STYLES
229
+ / (stylesheet.rsplit(".", 1)[0].strip("/") + ".css")
230
+ )
231
+ target.parent.mkdir(parents=True, exist_ok=True)
232
+
233
+ if stylesheet_full_path.suffix == ".css":
234
+ path_ops.cp(src=stylesheet_full_path, dest=target, overwrite=True)
235
+ else:
236
+ try:
237
+ from sass import compile as sass_compile
238
+
239
+ target.write_text(
240
+ data=sass_compile(
241
+ filename=str(stylesheet_full_path),
242
+ output_style="compressed",
243
+ ),
244
+ encoding="utf8",
245
+ )
246
+ except ImportError:
247
+ failed_to_import_sass = True
248
+ else:
249
+ raise FileNotFoundError(
250
+ f'The stylesheet file "{stylesheet_full_path}" is not a valid file.'
251
+ )
252
+
253
+ stylesheet = f"./{stylesheet.rsplit('.', 1)[0].strip('/')}.css"
254
+
204
255
  sheets.append(stylesheet) if stylesheet not in sheets else None
256
+
257
+ if failed_to_import_sass:
258
+ console.error(
259
+ 'The `libsass` package is required to compile sass/scss stylesheet files. Run `pip install "libsass>=0.23.0"`.'
260
+ )
261
+
205
262
  return templates.STYLE.render(stylesheets=sheets)
206
263
 
207
264
 
@@ -190,7 +190,7 @@ class GhostUpload(Fragment):
190
190
  class Upload(MemoizationLeaf):
191
191
  """A file upload component."""
192
192
 
193
- library = "react-dropzone@14.3.5"
193
+ library = "react-dropzone@14.3.8"
194
194
 
195
195
  tag = ""
196
196
 
@@ -71,7 +71,7 @@ class Plotly(NoSSRComponent):
71
71
 
72
72
  library = "react-plotly.js@2.6.0"
73
73
 
74
- lib_dependencies: list[str] = ["plotly.js@2.35.3"]
74
+ lib_dependencies: list[str] = ["plotly.js@3.0.1"]
75
75
 
76
76
  tag = "Plot"
77
77
 
@@ -289,7 +289,7 @@ class PlotlyBasic(Plotly):
289
289
 
290
290
  library = "react-plotly.js@2.6.0"
291
291
 
292
- lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.0"]
292
+ lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.1"]
293
293
 
294
294
  def add_imports(self) -> ImportDict | list[ImportDict]:
295
295
  """Add imports for the plotly basic component.
@@ -315,7 +315,7 @@ class PlotlyCartesian(Plotly):
315
315
 
316
316
  library = "react-plotly.js@2.6.0"
317
317
 
318
- lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.0"]
318
+ lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.1"]
319
319
 
320
320
  def add_imports(self) -> ImportDict | list[ImportDict]:
321
321
  """Add imports for the plotly cartesian component.
@@ -341,7 +341,7 @@ class PlotlyGeo(Plotly):
341
341
 
342
342
  library = "react-plotly.js@2.6.0"
343
343
 
344
- lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.0"]
344
+ lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.1"]
345
345
 
346
346
  def add_imports(self) -> ImportDict | list[ImportDict]:
347
347
  """Add imports for the plotly geo component.
@@ -367,7 +367,7 @@ class PlotlyGl3d(Plotly):
367
367
 
368
368
  library = "react-plotly.js@2.6.0"
369
369
 
370
- lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.0"]
370
+ lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.1"]
371
371
 
372
372
  def add_imports(self) -> ImportDict | list[ImportDict]:
373
373
  """Add imports for the plotly 3d component.
@@ -393,7 +393,7 @@ class PlotlyGl2d(Plotly):
393
393
 
394
394
  library = "react-plotly.js@2.6.0"
395
395
 
396
- lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.0"]
396
+ lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.1"]
397
397
 
398
398
  def add_imports(self) -> ImportDict | list[ImportDict]:
399
399
  """Add imports for the plotly 2d component.
@@ -419,7 +419,7 @@ class PlotlyMapbox(Plotly):
419
419
 
420
420
  library = "react-plotly.js@2.6.0"
421
421
 
422
- lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.0"]
422
+ lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.1"]
423
423
 
424
424
  def add_imports(self) -> ImportDict | list[ImportDict]:
425
425
  """Add imports for the plotly mapbox component.
@@ -445,7 +445,7 @@ class PlotlyFinance(Plotly):
445
445
 
446
446
  library = "react-plotly.js@2.6.0"
447
447
 
448
- lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.0"]
448
+ lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.1"]
449
449
 
450
450
  def add_imports(self) -> ImportDict | list[ImportDict]:
451
451
  """Add imports for the plotly finance component.
@@ -471,7 +471,7 @@ class PlotlyStrict(Plotly):
471
471
 
472
472
  library = "react-plotly.js@2.6.0"
473
473
 
474
- lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.0"]
474
+ lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.1"]
475
475
 
476
476
  def add_imports(self) -> ImportDict | list[ImportDict]:
477
477
  """Add imports for the plotly strict component.
@@ -8,7 +8,7 @@ from reflex.components.component import Component, MemoizationLeaf, NoSSRCompone
8
8
  class Recharts(Component):
9
9
  """A component that wraps a recharts lib."""
10
10
 
11
- library = "recharts@2.15.0"
11
+ library = "recharts@2.15.1"
12
12
 
13
13
  def _get_style(self) -> dict:
14
14
  return {"wrapperStyle": self.style}
@@ -17,7 +17,7 @@ class Recharts(Component):
17
17
  class RechartsCharts(NoSSRComponent, MemoizationLeaf):
18
18
  """A component that wraps a recharts lib."""
19
19
 
20
- library = "recharts@2.15.0"
20
+ library = "recharts@2.15.1"
21
21
 
22
22
 
23
23
  LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
@@ -172,7 +172,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
172
172
  class Toaster(Component):
173
173
  """A Toaster Component for displaying toast notifications."""
174
174
 
175
- library: str | None = "sonner@1.7.2"
175
+ library: str | None = "sonner@2.0.1"
176
176
 
177
177
  tag = "Toaster"
178
178
 
reflex/config.py CHANGED
@@ -596,7 +596,7 @@ class EnvironmentVariables:
596
596
  constants.CompileContext.UNDEFINED, internal=True
597
597
  )
598
598
 
599
- # Whether to use npm over bun to install frontend packages.
599
+ # Whether to use npm over bun to install and run the frontend.
600
600
  REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
601
601
 
602
602
  # The npm registry to use.
@@ -614,9 +614,6 @@ class EnvironmentVariables:
614
614
  # Whether to use the system installed bun. If set to false, bun will be bundled with the app.
615
615
  REFLEX_USE_SYSTEM_BUN: EnvVar[bool] = env_var(False)
616
616
 
617
- # Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
618
- REFLEX_USE_SYSTEM_NODE: EnvVar[bool] = env_var(False)
619
-
620
617
  # The working directory for the next.js commands.
621
618
  REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
622
619
 
@@ -964,7 +961,7 @@ class Config(Base):
964
961
  env_var = "***"
965
962
 
966
963
  if value != getattr(self, key):
967
- console.info(
964
+ console.debug(
968
965
  f"Overriding config value {key} with env var {key.upper()}={env_var}",
969
966
  dedupe=True,
970
967
  )
@@ -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 = {
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 base._mixin or not issubclass(base, BaseState):
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()
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",
reflex/utils/exec.py CHANGED
@@ -154,7 +154,11 @@ def run_frontend(root: Path, port: str, backend_present: bool = True):
154
154
  console.rule("[bold green]App Running")
155
155
  os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
156
156
  run_process_and_launch_url(
157
- [prerequisites.get_package_manager(), "run", "dev"],
157
+ [
158
+ *prerequisites.get_js_package_executor(raise_on_none=True)[0],
159
+ "run",
160
+ "dev",
161
+ ],
158
162
  backend_present,
159
163
  )
160
164
 
@@ -176,7 +180,7 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
176
180
  # Run the frontend in production mode.
177
181
  console.rule("[bold green]App Running")
178
182
  run_process_and_launch_url(
179
- [prerequisites.get_package_manager(), "run", "prod"],
183
+ [*prerequisites.get_js_package_executor(raise_on_none=True)[0], "run", "prod"],
180
184
  backend_present,
181
185
  )
182
186
 
@@ -518,13 +522,8 @@ def output_system_info():
518
522
 
519
523
  system = platform.system()
520
524
 
521
- fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
522
-
523
- dependencies.extend(
524
- [
525
- fnm_info,
526
- f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
527
- ],
525
+ dependencies.append(
526
+ f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]"
528
527
  )
529
528
 
530
529
  if system == "Linux":
@@ -540,10 +539,10 @@ def output_system_info():
540
539
  console.debug(f"{dep}")
541
540
 
542
541
  console.debug(
543
- f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}"
542
+ f"Using package installer at: {prerequisites.get_nodejs_compatible_package_managers(raise_on_none=False)}"
544
543
  )
545
544
  console.debug(
546
- f"Using package executer at: {prerequisites.get_package_manager(on_failure_return_none=True)}"
545
+ f"Using package executer at: {prerequisites.get_js_package_executor(raise_on_none=False)}"
547
546
  )
548
547
  if system != "Windows":
549
548
  console.debug(f"Unzip path: {path_ops.which('unzip')}")
reflex/utils/path_ops.py CHANGED
@@ -9,7 +9,6 @@ import shutil
9
9
  import stat
10
10
  from pathlib import Path
11
11
 
12
- from reflex import constants
13
12
  from reflex.config import environment, get_config
14
13
 
15
14
  # Shorthand for join.
@@ -43,13 +42,19 @@ def rm(path: str | Path):
43
42
  path.unlink()
44
43
 
45
44
 
46
- def cp(src: str | Path, dest: str | Path, overwrite: bool = True) -> bool:
45
+ def cp(
46
+ src: str | Path,
47
+ dest: str | Path,
48
+ overwrite: bool = True,
49
+ ignore: tuple[str, ...] | None = None,
50
+ ) -> bool:
47
51
  """Copy a file or directory.
48
52
 
49
53
  Args:
50
54
  src: The path to the file or directory.
51
55
  dest: The path to the destination.
52
56
  overwrite: Whether to overwrite the destination.
57
+ ignore: Ignoring files and directories that match one of the glob-style patterns provided
53
58
 
54
59
  Returns:
55
60
  Whether the copy was successful.
@@ -61,7 +66,11 @@ def cp(src: str | Path, dest: str | Path, overwrite: bool = True) -> bool:
61
66
  return False
62
67
  if src.is_dir():
63
68
  rm(dest)
64
- shutil.copytree(src, dest)
69
+ shutil.copytree(
70
+ src,
71
+ dest,
72
+ ignore=shutil.ignore_patterns(*ignore) if ignore is not None else ignore,
73
+ )
65
74
  else:
66
75
  shutil.copyfile(src, dest)
67
76
  return True
@@ -146,15 +155,6 @@ def which(program: str | Path) -> Path | None:
146
155
  return Path(which_result) if which_result else None
147
156
 
148
157
 
149
- def use_system_node() -> bool:
150
- """Check if the system node should be used.
151
-
152
- Returns:
153
- Whether the system node should be used.
154
- """
155
- return environment.REFLEX_USE_SYSTEM_NODE.get()
156
-
157
-
158
158
  def use_system_bun() -> bool:
159
159
  """Check if the system bun should be used.
160
160
 
@@ -170,11 +170,7 @@ def get_node_bin_path() -> Path | None:
170
170
  Returns:
171
171
  The path to the node bin folder.
172
172
  """
173
- bin_path = Path(constants.Node.BIN_PATH)
174
- if not bin_path.exists():
175
- path = which("node")
176
- return path.parent.absolute() if path else None
177
- return bin_path.absolute()
173
+ return bin_path.parent.absolute() if (bin_path := get_node_path()) else None
178
174
 
179
175
 
180
176
  def get_node_path() -> Path | None:
@@ -183,10 +179,7 @@ def get_node_path() -> Path | None:
183
179
  Returns:
184
180
  The path to the node binary file.
185
181
  """
186
- node_path = Path(constants.Node.PATH)
187
- if use_system_node() or not node_path.exists():
188
- node_path = which("node")
189
- return node_path
182
+ return which("node")
190
183
 
191
184
 
192
185
  def get_npm_path() -> Path | None:
@@ -195,10 +188,7 @@ def get_npm_path() -> Path | None:
195
188
  Returns:
196
189
  The path to the npm binary file.
197
190
  """
198
- npm_path = Path(constants.Node.NPM_PATH)
199
- if use_system_node() or not npm_path.exists():
200
- npm_path = which("npm")
201
- return npm_path.absolute() if npm_path else None
191
+ return npm_path.absolute() if (npm_path := which("npm")) else None
202
192
 
203
193
 
204
194
  def get_bun_path() -> Path | None: