Skip to content

Commit e978a42

Browse files
committed
Merge branch 'main' into release/reflex-0.7.4
2 parents 0e29a8e + 6d49cfb commit e978a42

File tree

17 files changed

+265
-367
lines changed

17 files changed

+265
-367
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ dependencies = [
2626
"distro >=1.8.0,<2.0; platform_system == 'Linux'",
2727
"fastapi >=0.96.0,!=0.111.0,!=0.111.1",
2828
"granian[reload] >=2.0.0",
29+
"gunicorn >=23.0.0,<24.0.0",
2930
"httpx >=0.25.1,<1.0",
3031
"jinja2 >=3.1.2,<4.0",
3132
"lazy_loader >=0.4",
@@ -46,6 +47,7 @@ dependencies = [
4647
"twine >=4.0.0,<7.0",
4748
"typer >=0.15.1,<1.0",
4849
"typing_extensions >=4.6.0",
50+
"uvicorn >=0.20.0",
4951
"wheel >=0.42.0,<1.0",
5052
"wrapt >=1.17.0,<2.0",
5153
]
@@ -161,5 +163,4 @@ dev = [
161163
"ruff ==0.11.0",
162164
"selenium >=4.11.0,<5.0",
163165
"toml >=0.10.2,<1.0",
164-
"uvicorn >=0.20.0",
165166
]

reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTheme } from "next-themes";
2-
import { useEffect, useState } from "react";
2+
import { useRef, useEffect, useState } from "react";
33
import {
44
ColorModeContext,
55
defaultColorMode,
@@ -13,6 +13,14 @@ export default function RadixThemesColorModeProvider({ children }) {
1313
const [resolvedColorMode, setResolvedColorMode] = useState(
1414
defaultColorMode === "dark" ? "dark" : "light",
1515
);
16+
const firstUpdate = useRef(true);
17+
useEffect(() => {
18+
if (firstUpdate.current) {
19+
firstUpdate.current = false;
20+
setRawColorMode(theme);
21+
setResolvedColorMode(resolvedTheme);
22+
}
23+
});
1624

1725
useEffect(() => {
1826
if (isDevMode) {

reflex/app.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@ def _should_compile(self) -> bool:
968968
# Check the nocompile file.
969969
if nocompile.exists():
970970
# Delete the nocompile file
971-
nocompile.unlink()
971+
nocompile.unlink(missing_ok=True)
972972
return False
973973

974974
# By default, compile the app.
@@ -1258,7 +1258,9 @@ def memoized_toast_provider():
12581258
compiler.compile_document_root(
12591259
self.head_components,
12601260
html_lang=self.html_lang,
1261-
html_custom_attrs=self.html_custom_attrs, # pyright: ignore [reportArgumentType]
1261+
html_custom_attrs=(
1262+
{**self.html_custom_attrs} if self.html_custom_attrs else {}
1263+
),
12621264
)
12631265
)
12641266

reflex/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def validate_field_name(bases: list[Type["BaseModel"]], field_name: str) -> None
3838

3939
# monkeypatch pydantic validate_field_name method to skip validating
4040
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
41-
pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
41+
pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPrivateImportUsage]
4242

4343
if TYPE_CHECKING:
4444
from reflex.vars import Var
@@ -107,7 +107,7 @@ def add_field(cls, var: Var, default_value: Any):
107107
default_value: The default value of the field
108108
"""
109109
var_name = var._var_field_name
110-
new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
110+
new_field = ModelField.infer(
111111
name=var_name,
112112
value=default_value,
113113
annotation=var._var_type,
@@ -128,5 +128,5 @@ def get_value(self, key: str) -> Any:
128128
if isinstance(key, str):
129129
# Seems like this function signature was wrong all along?
130130
# If the user wants a field that we know of, get it and pass it off to _get_value
131-
return getattr(self, key, key)
131+
return getattr(self, key)
132132
return key

reflex/compiler/compiler.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from reflex.state import BaseState
2121
from reflex.style import SYSTEM_COLOR_MODE
2222
from reflex.utils import console, path_ops
23+
from reflex.utils.exceptions import ReflexError
2324
from reflex.utils.exec import is_prod_mode
2425
from reflex.utils.imports import ImportVar
2526
from reflex.utils.prerequisites import get_web_dir
@@ -651,13 +652,17 @@ def into_component(component: Component | ComponentCallable) -> Component:
651652
):
652653
return converted
653654
except KeyError as e:
655+
if isinstance(e, ReflexError):
656+
raise
654657
key = e.args[0] if e.args else None
655658
if key is not None and isinstance(key, Var):
656659
raise TypeError(
657660
"Cannot access a primitive map with a Var. Consider calling rx.Var.create() on the map."
658661
).with_traceback(e.__traceback__) from None
659662
raise
660663
except TypeError as e:
664+
if isinstance(e, ReflexError):
665+
raise
661666
message = e.args[0] if e.args else None
662667
if message and isinstance(message, str):
663668
if message.endswith("has no len()") and (

reflex/components/component.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import contextlib
56
import copy
67
import dataclasses
78
import functools
@@ -1974,13 +1975,15 @@ def _get_imports(self) -> ParsedImportDict:
19741975
# Do NOT import the main library/tag statically.
19751976
import_name = self._get_import_name()
19761977
if import_name is not None:
1977-
_imports[import_name] = [
1978+
with contextlib.suppress(ValueError):
1979+
_imports[import_name].remove(self.import_var)
1980+
_imports[import_name].append(
19781981
imports.ImportVar(
19791982
tag=None,
19801983
render=False,
19811984
transpile=self._should_transpile(self.library),
1982-
),
1983-
]
1985+
)
1986+
)
19841987

19851988
return imports.merge_imports(
19861989
dynamic_import,

reflex/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
)
4545

4646
try:
47-
from dotenv import load_dotenv # pyright: ignore [reportMissingImports]
47+
from dotenv import load_dotenv
4848
except ImportError:
4949
load_dotenv = None
5050

reflex/reflex.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,18 +205,22 @@ def _run(
205205
prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
206206

207207
# Get the app module.
208-
app_task = prerequisites.compile_app if frontend else prerequisites.validate_app
208+
app_task = prerequisites.compile_or_validate_app
209+
args = (frontend,)
209210

210211
# Granian fails if the app is already imported.
211212
if should_use_granian():
212213
import concurrent.futures
213214

214215
compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
215-
app_task
216+
app_task,
217+
*args,
216218
)
217-
compile_future.result()
219+
validation_result = compile_future.result()
218220
else:
219-
app_task()
221+
validation_result = app_task(*args)
222+
if not validation_result:
223+
raise typer.Exit(1)
220224

221225
# Warn if schema is not up to date.
222226
prerequisites.check_schema_up_to_date()

reflex/utils/exec.py

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,11 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
189189

190190
@once
191191
def _warn_user_about_uvicorn():
192-
console.warn(
193-
"Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
194-
)
192+
# When we eventually switch to Granian by default, we should enable this warning.
193+
if False:
194+
console.warn(
195+
"Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
196+
)
195197

196198

197199
def should_use_granian():
@@ -357,70 +359,74 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
357359
).serve()
358360

359361

362+
def _deprecate_asgi_config(
363+
config_name: str,
364+
reason: str = "",
365+
):
366+
# When we eventually switch to Granian by default, we should enable this deprecation.
367+
if False:
368+
console.deprecate(
369+
f"config.{config_name}",
370+
reason=reason,
371+
deprecation_version="0.7.5",
372+
removal_version="0.8.0",
373+
)
374+
375+
360376
@once
361377
def _get_backend_workers():
362378
from reflex.utils import processes
363379

364380
config = get_config()
365381

382+
gunicorn_workers = config.gunicorn_workers or 0
383+
366384
if config.gunicorn_workers is not None:
367-
console.deprecate(
368-
"config.gunicorn_workers",
369-
reason="If you're using Granian, use GRANIAN_WORKERS instead.",
370-
deprecation_version="0.7.4",
371-
removal_version="0.8.0",
385+
_deprecate_asgi_config(
386+
"gunicorn_workers",
387+
"If you're using Granian, use GRANIAN_WORKERS instead.",
372388
)
373389

374-
return (
375-
processes.get_num_workers()
376-
if not config.gunicorn_workers
377-
else config.gunicorn_workers
378-
)
390+
return gunicorn_workers if gunicorn_workers else processes.get_num_workers()
379391

380392

381393
@once
382394
def _get_backend_timeout():
383395
config = get_config()
384396

397+
timeout = config.timeout or 120
398+
385399
if config.timeout is not None:
386-
console.deprecate(
387-
"config.timeout",
388-
reason="If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
389-
deprecation_version="0.7.4",
390-
removal_version="0.8.0",
400+
_deprecate_asgi_config(
401+
"timeout",
402+
"If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
391403
)
392404

393-
return config.timeout
405+
return timeout
394406

395407

396408
@once
397409
def _get_backend_max_requests():
398410
config = get_config()
399411

412+
gunicorn_max_requests = config.gunicorn_max_requests or 120
413+
400414
if config.gunicorn_max_requests is not None:
401-
console.deprecate(
402-
"config.gunicorn_max_requests",
403-
reason="",
404-
deprecation_version="0.7.4",
405-
removal_version="0.8.0",
406-
)
415+
_deprecate_asgi_config("gunicorn_max_requests")
407416

408-
return config.gunicorn_max_requests
417+
return gunicorn_max_requests
409418

410419

411420
@once
412421
def _get_backend_max_requests_jitter():
413422
config = get_config()
414423

424+
gunicorn_max_requests_jitter = config.gunicorn_max_requests_jitter or 25
425+
415426
if config.gunicorn_max_requests_jitter is not None:
416-
console.deprecate(
417-
"config.gunicorn_max_requests_jitter",
418-
reason="",
419-
deprecation_version="0.7.4",
420-
removal_version="0.8.0",
421-
)
427+
_deprecate_asgi_config("gunicorn_max_requests_jitter")
422428

423-
return config.gunicorn_max_requests_jitter
429+
return gunicorn_max_requests_jitter
424430

425431

426432
def run_backend_prod(

0 commit comments

Comments
 (0)