Skip to content

Commit d7a20f2

Browse files
committed
Merge branch 'main' into disable-react-strict-mode-for-event-loop
2 parents 59d5092 + 3cb4443 commit d7a20f2

File tree

12 files changed

+1122
-503
lines changed

12 files changed

+1122
-503
lines changed

reflex/app.py

+33-16
Original file line numberDiff line numberDiff line change
@@ -909,11 +909,17 @@ def _validate_var_dependencies(
909909
if not var._cache:
910910
continue
911911
deps = var._deps(objclass=state)
912-
for dep in deps:
913-
if dep not in state.vars and dep not in state.backend_vars:
914-
raise exceptions.VarDependencyError(
915-
f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {dep}"
916-
)
912+
for state_name, dep_set in deps.items():
913+
state_cls = (
914+
state.get_root_state().get_class_substate(state_name)
915+
if state_name != state.get_full_name()
916+
else state
917+
)
918+
for dep in dep_set:
919+
if dep not in state_cls.vars and dep not in state_cls.backend_vars:
920+
raise exceptions.VarDependencyError(
921+
f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {state_name}.{dep}"
922+
)
917923

918924
for substate in state.class_subclasses:
919925
self._validate_var_dependencies(substate)
@@ -959,20 +965,16 @@ def get_compilation_time() -> str:
959965

960966
should_compile = self._should_compile()
961967

962-
for route in self._unevaluated_pages:
963-
console.debug(f"Evaluating page: {route}")
964-
self._compile_page(route, save_page=should_compile)
968+
if not should_compile:
969+
for route in self._unevaluated_pages:
970+
console.debug(f"Evaluating page: {route}")
971+
self._compile_page(route, save_page=should_compile)
965972

966-
# Add the optional endpoints (_upload)
967-
self._add_optional_endpoints()
973+
# Add the optional endpoints (_upload)
974+
self._add_optional_endpoints()
968975

969-
if not should_compile:
970976
return
971977

972-
self._validate_var_dependencies()
973-
self._setup_overlay_component()
974-
self._setup_error_boundary()
975-
976978
# Create a progress bar.
977979
progress = Progress(
978980
*Progress.get_default_columns()[:-1],
@@ -981,16 +983,31 @@ def get_compilation_time() -> str:
981983
)
982984

983985
# try to be somewhat accurate - but still not 100%
984-
adhoc_steps_without_executor = 6
986+
adhoc_steps_without_executor = 7
985987
fixed_pages_within_executor = 5
986988
progress.start()
987989
task = progress.add_task(
988990
f"[{get_compilation_time()}] Compiling:",
989991
total=len(self._pages)
992+
+ (len(self._unevaluated_pages) * 2)
990993
+ fixed_pages_within_executor
991994
+ adhoc_steps_without_executor,
992995
)
993996

997+
for route in self._unevaluated_pages:
998+
console.debug(f"Evaluating page: {route}")
999+
self._compile_page(route, save_page=should_compile)
1000+
progress.advance(task)
1001+
1002+
# Add the optional endpoints (_upload)
1003+
self._add_optional_endpoints()
1004+
1005+
self._validate_var_dependencies()
1006+
self._setup_overlay_component()
1007+
self._setup_error_boundary()
1008+
1009+
progress.advance(task)
1010+
9941011
# Store the compile results.
9951012
compile_results = []
9961013

reflex/compiler/compiler.py

+8
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,19 @@ def _compile_components(
239239
component_renders.append(component_render)
240240
imports = utils.merge_imports(imports, component_imports)
241241

242+
dynamic_imports = {
243+
comp_import: None
244+
for comp_render in component_renders
245+
if "dynamic_imports" in comp_render
246+
for comp_import in comp_render["dynamic_imports"]
247+
}
248+
242249
# Compile the components page.
243250
return (
244251
templates.COMPONENTS.render(
245252
imports=utils.compile_imports(imports),
246253
components=component_renders,
254+
dynamic_imports=dynamic_imports,
247255
),
248256
imports,
249257
)

reflex/compiler/utils.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
from __future__ import annotations
44

5+
import asyncio
6+
import concurrent.futures
57
import traceback
68
from datetime import datetime
79
from pathlib import Path
810
from typing import Any, Callable, Dict, Optional, Type, Union
911
from urllib.parse import urlparse
1012

13+
from reflex.utils.exec import is_in_app_harness
1114
from reflex.utils.prerequisites import get_web_dir
1215
from reflex.vars.base import Var
1316

@@ -33,7 +36,7 @@
3336
)
3437
from reflex.components.component import Component, ComponentStyle, CustomComponent
3538
from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
36-
from reflex.state import BaseState
39+
from reflex.state import BaseState, _resolve_delta
3740
from reflex.style import Style
3841
from reflex.utils import console, format, imports, path_ops
3942
from reflex.utils.imports import ImportVar, ParsedImportDict
@@ -177,7 +180,24 @@ def compile_state(state: Type[BaseState]) -> dict:
177180
initial_state = state(_reflex_internal_init=True).dict(
178181
initial=True, include_computed=False
179182
)
180-
return initial_state
183+
try:
184+
_ = asyncio.get_running_loop()
185+
except RuntimeError:
186+
pass
187+
else:
188+
if is_in_app_harness():
189+
# Playwright tests already have an event loop running, so we can't use asyncio.run.
190+
with concurrent.futures.ThreadPoolExecutor() as pool:
191+
resolved_initial_state = pool.submit(
192+
asyncio.run, _resolve_delta(initial_state)
193+
).result()
194+
console.warn(
195+
f"Had to get initial state in a thread 🤮 {resolved_initial_state}",
196+
)
197+
return resolved_initial_state
198+
199+
# Normally the compile runs before any event loop starts, we asyncio.run is available for calling.
200+
return asyncio.run(_resolve_delta(initial_state))
181201

182202

183203
def _compile_client_storage_field(
@@ -300,6 +320,7 @@ def compile_custom_component(
300320
"render": render.render(),
301321
"hooks": render._get_all_hooks(),
302322
"custom_code": render._get_all_custom_code(),
323+
"dynamic_imports": render._get_all_dynamic_imports(),
303324
},
304325
imports,
305326
)

reflex/middleware/hydrate_middleware.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from reflex import constants
99
from reflex.event import Event, get_hydrate_event
1010
from reflex.middleware.middleware import Middleware
11-
from reflex.state import BaseState, StateUpdate
11+
from reflex.state import BaseState, StateUpdate, _resolve_delta
1212

1313
if TYPE_CHECKING:
1414
from reflex.app import App
@@ -42,7 +42,7 @@ async def preprocess(
4242
setattr(state, constants.CompileVars.IS_HYDRATED, False)
4343

4444
# Get the initial state.
45-
delta = state.dict()
45+
delta = await _resolve_delta(state.dict())
4646
# since a full dict was captured, clean any dirtiness
4747
state._clean()
4848

0 commit comments

Comments
 (0)