Skip to content

Commit 046cd9b

Browse files
authored
0816dev (#5891)
* bump version and reflex * ruff * ok * bump deps * ok * precomm * precommit * no fun :(
1 parent 2cc6884 commit 046cd9b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1601
-1738
lines changed

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- uses: actions/checkout@v4
2424
- uses: ./.github/actions/setup_build_env
2525
with:
26-
python-version: 3.13
26+
python-version: 3.14
2727
run-uv-sync: true
2828
- uses: actions/checkout@v4
2929
with:

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.13
1+
3.14

pyi_hashes.json

Lines changed: 74 additions & 74 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "reflex"
3-
version = "0.8.15dev1"
3+
version = "0.8.16dev1"
44
description = "Web apps in pure Python."
55
license.text = "Apache-2.0"
66
authors = [
@@ -123,6 +123,7 @@ reportIncompatibleMethodOverride = false
123123
target-version = "py310"
124124
output-format = "concise"
125125
lint.isort.split-on-trailing-comma = false
126+
preview = true
126127
lint.select = ["ALL"]
127128
lint.ignore = [
128129
"A",
@@ -134,12 +135,18 @@ lint.ignore = [
134135
"BLE",
135136
"C901",
136137
"COM",
138+
"CPY001",
137139
"D205",
140+
"DOC202",
141+
"DOC501",
142+
"DOC502",
138143
"DTZ",
139144
"E501",
140145
"F403",
141146
"FBT",
142147
"FIX",
148+
"FURB189",
149+
"FURB140",
143150
"G004",
144151
"ISC003",
145152
"PLC",
@@ -180,6 +187,7 @@ lint.flake8-bugbear.extend-immutable-calls = [
180187
"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N", "PGH"]
181188
"pyi_generator.py" = ["N802"]
182189
"reflex/constants/*.py" = ["N"]
190+
"reflex/.templates/apps/blank/code/*" = ["INP001"]
183191
"*/blank.py" = ["I001"]
184192

185193
[tool.pytest.ini_options]
@@ -235,7 +243,7 @@ fail_fast = true
235243

236244
[[tool.pre-commit.repos]]
237245
repo = "https://github.com/astral-sh/ruff-pre-commit"
238-
rev = "v0.13.3"
246+
rev = "v0.14.0"
239247
hooks = [
240248
{ id = "ruff-format", args = [
241249
"reflex",
@@ -270,11 +278,6 @@ repo = "https://github.com/RobertCraigie/pyright-python"
270278
rev = "v1.1.406"
271279
hooks = [{ id = "pyright", args = ["reflex", "tests"], language = "system" }]
272280

273-
[[tool.pre-commit.repos]]
274-
repo = "https://github.com/terrencepreilly/darglint"
275-
rev = "v1.8.1"
276-
hooks = [{ id = "darglint", exclude = "^reflex/reflex.py" }]
277-
278281
[[tool.pre-commit.repos]]
279282
repo = "https://github.com/pre-commit/mirrors-prettier"
280283
rev = "f62a70a3a7114896b062de517d72829ea1c884b6"

reflex/app.py

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import inspect
1212
import io
1313
import json
14+
import operator
1415
import sys
1516
import time
1617
import traceback
@@ -118,6 +119,7 @@
118119
should_prerender_routes,
119120
)
120121
from reflex.utils.imports import ImportVar
122+
from reflex.utils.misc import run_in_thread
121123
from reflex.utils.token_manager import TokenManager
122124
from reflex.utils.types import ASGIApp, Message, Receive, Scope, Send
123125

@@ -849,7 +851,7 @@ def add_page(
849851

850852
# Setup dynamic args for the route.
851853
# this state assignment is only required for tests using the deprecated state kwarg for App
852-
state = self._state if self._state else State
854+
state = self._state or State
853855
state.setup_dynamic_args(get_route_args(route))
854856

855857
self._load_events[route] = (
@@ -969,14 +971,10 @@ def _setup_admin_dash(self):
969971

970972
if admin_dash and admin_dash.models:
971973
# Build the admin dashboard
972-
admin = (
973-
admin_dash.admin
974-
if admin_dash.admin
975-
else Admin(
976-
engine=Model.get_db_engine(),
977-
title="Reflex Admin Dashboard",
978-
logo_url="https://reflex.dev/Reflex.svg",
979-
)
974+
admin = admin_dash.admin or Admin(
975+
engine=Model.get_db_engine(),
976+
title="Reflex Admin Dashboard",
977+
logo_url="https://reflex.dev/Reflex.svg",
980978
)
981979

982980
for model in admin_dash.models:
@@ -1009,21 +1007,21 @@ def _get_frontend_packages(self, imports: dict[str, set[ImportVar]]):
10091007
page_imports = {i for i in page_imports if i not in pinned}
10101008

10111009
frontend_packages = get_config().frontend_packages
1012-
_frontend_packages = []
1010+
filtered_frontend_packages = []
10131011
for package in frontend_packages:
10141012
if package in page_imports:
10151013
console.warn(
10161014
f"React packages and their dependencies are inferred from Component.library and Component.lib_dependencies, remove `{package}` from `frontend_packages`"
10171015
)
10181016
continue
1019-
_frontend_packages.append(package)
1020-
page_imports.update(_frontend_packages)
1017+
filtered_frontend_packages.append(package)
1018+
page_imports.update(filtered_frontend_packages)
10211019
js_runtimes.install_frontend_packages(page_imports, get_config())
10221020

10231021
def _app_root(self, app_wrappers: dict[tuple[int, str], Component]) -> Component:
10241022
for component in tuple(app_wrappers.values()):
10251023
app_wrappers.update(component._get_all_app_wrap_components())
1026-
order = sorted(app_wrappers, key=lambda k: k[0], reverse=True)
1024+
order = sorted(app_wrappers, key=operator.itemgetter(0), reverse=True)
10271025
root = copy.deepcopy(app_wrappers[order[0]])
10281026

10291027
def reducer(parent: Component, key: tuple[int, str]) -> Component:
@@ -1095,7 +1093,7 @@ def memoized_badge():
10951093
sticky_badge._add_style_recursive({})
10961094
return sticky_badge
10971095

1098-
self.app_wraps[(0, "StickyBadge")] = lambda _: memoized_badge()
1096+
self.app_wraps[0, "StickyBadge"] = lambda _: memoized_badge()
10991097

11001098
def _apply_decorated_pages(self):
11011099
"""Add @rx.page decorated pages to the app."""
@@ -1190,13 +1188,13 @@ def get_compilation_time() -> str:
11901188

11911189
if self.theme is not None:
11921190
# If a theme component was provided, wrap the app with it
1193-
app_wrappers[(20, "Theme")] = self.theme
1191+
app_wrappers[20, "Theme"] = self.theme
11941192

11951193
# Get the env mode.
11961194
config = get_config()
11971195

11981196
if config.react_strict_mode:
1199-
app_wrappers[(200, "StrictMode")] = StrictMode.create()
1197+
app_wrappers[200, "StrictMode"] = StrictMode.create()
12001198

12011199
if not should_compile and not dry_run:
12021200
with console.timing("Evaluate Pages (Backend)"):
@@ -1251,7 +1249,7 @@ def get_compilation_time() -> str:
12511249
+ "\n".join(
12521250
f"{route}: {time * 1000:.1f}ms"
12531251
for route, time in sorted(
1254-
performance_metrics, key=lambda x: x[1], reverse=True
1252+
performance_metrics, key=operator.itemgetter(1), reverse=True
12551253
)[:10]
12561254
)
12571255
)
@@ -1295,7 +1293,7 @@ def memoized_toast_provider():
12951293

12961294
toast_provider = Fragment.create(memoized_toast_provider())
12971295

1298-
app_wrappers[(44, "ToasterProvider")] = toast_provider
1296+
app_wrappers[44, "ToasterProvider"] = toast_provider
12991297

13001298
# Add the app wraps to the app.
13011299
for key, app_wrap in chain(
@@ -1427,12 +1425,10 @@ def _submit_work_without_advancing(
14271425
plugin.pre_compile(
14281426
add_save_task=_submit_work_without_advancing,
14291427
add_modify_task=(
1430-
lambda *args, plugin=plugin: modify_files_tasks.append(
1431-
(
1432-
plugin.__class__.__module__ + plugin.__class__.__name__,
1433-
*args,
1434-
)
1435-
)
1428+
lambda *args, plugin=plugin: modify_files_tasks.append((
1429+
plugin.__class__.__module__ + plugin.__class__.__name__,
1430+
*args,
1431+
))
14361432
),
14371433
unevaluated_pages=list(self._unevaluated_pages.values()),
14381434
)
@@ -1552,7 +1548,7 @@ def add_all_routes_endpoint(self):
15521548
if not self._api:
15531549
return
15541550

1555-
async def all_routes(_request: Request) -> Response:
1551+
def all_routes(_request: Request) -> Response:
15561552
return JSONResponse(list(self._unevaluated_pages.keys()))
15571553

15581554
self._api.add_route(
@@ -1663,21 +1659,21 @@ def _validate_exception_handlers(self):
16631659
strict=True,
16641660
):
16651661
if hasattr(handler_fn, "__name__"):
1666-
_fn_name = handler_fn.__name__
1662+
fn_name_ = handler_fn.__name__
16671663
else:
1668-
_fn_name = type(handler_fn).__name__
1664+
fn_name_ = type(handler_fn).__name__
16691665

16701666
if isinstance(handler_fn, functools.partial):
1671-
msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is a partial function. Please provide a named function instead."
1667+
msg = f"Provided custom {handler_domain} exception handler `{fn_name_}` is a partial function. Please provide a named function instead."
16721668
raise ValueError(msg)
16731669

16741670
if not callable(handler_fn):
1675-
msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is not a function."
1671+
msg = f"Provided custom {handler_domain} exception handler `{fn_name_}` is not a function."
16761672
raise ValueError(msg)
16771673

16781674
# Allow named functions only as lambda functions cannot be introspected
1679-
if _fn_name == "<lambda>":
1680-
msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is a lambda function. Please use a named function instead."
1675+
if fn_name_ == "<lambda>":
1676+
msg = f"Provided custom {handler_domain} exception handler `{fn_name_}` is a lambda function. Please use a named function instead."
16811677
raise ValueError(msg)
16821678

16831679
# Check if the function has the necessary annotations and types in the right order
@@ -1690,18 +1686,18 @@ def _validate_exception_handlers(self):
16901686

16911687
for required_arg_index, required_arg in enumerate(handler_spec):
16921688
if required_arg not in arg_annotations:
1693-
msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` does not take the required argument `{required_arg}`"
1689+
msg = f"Provided custom {handler_domain} exception handler `{fn_name_}` does not take the required argument `{required_arg}`"
16941690
raise ValueError(msg)
16951691
if list(arg_annotations.keys())[required_arg_index] != required_arg:
16961692
msg = (
1697-
f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong argument order."
1693+
f"Provided custom {handler_domain} exception handler `{fn_name_}` has the wrong argument order."
16981694
f"Expected `{required_arg}` as the {required_arg_index + 1} argument but got `{list(arg_annotations.keys())[required_arg_index]}`"
16991695
)
17001696
raise ValueError(msg)
17011697

17021698
if not issubclass(arg_annotations[required_arg], Exception):
17031699
msg = (
1704-
f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong type for {required_arg} argument."
1700+
f"Provided custom {handler_domain} exception handler `{fn_name_}` has the wrong type for {required_arg} argument."
17051701
f"Expected to be `Exception` but got `{arg_annotations[required_arg]}`"
17061702
)
17071703
raise ValueError(msg)
@@ -1725,7 +1721,7 @@ def _validate_exception_handlers(self):
17251721

17261722
if not valid:
17271723
msg = (
1728-
f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong return type."
1724+
f"Provided custom {handler_domain} exception handler `{fn_name_}` has the wrong return type."
17291725
f"Expected `EventSpec | list[EventSpec] | None` but got `{return_type}`"
17301726
)
17311727
raise ValueError(msg)
@@ -1754,15 +1750,13 @@ async def process(
17541750
try:
17551751
# Add request data to the state.
17561752
router_data = event.router_data
1757-
router_data.update(
1758-
{
1759-
constants.RouteVar.QUERY: format.format_query_params(event.router_data),
1760-
constants.RouteVar.CLIENT_TOKEN: event.token,
1761-
constants.RouteVar.SESSION_ID: sid,
1762-
constants.RouteVar.HEADERS: headers,
1763-
constants.RouteVar.CLIENT_IP: client_ip,
1764-
}
1765-
)
1753+
router_data.update({
1754+
constants.RouteVar.QUERY: format.format_query_params(event.router_data),
1755+
constants.RouteVar.CLIENT_TOKEN: event.token,
1756+
constants.RouteVar.SESSION_ID: sid,
1757+
constants.RouteVar.HEADERS: headers,
1758+
constants.RouteVar.CLIENT_IP: client_ip,
1759+
})
17661760
# Get the state for the session exclusively.
17671761
async with app.state_manager.modify_state(event.substate_token) as state:
17681762
# When this is a brand new instance of the state, signal the
@@ -1820,7 +1814,7 @@ async def process(
18201814
raise
18211815

18221816

1823-
async def ping(_request: Request) -> Response:
1817+
def ping(_request: Request) -> Response:
18241818
"""Test API endpoint.
18251819
18261820
Args:
@@ -1852,7 +1846,7 @@ async def health(_request: Request) -> JSONResponse:
18521846
if prerequisites.check_db_used():
18531847
from reflex.model import get_db_status
18541848

1855-
tasks.append(get_db_status())
1849+
tasks.append(run_in_thread(get_db_status))
18561850
if prerequisites.check_redis_used():
18571851
tasks.append(prerequisites.get_redis_status())
18581852

reflex/app_mixins/lifespan.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ async def _run_lifespan_tasks(self, app: Starlette):
4141
signature = inspect.signature(task)
4242
if "app" in signature.parameters:
4343
task = functools.partial(task, app=app)
44-
_t = task()
45-
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
46-
await stack.enter_async_context(_t)
44+
t_ = task()
45+
if isinstance(t_, contextlib._AsyncGeneratorContextManager):
46+
await stack.enter_async_context(t_)
4747
console.debug(run_msg.format(type="asynccontextmanager"))
48-
elif isinstance(_t, Coroutine):
48+
elif isinstance(t_, Coroutine):
4949
task_ = asyncio.create_task(
50-
_t,
50+
t_,
5151
name=f"reflex_lifespan_task|{task_name}|{time.time()}",
5252
)
5353
task_.add_done_callback(lambda t: t.result())

reflex/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def json(self) -> str:
4848
self.dict(),
4949
default=serialize,
5050
)
51+
5152
else:
5253

5354
class PydanticNotFoundFallback:

reflex/compiler/compiler.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -758,12 +758,10 @@ def into_component(component: Component | ComponentCallable) -> Component:
758758
raise TypeError(
759759
"Cannot pass a Var to a built-in function. Consider using .length() for accessing the length of an iterable Var."
760760
).with_traceback(e.__traceback__) from None
761-
if message.endswith(
762-
(
763-
"indices must be integers or slices, not NumberCastedVar",
764-
"indices must be integers or slices, not BooleanCastedVar",
765-
)
766-
):
761+
if message.endswith((
762+
"indices must be integers or slices, not NumberCastedVar",
763+
"indices must be integers or slices, not BooleanCastedVar",
764+
)):
767765
raise TypeError(
768766
"Cannot index into a primitive sequence with a Var. Consider calling rx.Var.create() on the sequence."
769767
).with_traceback(e.__traceback__) from None

0 commit comments

Comments
 (0)