Merge remote-tracking branch 'origin/main' into lendemor/add_sticky_logo

This commit is contained in:
Masen Furer 2025-01-31 12:53:22 -08:00
commit aa5c9b7f4b
No known key found for this signature in database
GPG Key ID: 2AE2BD5531FF94F4
160 changed files with 1870 additions and 1124 deletions

34
.github/workflows/performance.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: performance-tests
on:
push:
branches:
- "main" # or "master"
paths-ignore:
- "**/*.md"
pull_request:
workflow_dispatch:
env:
TELEMETRY_ENABLED: false
NODE_OPTIONS: "--max_old_space_size=8192"
PR_TITLE: ${{ github.event.pull_request.title }}
APP_HARNESS_HEADLESS: 1
PYTHONUNBUFFERED: 1
jobs:
benchmarks:
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: 3.12.8
run-poetry-install: true
create-venv-at-path: .venv
- name: Run benchmarks
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: poetry run pytest benchmarks/test_evaluate.py --codspeed

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ requirements.txt
.pyi_generator_last_run .pyi_generator_last_run
.pyi_generator_diff .pyi_generator_diff
reflex.db reflex.db
.codspeed

View File

@ -28,7 +28,7 @@ repos:
entry: python3 scripts/make_pyi.py entry: python3 scripts/make_pyi.py
- repo: https://github.com/RobertCraigie/pyright-python - repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.334 rev: v1.1.392
hooks: hooks:
- id: pyright - id: pyright
args: [reflex, tests] args: [reflex, tests]

View File

@ -34,13 +34,13 @@ def render_component(num: int):
rx.box( rx.box(
rx.accordion.root( rx.accordion.root(
rx.accordion.item( rx.accordion.item(
header="Full Ingredients", # type: ignore header="Full Ingredients",
content="Yes. It's built with accessibility in mind.", # type: ignore content="Yes. It's built with accessibility in mind.",
font_size="3em", font_size="3em",
), ),
rx.accordion.item( rx.accordion.item(
header="Applications", # type: ignore header="Applications",
content="Yes. It's unstyled by default, giving you freedom over the look and feel.", # type: ignore content="Yes. It's unstyled by default, giving you freedom over the look and feel.",
), ),
collapsible=True, collapsible=True,
variant="ghost", variant="ghost",
@ -166,9 +166,9 @@ def app_with_10_components(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithTenComponentsOnePage, AppWithTenComponentsOnePage,
render_component=render_component, # type: ignore render_component=render_component, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -189,9 +189,9 @@ def app_with_100_components(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithHundredComponentOnePage, AppWithHundredComponentOnePage,
render_component=render_component, # type: ignore render_component=render_component, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -212,9 +212,9 @@ def app_with_1000_components(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithThousandComponentsOnePage, AppWithThousandComponentsOnePage,
render_component=render_component, # type: ignore render_component=render_component, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON) @pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)

View File

@ -28,7 +28,7 @@ def render_multiple_pages(app, num: int):
""" """
from typing import Tuple from typing import Tuple
from rxconfig import config # type: ignore from rxconfig import config # pyright: ignore [reportMissingImports]
import reflex as rx import reflex as rx
@ -74,13 +74,13 @@ def render_multiple_pages(app, num: int):
rx.select( rx.select(
["C", "PF", "SF", "PG", "SG"], ["C", "PF", "SF", "PG", "SG"],
placeholder="Select a position. (All)", placeholder="Select a position. (All)",
on_change=State.set_position, # type: ignore on_change=State.set_position, # pyright: ignore [reportAttributeAccessIssue]
size="3", size="3",
), ),
rx.select( rx.select(
college, college,
placeholder="Select a college. (All)", placeholder="Select a college. (All)",
on_change=State.set_college, # type: ignore on_change=State.set_college, # pyright: ignore [reportAttributeAccessIssue]
size="3", size="3",
), ),
), ),
@ -95,7 +95,7 @@ def render_multiple_pages(app, num: int):
default_value=[18, 50], default_value=[18, 50],
min=18, min=18,
max=50, max=50,
on_value_commit=State.set_age, # type: ignore on_value_commit=State.set_age, # pyright: ignore [reportAttributeAccessIssue]
), ),
align_items="left", align_items="left",
width="100%", width="100%",
@ -110,7 +110,7 @@ def render_multiple_pages(app, num: int):
default_value=[0, 25000000], default_value=[0, 25000000],
min=0, min=0,
max=25000000, max=25000000,
on_value_commit=State.set_salary, # type: ignore on_value_commit=State.set_salary, # pyright: ignore [reportAttributeAccessIssue]
), ),
align_items="left", align_items="left",
width="100%", width="100%",
@ -130,7 +130,7 @@ def render_multiple_pages(app, num: int):
def AppWithOnePage(): def AppWithOnePage():
"""A reflex app with one page.""" """A reflex app with one page."""
from rxconfig import config # type: ignore from rxconfig import config # pyright: ignore [reportMissingImports]
import reflex as rx import reflex as rx
@ -232,7 +232,7 @@ def app_with_ten_pages(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithTenPages, AppWithTenPages,
render_comp=render_multiple_pages, # type: ignore render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
), ),
) )
@ -255,9 +255,9 @@ def app_with_hundred_pages(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithHundredPages, AppWithHundredPages,
render_comp=render_multiple_pages, # type: ignore render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -278,9 +278,9 @@ def app_with_thousand_pages(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithThousandPages, AppWithThousandPages,
render_comp=render_multiple_pages, # type: ignore render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -301,9 +301,9 @@ def app_with_ten_thousand_pages(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
AppWithTenThousandPages, AppWithTenThousandPages,
render_comp=render_multiple_pages, # type: ignore render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
), ),
) # type: ignore )
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON) @pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)

231
benchmarks/test_evaluate.py Normal file
View File

@ -0,0 +1,231 @@
from dataclasses import dataclass
from typing import cast
import pytest
import reflex as rx
class SideBarState(rx.State):
"""State for the side bar."""
current_page: rx.Field[str] = rx.field("/")
@dataclass(frozen=True)
class SideBarPage:
"""A page in the side bar."""
title: str
href: str
@dataclass(frozen=True)
class SideBarSection:
"""A section in the side bar."""
name: str
icon: str
pages: tuple[SideBarPage, ...]
@dataclass(frozen=True)
class Category:
"""A category in the side bar."""
name: str
href: str
sections: tuple[SideBarSection, ...]
SIDE_BAR = (
Category(
name="General",
href="/",
sections=(
SideBarSection(
name="Home",
icon="home",
pages=(
SideBarPage(title="Home", href="/"),
SideBarPage(title="Contact", href="/contact"),
),
),
SideBarSection(
name="About",
icon="info",
pages=(
SideBarPage(title="About", href="/about"),
SideBarPage(title="FAQ", href="/faq"),
),
),
),
),
Category(
name="Projects",
href="/projects",
sections=(
SideBarSection(
name="Python",
icon="worm",
pages=(
SideBarPage(title="Python", href="/projects/python"),
SideBarPage(title="Django", href="/projects/django"),
SideBarPage(title="Flask", href="/projects/flask"),
SideBarPage(title="FastAPI", href="/projects/fastapi"),
SideBarPage(title="Pyramid", href="/projects/pyramid"),
SideBarPage(title="Tornado", href="/projects/tornado"),
SideBarPage(title="TurboGears", href="/projects/turbogears"),
SideBarPage(title="Web2py", href="/projects/web2py"),
SideBarPage(title="Zope", href="/projects/zope"),
SideBarPage(title="Plone", href="/projects/plone"),
SideBarPage(title="Quixote", href="/projects/quixote"),
SideBarPage(title="Bottle", href="/projects/bottle"),
SideBarPage(title="CherryPy", href="/projects/cherrypy"),
SideBarPage(title="Falcon", href="/projects/falcon"),
SideBarPage(title="Sanic", href="/projects/sanic"),
SideBarPage(title="Starlette", href="/projects/starlette"),
),
),
SideBarSection(
name="JavaScript",
icon="banana",
pages=(
SideBarPage(title="JavaScript", href="/projects/javascript"),
SideBarPage(title="Angular", href="/projects/angular"),
SideBarPage(title="React", href="/projects/react"),
SideBarPage(title="Vue", href="/projects/vue"),
SideBarPage(title="Ember", href="/projects/ember"),
SideBarPage(title="Backbone", href="/projects/backbone"),
SideBarPage(title="Meteor", href="/projects/meteor"),
SideBarPage(title="Svelte", href="/projects/svelte"),
SideBarPage(title="Preact", href="/projects/preact"),
SideBarPage(title="Mithril", href="/projects/mithril"),
SideBarPage(title="Aurelia", href="/projects/aurelia"),
SideBarPage(title="Polymer", href="/projects/polymer"),
SideBarPage(title="Knockout", href="/projects/knockout"),
SideBarPage(title="Dojo", href="/projects/dojo"),
SideBarPage(title="Riot", href="/projects/riot"),
SideBarPage(title="Alpine", href="/projects/alpine"),
SideBarPage(title="Stimulus", href="/projects/stimulus"),
SideBarPage(title="Marko", href="/projects/marko"),
SideBarPage(title="Sapper", href="/projects/sapper"),
SideBarPage(title="Nuxt", href="/projects/nuxt"),
SideBarPage(title="Next", href="/projects/next"),
SideBarPage(title="Gatsby", href="/projects/gatsby"),
SideBarPage(title="Gridsome", href="/projects/gridsome"),
SideBarPage(title="Nest", href="/projects/nest"),
SideBarPage(title="Express", href="/projects/express"),
SideBarPage(title="Koa", href="/projects/koa"),
SideBarPage(title="Hapi", href="/projects/hapi"),
SideBarPage(title="LoopBack", href="/projects/loopback"),
SideBarPage(title="Feathers", href="/projects/feathers"),
SideBarPage(title="Sails", href="/projects/sails"),
SideBarPage(title="Adonis", href="/projects/adonis"),
SideBarPage(title="Meteor", href="/projects/meteor"),
SideBarPage(title="Derby", href="/projects/derby"),
SideBarPage(title="Socket.IO", href="/projects/socketio"),
),
),
),
),
)
def side_bar_page(page: SideBarPage):
return rx.box(
rx.link(
page.title,
href=page.href,
)
)
def side_bar_section(section: SideBarSection):
return rx.accordion.item(
rx.accordion.header(
rx.accordion.trigger(
rx.hstack(
rx.hstack(
rx.icon(section.icon),
section.name,
align="center",
),
rx.accordion.icon(),
width="100%",
justify="between",
)
)
),
rx.accordion.content(
rx.vstack(
*map(side_bar_page, section.pages),
),
border_inline_start="1px solid",
padding_inline_start="1em",
margin_inline_start="1.5em",
),
value=section.name,
width="100%",
variant="ghost",
)
def side_bar_category(category: Category):
selected_section = cast(
rx.Var,
rx.match(
SideBarState.current_page,
*[
(
section.name,
section.name,
)
for section in category.sections
],
None,
),
)
return rx.vstack(
rx.heading(
rx.link(
category.name,
href=category.href,
),
size="5",
),
rx.accordion.root(
*map(side_bar_section, category.sections),
default_value=selected_section.to(str),
variant="ghost",
width="100%",
collapsible=True,
type="multiple",
),
width="100%",
)
def side_bar():
return rx.vstack(
*map(side_bar_category, SIDE_BAR),
width="fit-content",
)
LOREM_IPSUM = "Lorem ipsum dolor sit amet, dolor ut dolore pariatur aliqua enim tempor sed. Labore excepteur sed exercitation. Ullamco aliquip lorem sunt enim in incididunt. Magna anim officia sint cillum labore. Ut eu non dolore minim nostrud magna eu, aute ex in incididunt irure eu. Fugiat et magna magna est excepteur eiusmod minim. Quis eiusmod et non pariatur dolor veniam incididunt, eiusmod irure enim sed dolor lorem pariatur do. Occaecat duis irure excepteur dolore. Proident ut laborum pariatur sit sit, nisi nostrud voluptate magna commodo laborum esse velit. Voluptate non minim deserunt adipiscing irure deserunt cupidatat. Laboris veniam commodo incididunt veniam lorem occaecat, fugiat ipsum dolor cupidatat. Ea officia sed eu excepteur culpa adipiscing, tempor consectetur ullamco eu. Anim ex proident nulla sunt culpa, voluptate veniam proident est adipiscing sint elit velit. Laboris adipiscing est culpa cillum magna. Sit veniam nulla nulla, aliqua eiusmod commodo lorem cupidatat commodo occaecat. Fugiat cillum dolor incididunt mollit eiusmod sint. Non lorem dolore labore excepteur minim laborum sed. Irure nisi do lorem nulla sunt commodo, deserunt quis mollit consectetur minim et esse est, proident nostrud officia enim sed reprehenderit. Magna cillum consequat aute reprehenderit duis sunt ullamco. Labore qui mollit voluptate. Duis dolor sint aute amet aliquip officia, est non mollit tempor enim quis fugiat, eu do culpa consectetur magna. Do ullamco aliqua voluptate culpa excepteur reprehenderit reprehenderit. Occaecat nulla sit est magna. Deserunt ea voluptate veniam cillum. Amet cupidatat duis est tempor fugiat ex eu, officia est sunt consectetur labore esse exercitation. Nisi cupidatat irure est nisi. Officia amet eu veniam reprehenderit. In amet incididunt tempor commodo ea labore. Mollit dolor aliquip excepteur, voluptate aute occaecat id officia proident. Ullamco est amet tempor. Proident aliquip proident mollit do aliquip ipsum, culpa quis aute id irure. Velit excepteur cillum cillum ut cupidatat. Occaecat qui elit esse nulla minim. Consequat velit id ad pariatur tempor. Eiusmod deserunt aliqua ex sed quis non. Dolor sint commodo ex in deserunt nostrud excepteur, pariatur ex aliqua anim adipiscing amet proident. Laboris eu laborum magna lorem ipsum fugiat velit."
def complicated_page():
return rx.hstack(
side_bar(),
rx.box(
rx.heading("Complicated Page", size="1"),
rx.text(LOREM_IPSUM),
),
)
@pytest.mark.benchmark
def test_component_init():
complicated_page()

465
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ keywords = ["web", "framework"]
classifiers = ["Development Status :: 4 - Beta"] classifiers = ["Development Status :: 4 - Beta"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = ">=3.10, <4.0"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1" fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
gunicorn = ">=20.1.0,<24.0" gunicorn = ">=20.1.0,<24.0"
jinja2 = ">=3.1.2,<4.0" jinja2 = ">=3.1.2,<4.0"
@ -55,7 +55,7 @@ typing_extensions = ">=4.6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = ">=7.1.2,<9.0" pytest = ">=7.1.2,<9.0"
pytest-mock = ">=3.10.0,<4.0" pytest-mock = ">=3.10.0,<4.0"
pyright = ">=1.1.229,<1.1.335" pyright = ">=1.1.392, <1.2"
darglint = ">=1.8.1,<2.0" darglint = ">=1.8.1,<2.0"
dill = ">=0.3.8" dill = ">=0.3.8"
toml = ">=0.10.2,<1.0" toml = ">=0.10.2,<1.0"
@ -71,6 +71,7 @@ selenium = ">=4.11.0,<5.0"
pytest-benchmark = ">=4.0.0,<6.0" pytest-benchmark = ">=4.0.0,<6.0"
playwright = ">=1.46.0" playwright = ">=1.46.0"
pytest-playwright = ">=0.5.1" pytest-playwright = ">=0.5.1"
pytest-codspeed = "^3.1.2"
[tool.poetry.scripts] [tool.poetry.scripts]
reflex = "reflex.reflex:cli" reflex = "reflex.reflex:cli"
@ -80,21 +81,22 @@ requires = ["poetry-core>=1.5.1"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.pyright] [tool.pyright]
reportIncompatibleMethodOverride = false
[tool.ruff] [tool.ruff]
target-version = "py39" target-version = "py310"
output-format = "concise" output-format = "concise"
lint.isort.split-on-trailing-comma = false lint.isort.split-on-trailing-comma = false
lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PTH", "RUF", "SIM", "T", "TRY", "W"] lint.select = ["ANN001","B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PGH", "PTH", "RUF", "SIM", "T", "TRY", "W"]
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012", "TRY0"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012", "TRY0"]
lint.pydocstyle.convention = "google" lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"] "__init__.py" = ["F401"]
"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] "tests/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"benchmarks/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] "benchmarks/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"] "reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N"] "*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N", "PGH"]
"pyi_generator.py" = ["N802"] "pyi_generator.py" = ["N802"]
"reflex/constants/*.py" = ["N"] "reflex/constants/*.py" = ["N"]
"*/blank.py" = ["I001"] "*/blank.py" = ["I001"]

View File

@ -86,11 +86,11 @@
{% for condition in case[:-1] %} {% for condition in case[:-1] %}
case JSON.stringify({{ condition._js_expr }}): case JSON.stringify({{ condition._js_expr }}):
{% endfor %} {% endfor %}
return {{ case[-1] }}; return {{ render(case[-1]) }};
break; break;
{% endfor %} {% endfor %}
default: default:
return {{ component.default }}; return {{ render(component.default) }};
break; break;
} }
})() })()

View File

@ -84,6 +84,9 @@ In the example above, you will be able to do `rx.list`
from __future__ import annotations from __future__ import annotations
from types import ModuleType
from typing import Any
from reflex.utils import ( from reflex.utils import (
compat, # for side-effects compat, # for side-effects
lazy_loader, lazy_loader,
@ -365,5 +368,5 @@ getattr, __dir__, __all__ = lazy_loader.attach(
) )
def __getattr__(name): def __getattr__(name: ModuleType | Any):
return getattr(name) return getattr(name)

View File

@ -131,7 +131,7 @@ from .components.radix.themes.layout.container import container as container
from .components.radix.themes.layout.flex import flex as flex from .components.radix.themes.layout.flex import flex as flex
from .components.radix.themes.layout.grid import grid as grid from .components.radix.themes.layout.grid import grid as grid
from .components.radix.themes.layout.list import list_item as list_item from .components.radix.themes.layout.list import list_item as list_item
from .components.radix.themes.layout.list import list_ns as list # noqa from .components.radix.themes.layout.list import list_ns as list # noqa: F401
from .components.radix.themes.layout.list import ordered_list as ordered_list from .components.radix.themes.layout.list import ordered_list as ordered_list
from .components.radix.themes.layout.list import unordered_list as unordered_list from .components.radix.themes.layout.list import unordered_list as unordered_list
from .components.radix.themes.layout.section import section as section from .components.radix.themes.layout.section import section as section

View File

@ -27,6 +27,7 @@ from typing import (
Dict, Dict,
Generic, Generic,
List, List,
MutableMapping,
Optional, Optional,
Set, Set,
Type, Type,
@ -146,7 +147,7 @@ def default_backend_exception_handler(exception: Exception) -> EventSpec:
position="top-center", position="top-center",
id="backend_error", id="backend_error",
style={"width": "500px"}, style={"width": "500px"},
) # type: ignore ) # pyright: ignore [reportReturnType]
else: else:
error_message.insert(0, "An error occurred.") error_message.insert(0, "An error occurred.")
return window_alert("\n".join(error_message)) return window_alert("\n".join(error_message))
@ -408,23 +409,28 @@ class App(MiddlewareMixin, LifespanMixin):
if self.api: if self.api:
class HeaderMiddleware: class HeaderMiddleware:
def __init__(self, app): def __init__(self, app: ASGIApp):
self.app = app self.app = app
async def __call__(self, scope, receive, send): async def __call__(
self, scope: MutableMapping[str, Any], receive: Any, send: Callable
):
original_send = send original_send = send
async def modified_send(message): async def modified_send(message: dict):
headers = dict(scope["headers"]) if message["type"] == "websocket.accept":
protocol_key = b"sec-websocket-protocol" if scope.get("subprotocols"):
if ( # The following *does* say "subprotocol" instead of "subprotocols", intentionally.
message["type"] == "websocket.accept" message["subprotocol"] = scope["subprotocols"][0]
and protocol_key in headers
): headers = dict(message.get("headers", []))
message["headers"] = [ header_key = b"sec-websocket-protocol"
*message.get("headers", []), if subprotocol := headers.get(header_key):
(b"sec-websocket-protocol", headers[protocol_key]), message["headers"] = [
] *message.get("headers", []),
(header_key, subprotocol),
]
return await original_send(message) return await original_send(message)
return await self.app(scope, receive, modified_send) return await self.app(scope, receive, modified_send)
@ -673,7 +679,10 @@ class App(MiddlewareMixin, LifespanMixin):
for route in self._pages: for route in self._pages:
replaced_route = replace_brackets_with_keywords(route) replaced_route = replace_brackets_with_keywords(route)
for rw, r, nr in zip( for rw, r, nr in zip(
replaced_route.split("/"), route.split("/"), new_route.split("/") replaced_route.split("/"),
route.split("/"),
new_route.split("/"),
strict=False,
): ):
if rw in segments and r != nr: if rw in segments and r != nr:
# If the slugs in the segments of both routes are not the same, then the route is invalid # If the slugs in the segments of both routes are not the same, then the route is invalid
@ -704,8 +713,8 @@ class App(MiddlewareMixin, LifespanMixin):
Args: Args:
component: The component to display at the page. component: The component to display at the page.
title: The title of the page. title: The title of the page.
description: The description of the page.
image: The image to display on the page. image: The image to display on the page.
description: The description of the page.
on_load: The event handler(s) that will be called each time the page load. on_load: The event handler(s) that will be called each time the page load.
meta: The metadata of the page. meta: The metadata of the page.
""" """
@ -772,7 +781,7 @@ class App(MiddlewareMixin, LifespanMixin):
frontend_packages = get_config().frontend_packages frontend_packages = get_config().frontend_packages
_frontend_packages = [] _frontend_packages = []
for package in frontend_packages: for package in frontend_packages:
if package in (get_config().tailwind or {}).get("plugins", []): # type: ignore if package in (get_config().tailwind or {}).get("plugins", []):
console.warn( console.warn(
f"Tailwind packages are inferred from 'plugins', remove `{package}` from `frontend_packages`" f"Tailwind packages are inferred from 'plugins', remove `{package}` from `frontend_packages`"
) )
@ -1029,7 +1038,7 @@ class App(MiddlewareMixin, LifespanMixin):
compiler.compile_document_root( compiler.compile_document_root(
self.head_components, self.head_components,
html_lang=self.html_lang, html_lang=self.html_lang,
html_custom_attrs=self.html_custom_attrs, # type: ignore html_custom_attrs=self.html_custom_attrs, # pyright: ignore [reportArgumentType]
) )
) )
@ -1052,7 +1061,7 @@ class App(MiddlewareMixin, LifespanMixin):
max_workers=environment.REFLEX_COMPILE_THREADS.get() or None max_workers=environment.REFLEX_COMPILE_THREADS.get() or None
) )
for route, component in zip(self._pages, page_components): for route, component in zip(self._pages, page_components, strict=True):
ExecutorSafeFunctions.COMPONENTS[route] = component ExecutorSafeFunctions.COMPONENTS[route] = component
ExecutorSafeFunctions.STATE = self._state ExecutorSafeFunctions.STATE = self._state
@ -1060,7 +1069,7 @@ class App(MiddlewareMixin, LifespanMixin):
with executor: with executor:
result_futures = [] result_futures = []
def _submit_work(fn, *args, **kwargs): def _submit_work(fn: Callable, *args, **kwargs):
f = executor.submit(fn, *args, **kwargs) f = executor.submit(fn, *args, **kwargs)
result_futures.append(f) result_futures.append(f)
@ -1249,6 +1258,7 @@ class App(MiddlewareMixin, LifespanMixin):
frontend_arg_spec, frontend_arg_spec,
backend_arg_spec, backend_arg_spec,
], ],
strict=True,
): ):
if hasattr(handler_fn, "__name__"): if hasattr(handler_fn, "__name__"):
_fn_name = handler_fn.__name__ _fn_name = handler_fn.__name__
@ -1390,15 +1400,14 @@ async def process(
if app._process_background(state, event) is not None: if app._process_background(state, event) is not None:
# `final=True` allows the frontend send more events immediately. # `final=True` allows the frontend send more events immediately.
yield StateUpdate(final=True) yield StateUpdate(final=True)
return else:
# Process the event synchronously.
async for update in state._process(event):
# Postprocess the event.
update = await app._postprocess(state, event, update)
# Process the event synchronously. # Yield the update.
async for update in state._process(event): yield update
# Postprocess the event.
update = await app._postprocess(state, event, update)
# Yield the update.
yield update
except Exception as ex: except Exception as ex:
telemetry.send_error(ex, context="backend") telemetry.send_error(ex, context="backend")
@ -1593,20 +1602,20 @@ class EventNamespace(AsyncNamespace):
self.sid_to_token = {} self.sid_to_token = {}
self.app = app self.app = app
def on_connect(self, sid, environ): def on_connect(self, sid: str, environ: dict):
"""Event for when the websocket is connected. """Event for when the websocket is connected.
Args: Args:
sid: The Socket.IO session id. sid: The Socket.IO session id.
environ: The request information, including HTTP headers. environ: The request information, including HTTP headers.
""" """
subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL", None) subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL")
if subprotocol and subprotocol != constants.Reflex.VERSION: if subprotocol and subprotocol != constants.Reflex.VERSION:
console.warn( console.warn(
f"Frontend version {subprotocol} for session {sid} does not match the backend version {constants.Reflex.VERSION}." f"Frontend version {subprotocol} for session {sid} does not match the backend version {constants.Reflex.VERSION}."
) )
def on_disconnect(self, sid): def on_disconnect(self, sid: str):
"""Event for when the websocket disconnects. """Event for when the websocket disconnects.
Args: Args:
@ -1628,7 +1637,7 @@ class EventNamespace(AsyncNamespace):
self.emit(str(constants.SocketEvent.EVENT), update, to=sid) self.emit(str(constants.SocketEvent.EVENT), update, to=sid)
) )
async def on_event(self, sid, data): async def on_event(self, sid: str, data: Any):
"""Event for receiving front-end websocket events. """Event for receiving front-end websocket events.
Raises: Raises:
@ -1695,7 +1704,7 @@ class EventNamespace(AsyncNamespace):
# Emit the update from processing the event. # Emit the update from processing the event.
await self.emit_update(update=update, sid=sid) await self.emit_update(update=update, sid=sid)
async def on_ping(self, sid): async def on_ping(self, sid: str):
"""Event for testing the API endpoint. """Event for testing the API endpoint.
Args: Args:

View File

@ -32,7 +32,7 @@ class LifespanMixin(AppMixin):
try: try:
async with contextlib.AsyncExitStack() as stack: async with contextlib.AsyncExitStack() as stack:
for task in self.lifespan_tasks: for task in self.lifespan_tasks:
run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # pyright: ignore [reportAttributeAccessIssue]
if isinstance(task, asyncio.Task): if isinstance(task, asyncio.Task):
running_tasks.append(task) running_tasks.append(task)
else: else:
@ -61,7 +61,7 @@ class LifespanMixin(AppMixin):
Args: Args:
task: The task to register. task: The task to register.
task_kwargs: The kwargs of the task. **task_kwargs: The kwargs of the task.
Raises: Raises:
InvalidLifespanTaskTypeError: If the task is a generator function. InvalidLifespanTaskTypeError: If the task is a generator function.
@ -73,7 +73,7 @@ class LifespanMixin(AppMixin):
if task_kwargs: if task_kwargs:
original_task = task original_task = task
task = functools.partial(task, **task_kwargs) # type: ignore task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
functools.update_wrapper(task, original_task) # type: ignore functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
self.lifespan_tasks.add(task) # type: ignore self.lifespan_tasks.add(task)
console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore console.debug(f"Registered lifespan task: {task.__name__}") # pyright: ignore [reportAttributeAccessIssue]

View File

@ -53,11 +53,11 @@ class MiddlewareMixin(AppMixin):
""" """
for middleware in self.middleware: for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.preprocess): if asyncio.iscoroutinefunction(middleware.preprocess):
out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore out = await middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
else: else:
out = middleware.preprocess(app=self, state=state, event=event) # type: ignore out = middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
if out is not None: if out is not None:
return out # type: ignore return out # pyright: ignore [reportReturnType]
async def _postprocess( async def _postprocess(
self, state: BaseState, event: Event, update: StateUpdate self, state: BaseState, event: Event, update: StateUpdate
@ -78,18 +78,18 @@ class MiddlewareMixin(AppMixin):
for middleware in self.middleware: for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.postprocess): if asyncio.iscoroutinefunction(middleware.postprocess):
out = await middleware.postprocess( out = await middleware.postprocess(
app=self, # type: ignore app=self, # pyright: ignore [reportArgumentType]
state=state, state=state,
event=event, event=event,
update=update, update=update,
) )
else: else:
out = middleware.postprocess( out = middleware.postprocess(
app=self, # type: ignore app=self, # pyright: ignore [reportArgumentType]
state=state, state=state,
event=event, event=event,
update=update, update=update,
) )
if out is not None: if out is not None:
return out # type: ignore return out # pyright: ignore [reportReturnType]
return update return update

View File

@ -13,7 +13,7 @@ except ModuleNotFoundError:
if not TYPE_CHECKING: if not TYPE_CHECKING:
import pydantic.main as pydantic_main import pydantic.main as pydantic_main
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.fields import ModelField # type: ignore from pydantic.fields import ModelField
def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None: def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
@ -44,13 +44,13 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
# monkeypatch pydantic validate_field_name method to skip validating # monkeypatch pydantic validate_field_name method to skip validating
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True) # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
pydantic_main.validate_field_name = validate_field_name # type: ignore pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
if TYPE_CHECKING: if TYPE_CHECKING:
from reflex.vars import Var from reflex.vars import Var
class Base(BaseModel): # pyright: ignore [reportUnboundVariable] class Base(BaseModel): # pyright: ignore [reportPossiblyUnboundVariable]
"""The base class subclassed by all Reflex classes. """The base class subclassed by all Reflex classes.
This class wraps Pydantic and provides common methods such as This class wraps Pydantic and provides common methods such as
@ -75,12 +75,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
""" """
from reflex.utils.serializers import serialize from reflex.utils.serializers import serialize
return self.__config__.json_dumps( # type: ignore return self.__config__.json_dumps(
self.dict(), self.dict(),
default=serialize, default=serialize,
) )
def set(self, **kwargs): def set(self, **kwargs: Any):
"""Set multiple fields and return the object. """Set multiple fields and return the object.
Args: Args:
@ -113,12 +113,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
default_value: The default value of the field default_value: The default value of the field
""" """
var_name = var._var_field_name var_name = var._var_field_name
new_field = ModelField.infer( new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
name=var_name, name=var_name,
value=default_value, value=default_value,
annotation=var._var_type, annotation=var._var_type,
class_validators=None, class_validators=None,
config=cls.__config__, # type: ignore config=cls.__config__,
) )
cls.__fields__.update({var_name: new_field}) cls.__fields__.update({var_name: new_field})

View File

@ -2,6 +2,8 @@
from __future__ import annotations from __future__ import annotations
import traceback
from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, Optional, Type, Union from typing import Any, Callable, Dict, Optional, Type, Union
from urllib.parse import urlparse from urllib.parse import urlparse
@ -12,7 +14,9 @@ from reflex.vars.base import Var
try: try:
from pydantic.v1.fields import ModelField from pydantic.v1.fields import ModelField
except ModuleNotFoundError: except ModuleNotFoundError:
from pydantic.fields import ModelField # type: ignore from pydantic.fields import (
ModelField, # pyright: ignore [reportAttributeAccessIssue]
)
from reflex import constants from reflex import constants
from reflex.components.base import ( from reflex.components.base import (
@ -115,7 +119,7 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
default, rest = compile_import_statement(fields) default, rest = compile_import_statement(fields)
# prevent lib from being rendered on the page if all imports are non rendered kind # prevent lib from being rendered on the page if all imports are non rendered kind
if not any(f.render for f in fields): # type: ignore if not any(f.render for f in fields):
continue continue
if not lib: if not lib:
@ -163,8 +167,12 @@ def compile_state(state: Type[BaseState]) -> dict:
try: try:
initial_state = state(_reflex_internal_init=True).dict(initial=True) initial_state = state(_reflex_internal_init=True).dict(initial=True)
except Exception as e: except Exception as e:
timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
log_path = constants.Reflex.LOGS_DIR / f"state_compile_error_{timestamp}.log"
traceback.TracebackException.from_exception(e).print(file=log_path.open("w+"))
console.warn( console.warn(
f"Failed to compile initial state with computed vars, excluding them: {e}" f"Failed to compile initial state with computed vars. Error log saved to {log_path}"
) )
initial_state = state(_reflex_internal_init=True).dict( initial_state = state(_reflex_internal_init=True).dict(
initial=True, include_computed=False initial=True, include_computed=False
@ -494,7 +502,7 @@ def empty_dir(path: str | Path, keep_files: list[str] | None = None):
path_ops.rm(element) path_ops.rm(element)
def is_valid_url(url) -> bool: def is_valid_url(url: str) -> bool:
"""Check if a url is valid. """Check if a url is valid.
Args: Args:

View File

@ -31,7 +31,7 @@ class Bare(Component):
return cls(contents=contents) return cls(contents=contents)
else: else:
contents = str(contents) if contents is not None else "" contents = str(contents) if contents is not None else ""
return cls(contents=contents) # type: ignore return cls(contents=contents)
def _get_all_hooks_internal(self) -> dict[str, VarData | None]: def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
"""Include the hooks for the component. """Include the hooks for the component.

View File

@ -53,11 +53,11 @@ class Description(Meta):
"""A component that displays the title of the current page.""" """A component that displays the title of the current page."""
# The type of the description. # The type of the description.
name: str = "description" name: str | None = "description"
class Image(Meta): class Image(Meta):
"""A component that displays the title of the current page.""" """A component that displays the title of the current page."""
# The type of the image. # The type of the image.
property: str = "og:image" property: str | None = "og:image"

View File

@ -150,7 +150,7 @@ class BaseComponent(Base, ABC):
class ComponentNamespace(SimpleNamespace): class ComponentNamespace(SimpleNamespace):
"""A namespace to manage components with subcomponents.""" """A namespace to manage components with subcomponents."""
def __hash__(self) -> int: def __hash__(self) -> int: # pyright: ignore [reportIncompatibleVariableOverride]
"""Get the hash of the namespace. """Get the hash of the namespace.
Returns: Returns:
@ -426,7 +426,7 @@ class Component(BaseComponent, ABC):
else: else:
continue continue
def determine_key(value): def determine_key(value: Any):
# Try to create a var from the value # Try to create a var from the value
key = value if isinstance(value, Var) else LiteralVar.create(value) key = value if isinstance(value, Var) else LiteralVar.create(value)
@ -462,9 +462,7 @@ class Component(BaseComponent, ABC):
if types.is_union(passed_type): if types.is_union(passed_type):
# We need to check all possible types in the union. # We need to check all possible types in the union.
passed_types = ( passed_types = (
arg arg for arg in passed_type.__args__ if arg is not type(None)
for arg in passed_type.__args__ # type: ignore
if arg is not type(None)
) )
if ( if (
# If the passed var is a union, check if all possible types are valid. # If the passed var is a union, check if all possible types are valid.
@ -491,7 +489,7 @@ class Component(BaseComponent, ABC):
# Check if the key is an event trigger. # Check if the key is an event trigger.
if key in component_specific_triggers: if key in component_specific_triggers:
kwargs["event_triggers"][key] = EventChain.create( kwargs["event_triggers"][key] = EventChain.create(
value=value, # type: ignore value=value,
args_spec=component_specific_triggers[key], args_spec=component_specific_triggers[key],
key=key, key=key,
) )
@ -578,7 +576,7 @@ class Component(BaseComponent, ABC):
annotation = field.annotation annotation = field.annotation
if (metadata := getattr(annotation, "__metadata__", None)) is not None: if (metadata := getattr(annotation, "__metadata__", None)) is not None:
args_spec = metadata[0] args_spec = metadata[0]
default_triggers[field.name] = args_spec or (no_args_event_spec) # type: ignore default_triggers[field.name] = args_spec or (no_args_event_spec)
return default_triggers return default_triggers
def __repr__(self) -> str: def __repr__(self) -> str:
@ -709,7 +707,7 @@ class Component(BaseComponent, ABC):
# Filter out None props # Filter out None props
props = {key: value for key, value in props.items() if value is not None} props = {key: value for key, value in props.items() if value is not None}
def validate_children(children): def validate_children(children: tuple | list):
for child in children: for child in children:
if isinstance(child, (tuple, list)): if isinstance(child, (tuple, list)):
validate_children(child) validate_children(child)
@ -761,7 +759,7 @@ class Component(BaseComponent, ABC):
# Walk the MRO to call all `add_style` methods. # Walk the MRO to call all `add_style` methods.
for base in self._iter_parent_classes_with_method("add_style"): for base in self._iter_parent_classes_with_method("add_style"):
s = base.add_style(self) # type: ignore s = base.add_style(self)
if s is not None: if s is not None:
styles.append(s) styles.append(s)
@ -853,7 +851,7 @@ class Component(BaseComponent, ABC):
else {} else {}
) )
def render(self) -> Dict: def render(self) -> dict:
"""Render the component. """Render the component.
Returns: Returns:
@ -871,7 +869,7 @@ class Component(BaseComponent, ABC):
self._replace_prop_names(rendered_dict) self._replace_prop_names(rendered_dict)
return rendered_dict return rendered_dict
def _replace_prop_names(self, rendered_dict) -> None: def _replace_prop_names(self, rendered_dict: dict) -> None:
"""Replace the prop names in the render dictionary. """Replace the prop names in the render dictionary.
Args: Args:
@ -911,7 +909,7 @@ class Component(BaseComponent, ABC):
comp.__name__ for comp in (Fragment, Foreach, Cond, Match) comp.__name__ for comp in (Fragment, Foreach, Cond, Match)
] ]
def validate_child(child): def validate_child(child: Any):
child_name = type(child).__name__ child_name = type(child).__name__
# Iterate through the immediate children of fragment # Iterate through the immediate children of fragment
@ -1674,7 +1672,7 @@ class CustomComponent(Component):
if base_value is not None and isinstance(value, Component): if base_value is not None and isinstance(value, Component):
self.component_props[key] = value self.component_props[key] = value
value = base_value._replace( value = base_value._replace(
merge_var_data=VarData( # type: ignore merge_var_data=VarData(
imports=value._get_all_imports(), imports=value._get_all_imports(),
hooks=value._get_all_hooks(), hooks=value._get_all_hooks(),
) )
@ -1707,7 +1705,7 @@ class CustomComponent(Component):
return hash(self.tag) return hash(self.tag)
@classmethod @classmethod
def get_props(cls) -> Set[str]: def get_props(cls) -> Set[str]: # pyright: ignore [reportIncompatibleVariableOverride]
"""Get the props for the component. """Get the props for the component.
Returns: Returns:
@ -1802,7 +1800,7 @@ class CustomComponent(Component):
include_children=include_children, ignore_ids=ignore_ids include_children=include_children, ignore_ids=ignore_ids
) )
@lru_cache(maxsize=None) # noqa @lru_cache(maxsize=None) # noqa: B019
def get_component(self) -> Component: def get_component(self) -> Component:
"""Render the component. """Render the component.
@ -1946,7 +1944,7 @@ class StatefulComponent(BaseComponent):
if not should_memoize: if not should_memoize:
# Determine if any Vars have associated data. # Determine if any Vars have associated data.
for prop_var in component._get_vars(): for prop_var in component._get_vars(include_children=True):
if prop_var._get_all_var_data(): if prop_var._get_all_var_data():
should_memoize = True should_memoize = True
break break
@ -2329,8 +2327,8 @@ class MemoizationLeaf(Component):
""" """
comp = super().create(*children, **props) comp = super().create(*children, **props)
if comp._get_all_hooks(): if comp._get_all_hooks():
comp._memoization_mode = cls._memoization_mode.copy( comp._memoization_mode = dataclasses.replace(
update={"disposition": MemoizationDisposition.ALWAYS} comp._memoization_mode, disposition=MemoizationDisposition.ALWAYS
) )
return comp return comp
@ -2391,7 +2389,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
if tag["name"] == "match": if tag["name"] == "match":
element = tag["cond"] element = tag["cond"]
conditionals = tag["default"] conditionals = render_dict_to_var(tag["default"], imported_names)
for case in tag["match_cases"][::-1]: for case in tag["match_cases"][::-1]:
condition = case[0].to_string() == element.to_string() condition = case[0].to_string() == element.to_string()
@ -2400,7 +2398,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
conditionals = ternary_operation( conditionals = ternary_operation(
condition, condition,
case[-1], render_dict_to_var(case[-1], imported_names),
conditionals, conditionals,
) )

View File

@ -25,7 +25,7 @@ from reflex.vars.function import FunctionStringVar
from reflex.vars.number import BooleanVar from reflex.vars.number import BooleanVar
from reflex.vars.sequence import LiteralArrayVar from reflex.vars.sequence import LiteralArrayVar
connect_error_var_data: VarData = VarData( # type: ignore connect_error_var_data: VarData = VarData(
imports=Imports.EVENTS, imports=Imports.EVENTS,
hooks={Hooks.EVENTS: None}, hooks={Hooks.EVENTS: None},
) )
@ -99,14 +99,14 @@ class ConnectionToaster(Toaster):
""" """
toast_id = "websocket-error" toast_id = "websocket-error"
target_url = WebsocketTargetURL.create() target_url = WebsocketTargetURL.create()
props = ToastProps( # type: ignore props = ToastProps(
description=LiteralVar.create( description=LiteralVar.create(
f"Check if server is reachable at {target_url}", f"Check if server is reachable at {target_url}",
), ),
close_button=True, close_button=True,
duration=120000, duration=120000,
id=toast_id, id=toast_id,
) ) # pyright: ignore [reportCallIssue]
individual_hooks = [ individual_hooks = [
f"const toast_props = {LiteralVar.create(props)!s};", f"const toast_props = {LiteralVar.create(props)!s};",
@ -116,7 +116,7 @@ class ConnectionToaster(Toaster):
_var_data=VarData( _var_data=VarData(
imports={ imports={
"react": ["useEffect", "useState"], "react": ["useEffect", "useState"],
**dict(target_url._get_all_var_data().imports), # type: ignore **dict(target_url._get_all_var_data().imports), # pyright: ignore [reportArgumentType, reportOptionalMemberAccess]
} }
), ),
).call( ).call(

View File

@ -82,7 +82,9 @@ class Breakpoints(Dict[K, V]):
return Breakpoints( return Breakpoints(
{ {
k: v k: v
for k, v in zip(["initial", *breakpoint_names], thresholds) for k, v in zip(
["initial", *breakpoint_names], thresholds, strict=True
)
if v is not None if v is not None
} }
) )

View File

@ -41,7 +41,7 @@ class ClientSideRouting(Component):
return "" return ""
def wait_for_client_redirect(component) -> Component: def wait_for_client_redirect(component: Component) -> Component:
"""Wait for a redirect to occur before rendering a component. """Wait for a redirect to occur before rendering a component.
This prevents the 404 page from flashing while the redirect is happening. This prevents the 404 page from flashing while the redirect is happening.

View File

@ -60,7 +60,7 @@ class ClientSideRouting(Component):
""" """
... ...
def wait_for_client_redirect(component) -> Component: ... def wait_for_client_redirect(component: Component) -> Component: ...
class Default404Page(Component): class Default404Page(Component):
@overload @overload

View File

@ -26,10 +26,9 @@ class Cond(MemoizationLeaf):
cond: Var[Any] cond: Var[Any]
# The component to render if the cond is true. # The component to render if the cond is true.
comp1: BaseComponent = None # type: ignore comp1: BaseComponent | None = None
# The component to render if the cond is false. # The component to render if the cond is false.
comp2: BaseComponent = None # type: ignore comp2: BaseComponent | None = None
@classmethod @classmethod
def create( def create(
@ -73,8 +72,8 @@ class Cond(MemoizationLeaf):
def _render(self) -> Tag: def _render(self) -> Tag:
return CondTag( return CondTag(
cond=self.cond, cond=self.cond,
true_value=self.comp1.render(), true_value=self.comp1.render(), # pyright: ignore [reportOptionalMemberAccess]
false_value=self.comp2.render(), false_value=self.comp2.render(), # pyright: ignore [reportOptionalMemberAccess]
) )
def render(self) -> Dict: def render(self) -> Dict:
@ -111,7 +110,7 @@ class Cond(MemoizationLeaf):
@overload @overload
def cond(condition: Any, c1: Component, c2: Any) -> Component: ... def cond(condition: Any, c1: Component, c2: Any) -> Component: ... # pyright: ignore [reportOverlappingOverload]
@overload @overload
@ -154,7 +153,7 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
if c2 is None: if c2 is None:
raise ValueError("For conditional vars, the second argument must be set.") raise ValueError("For conditional vars, the second argument must be set.")
def create_var(cond_part): def create_var(cond_part: Any) -> Var[Any]:
return LiteralVar.create(cond_part) return LiteralVar.create(cond_part)
# convert the truth and false cond parts into vars so the _var_data can be obtained. # convert the truth and false cond parts into vars so the _var_data can be obtained.
@ -163,16 +162,16 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
# Create the conditional var. # Create the conditional var.
return ternary_operation( return ternary_operation(
cond_var.bool()._replace( # type: ignore cond_var.bool()._replace(
merge_var_data=VarData(imports=_IS_TRUE_IMPORT), merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
), # type: ignore ),
c1, c1,
c2, c2,
) )
@overload @overload
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # type: ignore def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # pyright: ignore [reportOverlappingOverload]
@overload @overload

View File

@ -28,7 +28,7 @@ class DebounceInput(Component):
min_length: Var[int] min_length: Var[int]
# Time to wait between end of input and triggering on_change # Time to wait between end of input and triggering on_change
debounce_timeout: Var[int] = DEFAULT_DEBOUNCE_TIMEOUT # type: ignore debounce_timeout: Var[int] = Var.create(DEFAULT_DEBOUNCE_TIMEOUT)
# If true, notify when Enter key is pressed # If true, notify when Enter key is pressed
force_notify_by_enter: Var[bool] force_notify_by_enter: Var[bool]

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import functools
import inspect import inspect
from typing import Any, Callable, Iterable from typing import Any, Callable, Iterable
@ -97,9 +98,20 @@ class Foreach(Component):
# Determine the index var name based on the params accepted by render_fn. # Determine the index var name based on the params accepted by render_fn.
props["index_var_name"] = params[1].name props["index_var_name"] = params[1].name
else: else:
render_fn = self.render_fn
# Otherwise, use a deterministic index, based on the render function bytecode. # Otherwise, use a deterministic index, based on the render function bytecode.
code_hash = ( code_hash = (
hash(self.render_fn.__code__) hash(
getattr(
render_fn,
"__code__",
(
repr(self.render_fn)
if not isinstance(render_fn, functools.partial)
else render_fn.func.__code__
),
)
)
.to_bytes( .to_bytes(
length=8, length=8,
byteorder="big", byteorder="big",

View File

@ -109,7 +109,7 @@ class Match(MemoizationLeaf):
return cases, default return cases, default
@classmethod @classmethod
def _create_case_var_with_var_data(cls, case_element): def _create_case_var_with_var_data(cls, case_element: Any) -> Var:
"""Convert a case element into a Var.If the case """Convert a case element into a Var.If the case
is a Style type, we extract the var data and merge it with the is a Style type, we extract the var data and merge it with the
newly created Var. newly created Var.
@ -222,7 +222,7 @@ class Match(MemoizationLeaf):
cond=match_cond_var, cond=match_cond_var,
match_cases=match_cases, match_cases=match_cases,
default=default, default=default,
children=[case[-1] for case in match_cases] + [default], # type: ignore children=[case[-1] for case in match_cases] + [default], # pyright: ignore [reportArgumentType]
) )
) )
@ -236,13 +236,13 @@ class Match(MemoizationLeaf):
_js_expr=format.format_match( _js_expr=format.format_match(
cond=str(match_cond_var), cond=str(match_cond_var),
match_cases=match_cases, match_cases=match_cases,
default=default, # type: ignore default=default, # pyright: ignore [reportArgumentType]
), ),
_var_type=default._var_type, # type: ignore _var_type=default._var_type, # pyright: ignore [reportAttributeAccessIssue,reportOptionalMemberAccess]
_var_data=VarData.merge( _var_data=VarData.merge(
match_cond_var._get_all_var_data(), match_cond_var._get_all_var_data(),
*[el._get_all_var_data() for case in match_cases for el in case], *[el._get_all_var_data() for case in match_cases for el in case],
default._get_all_var_data(), # type: ignore default._get_all_var_data(), # pyright: ignore [reportAttributeAccessIssue, reportOptionalMemberAccess]
), ),
) )

View File

@ -269,7 +269,7 @@ class Upload(MemoizationLeaf):
on_drop = upload_props["on_drop"] on_drop = upload_props["on_drop"]
if isinstance(on_drop, Callable): if isinstance(on_drop, Callable):
# Call the lambda to get the event chain. # Call the lambda to get the event chain.
on_drop = call_event_fn(on_drop, _on_drop_spec) # type: ignore on_drop = call_event_fn(on_drop, _on_drop_spec)
if isinstance(on_drop, EventSpec): if isinstance(on_drop, EventSpec):
# Update the provided args for direct use with on_drop. # Update the provided args for direct use with on_drop.
on_drop = on_drop.with_args( on_drop = on_drop.with_args(

View File

@ -449,7 +449,7 @@ class CodeBlock(Component, MarkdownComponentMap):
if can_copy: if can_copy:
code = children[0] code = children[0]
copy_button = ( # type: ignore copy_button = (
copy_button copy_button
if copy_button is not None if copy_button is not None
else Button.create( else Button.create(

View File

@ -165,7 +165,7 @@ class DataEditor(NoSSRComponent):
tag = "DataEditor" tag = "DataEditor"
is_default = True is_default = True
library: str = "@glideapps/glide-data-grid@^6.0.3" library: str | None = "@glideapps/glide-data-grid@^6.0.3"
lib_dependencies: List[str] = [ lib_dependencies: List[str] = [
"lodash@^4.17.21", "lodash@^4.17.21",
"react-responsive-carousel@^3.2.7", "react-responsive-carousel@^3.2.7",
@ -321,6 +321,8 @@ class DataEditor(NoSSRComponent):
Returns: Returns:
The import dict. The import dict.
""" """
if self.library is None:
return {}
return { return {
"": f"{format.format_library_name(self.library)}/dist/index.css", "": f"{format.format_library_name(self.library)}/dist/index.css",
self.library: "GridCellKind", self.library: "GridCellKind",
@ -343,7 +345,7 @@ class DataEditor(NoSSRComponent):
data_callback = self.get_cell_content._js_expr data_callback = self.get_cell_content._js_expr
else: else:
data_callback = f"getData_{editor_id}" data_callback = f"getData_{editor_id}"
self.get_cell_content = Var(_js_expr=data_callback) # type: ignore self.get_cell_content = Var(_js_expr=data_callback)
code = [f"function {data_callback}([col, row])" "{"] code = [f"function {data_callback}([col, row])" "{"]

View File

@ -19,10 +19,8 @@ def svg_logo(
The Reflex logo SVG. The Reflex logo SVG.
""" """
def logo_path(d): def logo_path(d: str):
return rx.el.svg.path( return rx.el.svg.path(d=d)
d=d,
)
paths = [ paths = [
"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z", "M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z",

View File

@ -602,7 +602,7 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
transformer_styles = {} transformer_styles = {}
# Collect styles from transformers and wrapper # Collect styles from transformers and wrapper
for transformer in code_block.transformers._var_value: # type: ignore for transformer in code_block.transformers._var_value: # pyright: ignore [reportAttributeAccessIssue]
if isinstance(transformer, ShikiBaseTransformers) and transformer.style: if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
transformer_styles.update(transformer.style) transformer_styles.update(transformer.style)
transformer_styles.update(code_wrapper_props.pop("style", {})) transformer_styles.update(code_wrapper_props.pop("style", {}))
@ -653,8 +653,9 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
raise ValueError( raise ValueError(
f"the function names should be str names of functions in the specified transformer: {library!r}" f"the function names should be str names of functions in the specified transformer: {library!r}"
) )
return ShikiBaseTransformers( # type: ignore return ShikiBaseTransformers(
library=library, fns=[FunctionStringVar.create(fn) for fn in fns] library=library,
fns=[FunctionStringVar.create(fn) for fn in fns], # pyright: ignore [reportCallIssue]
) )
def _render(self, props: dict[str, Any] | None = None): def _render(self, props: dict[str, Any] | None = None):
@ -757,13 +758,13 @@ class ShikiHighLevelCodeBlock(ShikiCodeBlock):
if can_copy: if can_copy:
code = children[0] code = children[0]
copy_button = ( # type: ignore copy_button = (
copy_button copy_button
if copy_button is not None if copy_button is not None
else Button.create( else Button.create(
Icon.create(tag="copy", size=16, color=color("gray", 11)), Icon.create(tag="copy", size=16, color=color("gray", 11)),
on_click=[ on_click=[
set_clipboard(cls._strip_transformer_triggers(code)), # type: ignore set_clipboard(cls._strip_transformer_triggers(code)),
copy_script(), copy_script(),
], ],
style=Style( style=Style(

View File

@ -48,4 +48,4 @@ PROP_TO_ELEMENTS = {
ELEMENT_TO_PROPS = defaultdict(list) ELEMENT_TO_PROPS = defaultdict(list)
for prop, elements in PROP_TO_ELEMENTS.items(): for prop, elements in PROP_TO_ELEMENTS.items():
for el in elements: for el in elements:
ELEMENT_TO_PROPS[el].append(prop) # type: ignore ELEMENT_TO_PROPS[el].append(prop)

View File

@ -6,7 +6,7 @@ from reflex.components.component import Component
class Element(Component): class Element(Component):
"""The base class for all raw HTML elements.""" """The base class for all raw HTML elements."""
def __eq__(self, other): def __eq__(self, other: object):
"""Two elements are equal if they have the same tag. """Two elements are equal if they have the same tag.
Args: Args:

View File

@ -153,7 +153,7 @@ class Form(BaseHTML):
target: Var[Union[str, int, bool]] target: Var[Union[str, int, bool]]
# If true, the form will be cleared after submit. # If true, the form will be cleared after submit.
reset_on_submit: Var[bool] = False # type: ignore reset_on_submit: Var[bool] = Var.create(False)
# The name used to make this form's submit handler function unique. # The name used to make this form's submit handler function unique.
handle_submit_unique_name: Var[str] handle_submit_unique_name: Var[str]
@ -405,7 +405,7 @@ class Input(BaseHTML):
(value_var := Var.create(value))._var_type (value_var := Var.create(value))._var_type
): ):
props["value"] = ternary_operation( props["value"] = ternary_operation(
(value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] (value_var != Var.create(None)) # pyright: ignore [reportArgumentType]
& (value_var != Var(_js_expr="undefined")), & (value_var != Var(_js_expr="undefined")),
value, value,
Var.create(""), Var.create(""),

View File

@ -8,7 +8,7 @@ from functools import lru_cache
from hashlib import md5 from hashlib import md5
from typing import Any, Callable, Dict, Sequence, Union from typing import Any, Callable, Dict, Sequence, Union
from reflex.components.component import Component, CustomComponent from reflex.components.component import BaseComponent, Component, CustomComponent
from reflex.components.tags.tag import Tag from reflex.components.tags.tag import Tag
from reflex.utils import types from reflex.utils import types
from reflex.utils.imports import ImportDict, ImportVar from reflex.utils.imports import ImportDict, ImportVar
@ -65,8 +65,8 @@ def get_base_component_map() -> dict[str, Callable]:
"h5": lambda value: Heading.create(value, as_="h5", size="2", margin_y="0.5em"), "h5": lambda value: Heading.create(value, as_="h5", size="2", margin_y="0.5em"),
"h6": lambda value: Heading.create(value, as_="h6", size="1", margin_y="0.5em"), "h6": lambda value: Heading.create(value, as_="h6", size="1", margin_y="0.5em"),
"p": lambda value: Text.create(value, margin_y="1em"), "p": lambda value: Text.create(value, margin_y="1em"),
"ul": lambda value: UnorderedList.create(value, margin_y="1em"), # type: ignore "ul": lambda value: UnorderedList.create(value, margin_y="1em"),
"ol": lambda value: OrderedList.create(value, margin_y="1em"), # type: ignore "ol": lambda value: OrderedList.create(value, margin_y="1em"),
"li": lambda value: ListItem.create(value, margin_y="0.5em"), "li": lambda value: ListItem.create(value, margin_y="0.5em"),
"a": lambda value: Link.create(value), "a": lambda value: Link.create(value),
"code": lambda value: Code.create(value), "code": lambda value: Code.create(value),
@ -236,7 +236,7 @@ class Markdown(Component):
), ),
}, },
*[ *[
component(_MOCK_ARG)._get_all_imports() # type: ignore component(_MOCK_ARG)._get_all_imports()
for component in self.component_map.values() for component in self.component_map.values()
], ],
] ]
@ -327,7 +327,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
if tag != "codeblock" if tag != "codeblock"
# For codeblock, the mapping for some cases returns an array of elements. Let's join them into a string. # For codeblock, the mapping for some cases returns an array of elements. Let's join them into a string.
else ternary_operation( else ternary_operation(
ARRAY_ISARRAY.call(_CHILDREN), # type: ignore ARRAY_ISARRAY.call(_CHILDREN), # pyright: ignore [reportArgumentType]
_CHILDREN.to(list).join("\n"), _CHILDREN.to(list).join("\n"),
_CHILDREN, _CHILDREN,
).to(str) ).to(str)
@ -379,7 +379,9 @@ const {_LANGUAGE!s} = match ? match[1] : '';
# fallback to the default fn Var creation if the component is not a MarkdownComponentMap. # fallback to the default fn Var creation if the component is not a MarkdownComponentMap.
return MarkdownComponentMap.create_map_fn_var(fn_body=formatted_component) return MarkdownComponentMap.create_map_fn_var(fn_body=formatted_component)
def _get_map_fn_custom_code_from_children(self, component) -> list[str]: def _get_map_fn_custom_code_from_children(
self, component: BaseComponent
) -> list[str]:
"""Recursively get markdown custom code from children components. """Recursively get markdown custom code from children components.
Args: Args:
@ -409,7 +411,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
return custom_code_list return custom_code_list
@staticmethod @staticmethod
def _component_map_hash(component_map) -> str: def _component_map_hash(component_map: dict) -> str:
inp = str( inp = str(
{tag: component(_MOCK_ARG) for tag, component in component_map.items()} {tag: component(_MOCK_ARG) for tag, component in component_map.items()}
).encode() ).encode()
@ -425,7 +427,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
for _component in self.component_map.values(): for _component in self.component_map.values():
comp = _component(_MOCK_ARG) comp = _component(_MOCK_ARG)
hooks.update(comp._get_all_hooks()) hooks.update(comp._get_all_hooks())
formatted_hooks = MACROS.module.renderHooks(hooks) # type: ignore formatted_hooks = MACROS.module.renderHooks(hooks) # pyright: ignore [reportAttributeAccessIssue]
return f""" return f"""
function {self._get_component_map_name()} () {{ function {self._get_component_map_name()} () {{
{formatted_hooks} {formatted_hooks}

View File

@ -28,9 +28,9 @@ class MomentDelta:
class Moment(NoSSRComponent): class Moment(NoSSRComponent):
"""The Moment component.""" """The Moment component."""
tag: str = "Moment" tag: str | None = "Moment"
is_default = True is_default = True
library: str = "react-moment" library: str | None = "react-moment"
lib_dependencies: List[str] = ["moment"] lib_dependencies: List[str] = ["moment"]
# How often the date update (how often time update / 0 to disable). # How often the date update (how often time update / 0 to disable).

View File

@ -1,5 +1,7 @@
"""Image component from next/image.""" """Image component from next/image."""
from __future__ import annotations
from typing import Any, Literal, Optional, Union from typing import Any, Literal, Optional, Union
from reflex.event import EventHandler, no_args_event_spec from reflex.event import EventHandler, no_args_event_spec
@ -93,7 +95,7 @@ class Image(NextComponent):
style = props.get("style", {}) style = props.get("style", {})
def check_prop_type(prop_name, prop_value): def check_prop_type(prop_name: str, prop_value: int | str | None):
if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]): if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]):
props[prop_name] = prop_value props[prop_name] = prop_value

View File

@ -17,4 +17,4 @@ class NextLink(Component):
href: Var[str] href: Var[str]
# Whether to pass the href prop to the child. # Whether to pass the href prop to the child.
pass_href: Var[bool] = True # type: ignore pass_href: Var[bool] = Var.create(True)

View File

@ -18,8 +18,8 @@ try:
Template = layout.Template Template = layout.Template
except ImportError: except ImportError:
console.warn("Plotly is not installed. Please run `pip install plotly`.") console.warn("Plotly is not installed. Please run `pip install plotly`.")
Figure = Any # type: ignore Figure = Any
Template = Any # type: ignore Template = Any
def _event_points_data_signature(e0: Var) -> Tuple[Var[List[Point]]]: def _event_points_data_signature(e0: Var) -> Tuple[Var[List[Point]]]:
@ -102,13 +102,13 @@ class Plotly(NoSSRComponent):
is_default = True is_default = True
# The figure to display. This can be a plotly figure or a plotly data json. # The figure to display. This can be a plotly figure or a plotly data json.
data: Var[Figure] # type: ignore data: Var[Figure] # pyright: ignore [reportInvalidTypeForm]
# The layout of the graph. # The layout of the graph.
layout: Var[Dict] layout: Var[Dict]
# The template for visual appearance of the graph. # The template for visual appearance of the graph.
template: Var[Template] # type: ignore template: Var[Template] # pyright: ignore [reportInvalidTypeForm]
# The config of the graph. # The config of the graph.
config: Var[Dict] config: Var[Dict]

View File

@ -48,7 +48,7 @@ class PropsBase(Base):
class NoExtrasAllowedProps(Base): class NoExtrasAllowedProps(Base):
"""A class that holds props to be passed or applied to a component with no extra props allowed.""" """A class that holds props to be passed or applied to a component with no extra props allowed."""
def __init__(self, component_name=None, **kwargs): def __init__(self, component_name: str | None = None, **kwargs):
"""Initialize the props. """Initialize the props.
Args: Args:
@ -62,13 +62,13 @@ class NoExtrasAllowedProps(Base):
try: try:
super().__init__(**kwargs) super().__init__(**kwargs)
except ValidationError as e: except ValidationError as e:
invalid_fields = ", ".join([error["loc"][0] for error in e.errors()]) # type: ignore invalid_fields = ", ".join([error["loc"][0] for error in e.errors()]) # pyright: ignore [reportCallIssue, reportArgumentType]
supported_props_str = ", ".join(f'"{field}"' for field in self.get_fields()) supported_props_str = ", ".join(f'"{field}"' for field in self.get_fields())
raise InvalidPropValueError( raise InvalidPropValueError(
f"Invalid prop(s) {invalid_fields} for {component_name!r}. Supported props are {supported_props_str}" f"Invalid prop(s) {invalid_fields} for {component_name!r}. Supported props are {supported_props_str}"
) from None ) from None
class Config: class Config: # pyright: ignore [reportIncompatibleVariableOverride]
"""Pydantic config.""" """Pydantic config."""
arbitrary_types_allowed = True arbitrary_types_allowed = True

View File

@ -55,7 +55,7 @@ from .themes.layout.container import container as container
from .themes.layout.flex import flex as flex from .themes.layout.flex import flex as flex
from .themes.layout.grid import grid as grid from .themes.layout.grid import grid as grid
from .themes.layout.list import list_item as list_item from .themes.layout.list import list_item as list_item
from .themes.layout.list import list_ns as list # noqa from .themes.layout.list import list_ns as list # noqa: F401
from .themes.layout.list import ordered_list as ordered_list from .themes.layout.list import ordered_list as ordered_list
from .themes.layout.list import unordered_list as unordered_list from .themes.layout.list import unordered_list as unordered_list
from .themes.layout.section import section as section from .themes.layout.section import section as section

View File

@ -10,6 +10,7 @@ from reflex.components.core.cond import cond
from reflex.components.lucide.icon import Icon from reflex.components.lucide.icon import Icon
from reflex.components.radix.primitives.base import RadixPrimitiveComponent from reflex.components.radix.primitives.base import RadixPrimitiveComponent
from reflex.components.radix.themes.base import LiteralAccentColor, LiteralRadius from reflex.components.radix.themes.base import LiteralAccentColor, LiteralRadius
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler from reflex.event import EventHandler
from reflex.style import Style from reflex.style import Style
from reflex.vars import get_uuid_string_var from reflex.vars import get_uuid_string_var
@ -196,8 +197,9 @@ class AccordionItem(AccordionComponent):
# The header of the accordion item. # The header of the accordion item.
header: Var[Union[Component, str]] header: Var[Union[Component, str]]
# The content of the accordion item. # The content of the accordion item.
content: Var[Union[Component, str]] = Var.create(None) content: Var[Union[Component, str, None]] = Var.create(None)
_valid_children: List[str] = [ _valid_children: List[str] = [
"AccordionHeader", "AccordionHeader",
@ -341,6 +343,8 @@ class AccordionTrigger(AccordionComponent):
alias = "RadixAccordionTrigger" alias = "RadixAccordionTrigger"
_memoization_mode = MemoizationMode(recursive=False)
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:
"""Create the Accordion trigger component. """Create the Accordion trigger component.

View File

@ -308,7 +308,9 @@ class AccordionItem(AccordionComponent):
value: Optional[Union[Var[str], str]] = None, value: Optional[Union[Var[str], str]] = None,
disabled: Optional[Union[Var[bool], bool]] = None, disabled: Optional[Union[Var[bool], bool]] = None,
header: Optional[Union[Component, Var[Union[Component, str]], str]] = None, header: Optional[Union[Component, Var[Union[Component, str]], str]] = None,
content: Optional[Union[Component, Var[Union[Component, str]], str]] = None, content: Optional[
Union[Component, Var[Optional[Union[Component, str]]], str]
] = None,
color_scheme: Optional[ color_scheme: Optional[
Union[ Union[
Literal[ Literal[

View File

@ -10,6 +10,7 @@ from reflex.components.component import Component, ComponentNamespace
from reflex.components.radix.primitives.base import RadixPrimitiveComponent from reflex.components.radix.primitives.base import RadixPrimitiveComponent
from reflex.components.radix.themes.base import Theme from reflex.components.radix.themes.base import Theme
from reflex.components.radix.themes.layout.flex import Flex from reflex.components.radix.themes.layout.flex import Flex
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -83,7 +84,9 @@ class DrawerTrigger(DrawerComponent):
alias = "Vaul" + tag alias = "Vaul" + tag
# Defaults to true, if the first child acts as the trigger. # Defaults to true, if the first child acts as the trigger.
as_child: Var[bool] = True # type: ignore as_child: Var[bool] = Var.create(True)
_memoization_mode = MemoizationMode(recursive=False)
@classmethod @classmethod
def create(cls, *children: Any, **props: Any) -> Component: def create(cls, *children: Any, **props: Any) -> Component:

View File

@ -83,7 +83,7 @@ class ProgressIndicator(ProgressComponent):
"&[data_state='loading']": { "&[data_state='loading']": {
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear", "transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
}, },
"transform": f"translateX(calc(-100% + ({self.value} / {self.max} * 100%)))", # type: ignore "transform": f"translateX(calc(-100% + ({self.value} / {self.max} * 100%)))",
"boxShadow": "inset 0 0 0 1px var(--gray-a5)", "boxShadow": "inset 0 0 0 1px var(--gray-a5)",
} }

View File

@ -30,7 +30,7 @@ def on_value_event_spec(
Returns: Returns:
The event handler spec. The event handler spec.
""" """
return (value,) # type: ignore return (value,)
class SliderRoot(SliderComponent): class SliderRoot(SliderComponent):

View File

@ -17,7 +17,7 @@ rx.text(
from __future__ import annotations from __future__ import annotations
from typing import Dict, List, Literal, Optional, Union, get_args from typing import Any, Dict, List, Literal, Optional, Union, get_args
from reflex.components.component import BaseComponent from reflex.components.component import BaseComponent
from reflex.components.core.cond import Cond, color_mode_cond, cond from reflex.components.core.cond import Cond, color_mode_cond, cond
@ -78,17 +78,19 @@ position_map: Dict[str, List[str]] = {
# needed to inverse contains for find # needed to inverse contains for find
def _find(const: List[str], var): def _find(const: List[str], var: Any):
return LiteralArrayVar.create(const).contains(var) return LiteralArrayVar.create(const).contains(var)
def _set_var_default(props, position, prop, default1, default2=""): def _set_var_default(
props: dict, position: Any, prop: str, default1: str, default2: str = ""
):
props.setdefault( props.setdefault(
prop, cond(_find(position_map[prop], position), default1, default2) prop, cond(_find(position_map[prop], position), default1, default2)
) )
def _set_static_default(props, position, prop, default): def _set_static_default(props: dict, position: Any, prop: str, default: str):
if prop in position: if prop in position:
props.setdefault(prop, default) props.setdefault(prop, default)
@ -115,12 +117,12 @@ class ColorModeIconButton(IconButton):
Returns: Returns:
The button component. The button component.
""" """
position = props.pop("position", None) position: str | Var = props.pop("position", None)
allow_system = props.pop("allow_system", False) allow_system = props.pop("allow_system", False)
# position is used to set nice defaults for positioning the icon button # position is used to set nice defaults for positioning the icon button
if isinstance(position, Var): if isinstance(position, Var):
_set_var_default(props, position, "position", "fixed", position) # type: ignore _set_var_default(props, position, "position", "fixed", position) # pyright: ignore [reportArgumentType]
_set_var_default(props, position, "bottom", "2rem") _set_var_default(props, position, "bottom", "2rem")
_set_var_default(props, position, "top", "2rem") _set_var_default(props, position, "top", "2rem")
_set_var_default(props, position, "left", "2rem") _set_var_default(props, position, "left", "2rem")
@ -142,7 +144,7 @@ class ColorModeIconButton(IconButton):
if allow_system: if allow_system:
def color_mode_item(_color_mode): def color_mode_item(_color_mode: str):
return dropdown_menu.item( return dropdown_menu.item(
_color_mode.title(), on_click=set_color_mode(_color_mode) _color_mode.title(), on_click=set_color_mode(_color_mode)
) )

View File

@ -5,6 +5,7 @@ from typing import Literal
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.components.el import elements from reflex.components.el import elements
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -33,6 +34,8 @@ class AlertDialogTrigger(RadixThemesTriggerComponent):
tag = "AlertDialog.Trigger" tag = "AlertDialog.Trigger"
_memoization_mode = MemoizationMode(recursive=False)
class AlertDialogContent(elements.Div, RadixThemesComponent): class AlertDialogContent(elements.Div, RadixThemesComponent):
"""Contains the content of the dialog. This component is based on the div element.""" """Contains the content of the dialog. This component is based on the div element."""

View File

@ -4,6 +4,7 @@ from typing import Dict, List, Literal, Union
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -55,6 +56,8 @@ class ContextMenuTrigger(RadixThemesComponent):
_invalid_children: List[str] = ["ContextMenuContent"] _invalid_children: List[str] = ["ContextMenuContent"]
_memoization_mode = MemoizationMode(recursive=False)
class ContextMenuContent(RadixThemesComponent): class ContextMenuContent(RadixThemesComponent):
"""The component that pops out when the context menu is open.""" """The component that pops out when the context menu is open."""
@ -153,6 +156,8 @@ class ContextMenuSubTrigger(RadixThemesComponent):
_valid_parents: List[str] = ["ContextMenuContent", "ContextMenuSub"] _valid_parents: List[str] = ["ContextMenuContent", "ContextMenuSub"]
_memoization_mode = MemoizationMode(recursive=False)
class ContextMenuSubContent(RadixThemesComponent): class ContextMenuSubContent(RadixThemesComponent):
"""The component that pops out when a submenu is open.""" """The component that pops out when a submenu is open."""

View File

@ -5,6 +5,7 @@ from typing import Literal
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.components.el import elements from reflex.components.el import elements
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -31,6 +32,8 @@ class DialogTrigger(RadixThemesTriggerComponent):
tag = "Dialog.Trigger" tag = "Dialog.Trigger"
_memoization_mode = MemoizationMode(recursive=False)
class DialogTitle(RadixThemesComponent): class DialogTitle(RadixThemesComponent):
"""Title component to display inside a Dialog modal.""" """Title component to display inside a Dialog modal."""

View File

@ -4,6 +4,7 @@ from typing import Dict, List, Literal, Union
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -60,6 +61,8 @@ class DropdownMenuTrigger(RadixThemesTriggerComponent):
_invalid_children: List[str] = ["DropdownMenuContent"] _invalid_children: List[str] = ["DropdownMenuContent"]
_memoization_mode = MemoizationMode(recursive=False)
class DropdownMenuContent(RadixThemesComponent): class DropdownMenuContent(RadixThemesComponent):
"""The Dropdown Menu Content component that pops out when the dropdown menu is open.""" """The Dropdown Menu Content component that pops out when the dropdown menu is open."""
@ -143,6 +146,8 @@ class DropdownMenuSubTrigger(RadixThemesTriggerComponent):
_valid_parents: List[str] = ["DropdownMenuContent", "DropdownMenuSub"] _valid_parents: List[str] = ["DropdownMenuContent", "DropdownMenuSub"]
_memoization_mode = MemoizationMode(recursive=False)
class DropdownMenuSub(RadixThemesComponent): class DropdownMenuSub(RadixThemesComponent):
"""Contains all the parts of a submenu.""" """Contains all the parts of a submenu."""

View File

@ -5,6 +5,7 @@ from typing import Dict, Literal, Union
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.components.el import elements from reflex.components.el import elements
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, passthrough_event_spec from reflex.event import EventHandler, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -37,6 +38,8 @@ class HoverCardTrigger(RadixThemesTriggerComponent):
tag = "HoverCard.Trigger" tag = "HoverCard.Trigger"
_memoization_mode = MemoizationMode(recursive=False)
class HoverCardContent(elements.Div, RadixThemesComponent): class HoverCardContent(elements.Div, RadixThemesComponent):
"""Contains the content of the open hover card.""" """Contains the content of the open hover card."""

View File

@ -5,6 +5,7 @@ from typing import Dict, Literal, Union
from reflex.components.component import ComponentNamespace from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.components.el import elements from reflex.components.el import elements
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -34,6 +35,8 @@ class PopoverTrigger(RadixThemesTriggerComponent):
tag = "Popover.Trigger" tag = "Popover.Trigger"
_memoization_mode = MemoizationMode(recursive=False)
class PopoverContent(elements.Div, RadixThemesComponent): class PopoverContent(elements.Div, RadixThemesComponent):
"""Contains content to be rendered in the open popover.""" """Contains content to be rendered in the open popover."""

View File

@ -85,6 +85,8 @@ class RadioCardsItem(RadixThemesComponent):
# When true, indicates that the user must check the radio item before the owning form can be submitted. # When true, indicates that the user must check the radio item before the owning form can be submitted.
required: Var[bool] required: Var[bool]
_valid_parents: list[str] = ["RadioCardsRoot"]
class RadioCards(SimpleNamespace): class RadioCards(SimpleNamespace):
"""RadioCards components namespace.""" """RadioCards components namespace."""

View File

@ -155,7 +155,7 @@ class HighLevelRadioGroup(RadixThemesComponent):
if isinstance(default_value, str) or ( if isinstance(default_value, str) or (
isinstance(default_value, Var) and default_value._var_type is str isinstance(default_value, Var) and default_value._var_type is str
): ):
default_value = LiteralVar.create(default_value) # type: ignore default_value = LiteralVar.create(default_value)
else: else:
default_value = LiteralVar.create(default_value).to_string() default_value = LiteralVar.create(default_value).to_string()

View File

@ -5,6 +5,7 @@ from typing import List, Literal, Union
import reflex as rx import reflex as rx
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.constants.compiler import MemoizationMode
from reflex.event import no_args_event_spec, passthrough_event_spec from reflex.event import no_args_event_spec, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -69,6 +70,8 @@ class SelectTrigger(RadixThemesComponent):
_valid_parents: List[str] = ["SelectRoot"] _valid_parents: List[str] = ["SelectRoot"]
_memoization_mode = MemoizationMode(recursive=False)
class SelectContent(RadixThemesComponent): class SelectContent(RadixThemesComponent):
"""The component that pops out when the select is open.""" """The component that pops out when the select is open."""

View File

@ -7,6 +7,7 @@ from typing import Any, Dict, List, Literal
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
from reflex.components.core.breakpoints import Responsive from reflex.components.core.breakpoints import Responsive
from reflex.components.core.colors import color from reflex.components.core.colors import color
from reflex.constants.compiler import MemoizationMode
from reflex.event import EventHandler, passthrough_event_spec from reflex.event import EventHandler, passthrough_event_spec
from reflex.vars.base import Var from reflex.vars.base import Var
@ -95,6 +96,8 @@ class TabsTrigger(RadixThemesComponent):
_valid_parents: List[str] = ["TabsList"] _valid_parents: List[str] = ["TabsList"]
_memoization_mode = MemoizationMode(recursive=False)
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:
"""Create a TabsTrigger component. """Create a TabsTrigger component.

View File

@ -96,5 +96,17 @@ class TextArea(RadixThemesComponent, elements.Textarea):
return DebounceInput.create(super().create(*children, **props)) return DebounceInput.create(super().create(*children, **props))
return super().create(*children, **props) return super().create(*children, **props)
def add_style(self):
"""Add the style to the component.
Returns:
The style of the component.
"""
added_style: dict[str, dict] = {}
added_style.setdefault("& textarea", {})
if "padding" in self.style:
added_style["& textarea"]["padding"] = self.style.pop("padding")
return added_style
text_area = TextArea.create text_area = TextArea.create

View File

@ -268,4 +268,6 @@ class TextArea(RadixThemesComponent, elements.Textarea):
""" """
... ...
def add_style(self): ...
text_area = TextArea.create text_area = TextArea.create

View File

@ -105,7 +105,7 @@ class TextFieldRoot(elements.Input, RadixThemesComponent):
(value_var := Var.create(value))._var_type (value_var := Var.create(value))._var_type
): ):
props["value"] = ternary_operation( props["value"] = ternary_operation(
(value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] (value_var != Var.create(None)) # pyright: ignore [reportArgumentType]
& (value_var != Var(_js_expr="undefined")), & (value_var != Var(_js_expr="undefined")),
value, value,
Var.create(""), Var.create(""),

View File

@ -9,7 +9,7 @@ from .container import container as container
from .flex import flex as flex from .flex import flex as flex
from .grid import grid as grid from .grid import grid as grid
from .list import list_item as list_item from .list import list_item as list_item
from .list import list_ns as list # noqa from .list import list_ns as list # noqa: F401
from .list import ordered_list as ordered_list from .list import ordered_list as ordered_list
from .list import unordered_list as unordered_list from .list import unordered_list as unordered_list
from .section import section as section from .section import section as section

View File

@ -72,7 +72,7 @@ class BaseList(Component, MarkdownComponentMap):
if isinstance(items, Var): if isinstance(items, Var):
children = [Foreach.create(items, ListItem.create)] children = [Foreach.create(items, ListItem.create)]
else: else:
children = [ListItem.create(item) for item in items] # type: ignore children = [ListItem.create(item) for item in items]
props["direction"] = "column" props["direction"] = "column"
style = props.setdefault("style", {}) style = props.setdefault("style", {})
style["list_style_type"] = list_style_type style["list_style_type"] = list_style_type
@ -189,7 +189,7 @@ ordered_list = list_ns.ordered
unordered_list = list_ns.unordered unordered_list = list_ns.unordered
def __getattr__(name): def __getattr__(name: Any):
# special case for when accessing list to avoid shadowing # special case for when accessing list to avoid shadowing
# python's built in list object. # python's built in list object.
if name == "list": if name == "list":

View File

@ -49,14 +49,14 @@ class VStack(Stack):
"""A vertical stack component.""" """A vertical stack component."""
# The direction of the stack. # The direction of the stack.
direction: Var[LiteralFlexDirection] = "column" # type: ignore direction: Var[LiteralFlexDirection] = Var.create("column")
class HStack(Stack): class HStack(Stack):
"""A horizontal stack component.""" """A horizontal stack component."""
# The direction of the stack. # The direction of the stack.
direction: Var[LiteralFlexDirection] = "row" # type: ignore direction: Var[LiteralFlexDirection] = Var.create("row")
stack = Stack.create stack = Stack.create

View File

@ -60,7 +60,7 @@ class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap):
Returns: Returns:
The import dict. The import dict.
""" """
return next_link._get_imports() # type: ignore return next_link._get_imports() # pyright: ignore [reportReturnType]
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:

View File

@ -47,7 +47,7 @@ class Text(elements.Span, RadixThemesComponent, MarkdownComponentMap):
as_child: Var[bool] as_child: Var[bool]
# Change the default rendered element into a semantically appropriate alternative (cannot be used with asChild) # Change the default rendered element into a semantically appropriate alternative (cannot be used with asChild)
as_: Var[LiteralType] = "p" # type: ignore as_: Var[LiteralType] = Var.create("p")
# Text size: "1" - "9" # Text size: "1" - "9"
size: Var[Responsive[LiteralTextSize]] size: Var[Responsive[LiteralTextSize]]
@ -71,7 +71,7 @@ class Text(elements.Span, RadixThemesComponent, MarkdownComponentMap):
class Span(Text): class Span(Text):
"""A variant of text rendering as <span> element.""" """A variant of text rendering as <span> element."""
as_: Var[LiteralType] = "span" # type: ignore as_: Var[LiteralType] = Var.create("span")
class Em(elements.Em, RadixThemesComponent): class Em(elements.Em, RadixThemesComponent):

View File

@ -39,7 +39,7 @@ class ReactPlayer(NoSSRComponent):
loop: Var[bool] loop: Var[bool]
# Set to true or false to display native player controls. # Set to true or false to display native player controls.
controls: Var[bool] = True # type: ignore controls: Var[bool] = Var.create(True)
# Set to true to show just the video thumbnail, which loads the full player on click # Set to true to show just the video thumbnail, which loads the full player on click
light: Var[bool] light: Var[bool]

View File

@ -25,10 +25,10 @@ class ChartBase(RechartsCharts):
"""A component that wraps a Recharts charts.""" """A component that wraps a Recharts charts."""
# The width of chart container. String or Integer # The width of chart container. String or Integer
width: Var[Union[str, int]] = "100%" # type: ignore width: Var[Union[str, int]] = Var.create("100%")
# The height of chart container. # The height of chart container.
height: Var[Union[str, int]] = "100%" # type: ignore height: Var[Union[str, int]] = Var.create("100%")
# The customized event handler of click on the component in this chart # The customized event handler of click on the component in this chart
on_click: EventHandler[no_args_event_spec] on_click: EventHandler[no_args_event_spec]
@ -69,7 +69,7 @@ class ChartBase(RechartsCharts):
) )
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children: Any, **props: Any) -> Component:
"""Create a chart component. """Create a chart component.
Args: Args:
@ -84,21 +84,19 @@ class ChartBase(RechartsCharts):
cls._ensure_valid_dimension("width", width) cls._ensure_valid_dimension("width", width)
cls._ensure_valid_dimension("height", height) cls._ensure_valid_dimension("height", height)
dim_props = {
"width": width if width is not None else "100%",
"height": height if height is not None else "100%",
}
# Ensure that the min_height and min_width are set to prevent the chart from collapsing. # Ensure that the min_height and min_width are set to prevent the chart from collapsing.
# We are using small values so that height and width can still be used over min_height and min_width. # We are using small values so that height and width can still be used over min_height and min_width.
# Without this, sometimes the chart will not be visible. Causing confusion to the user. # Without this, sometimes the chart will not be visible. Causing confusion to the user.
# With this, the user will see a small chart and can adjust the height and width and can figure out that the issue is with the size. # With this, the user will see a small chart and can adjust the height and width and can figure out that the issue is with the size.
dim_props["min_height"] = props.pop("min_height", 10) min_height = props.pop("min_height", 10)
dim_props["min_width"] = props.pop("min_width", 10) min_width = props.pop("min_width", 10)
return ResponsiveContainer.create( return ResponsiveContainer.create(
super().create(*children, **props), super().create(*children, **props),
**dim_props, # type: ignore width=width if width is not None else "100%",
height=height if height is not None else "100%",
min_width=min_width,
min_height=min_height,
) )
@ -460,10 +458,10 @@ class Treemap(RechartsCharts):
alias = "RechartsTreemap" alias = "RechartsTreemap"
# The width of chart container. String or Integer. Default: "100%" # The width of chart container. String or Integer. Default: "100%"
width: Var[Union[str, int]] = "100%" # type: ignore width: Var[Union[str, int]] = Var.create("100%")
# The height of chart container. String or Integer. Default: "100%" # The height of chart container. String or Integer. Default: "100%"
height: Var[Union[str, int]] = "100%" # type: ignore height: Var[Union[str, int]] = Var.create("100%")
# data of treemap. Array # data of treemap. Array
data: Var[List[Dict[str, Any]]] data: Var[List[Dict[str, Any]]]

View File

@ -64,7 +64,7 @@ class Pie(Recharts):
legend_type: Var[LiteralLegendType] legend_type: Var[LiteralLegendType]
# If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. Default: False # If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. Default: False
label: Var[bool] = False # type: ignore label: Var[bool] = Var.create(False)
# If false set, label lines will not be drawn. If true set, label lines will be drawn which have the props calculated internally. Default: False # If false set, label lines will not be drawn. If true set, label lines will be drawn which have the props calculated internally. Default: False
label_line: Var[bool] label_line: Var[bool]

View File

@ -132,7 +132,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
# Function that gets called when the toast disappears automatically after it's timeout (duration` prop). # Function that gets called when the toast disappears automatically after it's timeout (duration` prop).
on_auto_close: Optional[Any] on_auto_close: Optional[Any]
def dict(self, *args, **kwargs) -> dict[str, Any]: def dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
"""Convert the object to a dictionary. """Convert the object to a dictionary.
Args: Args:
@ -142,7 +142,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
Returns: Returns:
The object as a dictionary with ToastAction fields intact. The object as a dictionary with ToastAction fields intact.
""" """
kwargs.setdefault("exclude_none", True) # type: ignore kwargs.setdefault("exclude_none", True)
d = super().dict(*args, **kwargs) d = super().dict(*args, **kwargs)
# Keep these fields as ToastAction so they can be serialized specially # Keep these fields as ToastAction so they can be serialized specially
if "action" in d: if "action" in d:
@ -167,7 +167,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
class Toaster(Component): class Toaster(Component):
"""A Toaster Component for displaying toast notifications.""" """A Toaster Component for displaying toast notifications."""
library: str = "sonner@1.7.2" library: str | None = "sonner@1.7.2"
tag = "Toaster" tag = "Toaster"
@ -222,6 +222,8 @@ class Toaster(Component):
Returns: Returns:
The hooks for the toaster component. The hooks for the toaster component.
""" """
if self.library is None:
return []
hook = Var( hook = Var(
_js_expr=f"{toast_ref} = toast", _js_expr=f"{toast_ref} = toast",
_var_data=VarData( _var_data=VarData(
@ -266,7 +268,7 @@ class Toaster(Component):
raise ValueError("Toast message or title or description must be provided.") raise ValueError("Toast message or title or description must be provided.")
if props: if props:
args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue, reportGeneralTypeIssues] args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue]
toast = toast_command.call(message, args) toast = toast_command.call(message, args)
else: else:
toast = toast_command.call(message) toast = toast_command.call(message)
@ -274,12 +276,12 @@ class Toaster(Component):
return run_script(toast) return run_script(toast)
@staticmethod @staticmethod
def toast_info(message: str | Var = "", **kwargs): def toast_info(message: str | Var = "", **kwargs: Any):
"""Display an info toast message. """Display an info toast message.
Args: Args:
message: The message to display. message: The message to display.
kwargs: Additional toast props. **kwargs: Additional toast props.
Returns: Returns:
The toast event. The toast event.
@ -287,12 +289,12 @@ class Toaster(Component):
return Toaster.send_toast(message, level="info", **kwargs) return Toaster.send_toast(message, level="info", **kwargs)
@staticmethod @staticmethod
def toast_warning(message: str | Var = "", **kwargs): def toast_warning(message: str | Var = "", **kwargs: Any):
"""Display a warning toast message. """Display a warning toast message.
Args: Args:
message: The message to display. message: The message to display.
kwargs: Additional toast props. **kwargs: Additional toast props.
Returns: Returns:
The toast event. The toast event.
@ -300,12 +302,12 @@ class Toaster(Component):
return Toaster.send_toast(message, level="warning", **kwargs) return Toaster.send_toast(message, level="warning", **kwargs)
@staticmethod @staticmethod
def toast_error(message: str | Var = "", **kwargs): def toast_error(message: str | Var = "", **kwargs: Any):
"""Display an error toast message. """Display an error toast message.
Args: Args:
message: The message to display. message: The message to display.
kwargs: Additional toast props. **kwargs: Additional toast props.
Returns: Returns:
The toast event. The toast event.
@ -313,12 +315,12 @@ class Toaster(Component):
return Toaster.send_toast(message, level="error", **kwargs) return Toaster.send_toast(message, level="error", **kwargs)
@staticmethod @staticmethod
def toast_success(message: str | Var = "", **kwargs): def toast_success(message: str | Var = "", **kwargs: Any):
"""Display a success toast message. """Display a success toast message.
Args: Args:
message: The message to display. message: The message to display.
kwargs: Additional toast props. **kwargs: Additional toast props.
Returns: Returns:
The toast event. The toast event.
@ -350,7 +352,7 @@ class Toaster(Component):
return run_script(dismiss_action) return run_script(dismiss_action)
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children: Any, **props: Any) -> Component:
"""Create a toaster component. """Create a toaster component.
Args: Args:

View File

@ -51,7 +51,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
on_dismiss: Optional[Any] on_dismiss: Optional[Any]
on_auto_close: Optional[Any] on_auto_close: Optional[Any]
def dict(self, *args, **kwargs) -> dict[str, Any]: ... def dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
class Toaster(Component): class Toaster(Component):
is_used: ClassVar[bool] = False is_used: ClassVar[bool] = False
@ -62,13 +62,13 @@ class Toaster(Component):
message: str | Var = "", level: str | None = None, **props message: str | Var = "", level: str | None = None, **props
) -> EventSpec: ... ) -> EventSpec: ...
@staticmethod @staticmethod
def toast_info(message: str | Var = "", **kwargs): ... def toast_info(message: str | Var = "", **kwargs: Any): ...
@staticmethod @staticmethod
def toast_warning(message: str | Var = "", **kwargs): ... def toast_warning(message: str | Var = "", **kwargs: Any): ...
@staticmethod @staticmethod
def toast_error(message: str | Var = "", **kwargs): ... def toast_error(message: str | Var = "", **kwargs: Any): ...
@staticmethod @staticmethod
def toast_success(message: str | Var = "", **kwargs): ... def toast_success(message: str | Var = "", **kwargs: Any): ...
@staticmethod @staticmethod
def toast_dismiss(id: Var | str | None = None): ... def toast_dismiss(id: Var | str | None = None): ...
@overload @overload

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
import enum import enum
from typing import Dict, List, Literal, Optional, Tuple, Union from typing import Any, Dict, List, Literal, Optional, Tuple, Union
from reflex.base import Base from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent from reflex.components.component import Component, NoSSRComponent
@ -115,7 +115,7 @@ class Editor(NoSSRComponent):
# Alternatively to a string, a dict of your language can be passed to this prop. # Alternatively to a string, a dict of your language can be passed to this prop.
# Please refer to the library docs for this. # Please refer to the library docs for this.
# options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | # options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" |
# "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" # "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it"
# default: "en". # default: "en".
lang: Var[ lang: Var[
Union[ Union[
@ -244,11 +244,13 @@ class Editor(NoSSRComponent):
} }
@classmethod @classmethod
def create(cls, set_options: Optional[EditorOptions] = None, **props) -> Component: def create(
cls, set_options: Optional[EditorOptions] = None, **props: Any
) -> Component:
"""Create an instance of Editor. No children allowed. """Create an instance of Editor. No children allowed.
Args: Args:
set_options(Optional[EditorOptions]): Configuration object to further configure the instance. set_options: Configuration object to further configure the instance.
**props: Any properties to be passed to the Editor **props: Any properties to be passed to the Editor
Returns: Returns:

View File

@ -171,8 +171,8 @@ class Editor(NoSSRComponent):
"""Create an instance of Editor. No children allowed. """Create an instance of Editor. No children allowed.
Args: Args:
set_options(Optional[EditorOptions]): Configuration object to further configure the instance. set_options: Configuration object to further configure the instance.
lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default: "en". lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default: "en".
name: This is used to set the HTML form name of the editor. This means on HTML form submission, it will be submitted together with contents of the editor by the name provided. name: This is used to set the HTML form name of the editor. This means on HTML form submission, it will be submitted together with contents of the editor by the name provided.
default_value: Sets the default value of the editor. This is useful if you don't want the on_change method to be called on render. If you want the on_change method to be called on render please use the set_contents prop default_value: Sets the default value of the editor. This is useful if you don't want the on_change method to be called on render. If you want the on_change method to be called on render please use the set_contents prop
width: Sets the width of the editor. px and percentage values are accepted, eg width="100%" or width="500px" default: 100% width: Sets the width of the editor. px and percentage values are accepted, eg width="100%" or width="500px" default: 100%

View File

@ -41,14 +41,14 @@ class IterTag(Tag):
try: try:
if iterable._var_type.mro()[0] is dict: if iterable._var_type.mro()[0] is dict:
# Arg is a tuple of (key, value). # Arg is a tuple of (key, value).
return Tuple[get_args(iterable._var_type)] # type: ignore return Tuple[get_args(iterable._var_type)] # pyright: ignore [reportReturnType]
elif iterable._var_type.mro()[0] is tuple: elif iterable._var_type.mro()[0] is tuple:
# Arg is a union of any possible values in the tuple. # Arg is a union of any possible values in the tuple.
return Union[get_args(iterable._var_type)] # type: ignore return Union[get_args(iterable._var_type)] # pyright: ignore [reportReturnType]
else: else:
return get_args(iterable._var_type)[0] return get_args(iterable._var_type)[0]
except Exception: except Exception:
return Any return Any # pyright: ignore [reportReturnType]
def get_index_var(self) -> Var: def get_index_var(self) -> Var:
"""Get the index var for the tag (with curly braces). """Get the index var for the tag (with curly braces).

View File

@ -3,13 +3,33 @@
from __future__ import annotations from __future__ import annotations
import dataclasses import dataclasses
from typing import Any, Dict, List, Optional, Union from typing import Any, Dict, List, Optional, Sequence, Union
from reflex.event import EventChain from reflex.event import EventChain
from reflex.utils import format, types from reflex.utils import format, types
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
def render_prop(value: Any) -> Any:
"""Render the prop.
Args:
value: The value to render.
Returns:
The rendered value.
"""
from reflex.components.component import BaseComponent
if isinstance(value, BaseComponent):
return value.render()
if isinstance(value, Sequence) and not isinstance(value, str):
return [render_prop(v) for v in value]
if callable(value) and not isinstance(value, Var):
return None
return value
@dataclasses.dataclass() @dataclasses.dataclass()
class Tag: class Tag:
"""A React tag.""" """A React tag."""
@ -49,7 +69,7 @@ class Tag:
"""Set the tag's fields. """Set the tag's fields.
Args: Args:
kwargs: The fields to set. **kwargs: The fields to set.
Returns: Returns:
The tag with the fields The tag with the fields
@ -66,7 +86,9 @@ class Tag:
Tuple[str, Any]: The field name and value. Tuple[str, Any]: The field name and value.
""" """
for field in dataclasses.fields(self): for field in dataclasses.fields(self):
yield field.name, getattr(self, field.name) rendered_value = render_prop(getattr(self, field.name))
if rendered_value is not None:
yield field.name, rendered_value
def add_props(self, **kwargs: Optional[Any]) -> Tag: def add_props(self, **kwargs: Optional[Any]) -> Tag:
"""Add props to the tag. """Add props to the tag.

View File

@ -390,7 +390,7 @@ class EnvVar(Generic[T]):
os.environ[self.name] = str(value) os.environ[self.name] = str(value)
class env_var: # type: ignore # noqa: N801 class env_var: # noqa: N801 # pyright: ignore [reportRedeclaration]
"""Descriptor for environment variables.""" """Descriptor for environment variables."""
name: str name: str
@ -407,7 +407,7 @@ class env_var: # type: ignore # noqa: N801
self.default = default self.default = default
self.internal = internal self.internal = internal
def __set_name__(self, owner, name): def __set_name__(self, owner: Any, name: str):
"""Set the name of the descriptor. """Set the name of the descriptor.
Args: Args:
@ -416,7 +416,7 @@ class env_var: # type: ignore # noqa: N801
""" """
self.name = name self.name = name
def __get__(self, instance, owner): def __get__(self, instance: Any, owner: Any):
"""Get the EnvVar instance. """Get the EnvVar instance.
Args: Args:
@ -435,7 +435,7 @@ class env_var: # type: ignore # noqa: N801
if TYPE_CHECKING: if TYPE_CHECKING:
def env_var(default, internal=False) -> EnvVar: def env_var(default: Any, internal: bool = False) -> EnvVar:
"""Typing helper for the env_var descriptor. """Typing helper for the env_var descriptor.
Args: Args:
@ -600,7 +600,7 @@ class Config(Base):
See the [configuration](https://reflex.dev/docs/getting-started/configuration/) docs for more info. See the [configuration](https://reflex.dev/docs/getting-started/configuration/) docs for more info.
""" """
class Config: class Config: # pyright: ignore [reportIncompatibleVariableOverride]
"""Pydantic config for the config.""" """Pydantic config for the config."""
validate_assignment = True validate_assignment = True
@ -769,7 +769,7 @@ class Config(Base):
""" """
if self.env_file: if self.env_file:
try: try:
from dotenv import load_dotenv # type: ignore from dotenv import load_dotenv # pyright: ignore [reportMissingImports]
# load env file if exists # load env file if exists
load_dotenv(self.env_file, override=True) load_dotenv(self.env_file, override=True)

View File

@ -75,6 +75,8 @@ class Reflex(SimpleNamespace):
# If user sets REFLEX_DIR envroment variable use that instead. # If user sets REFLEX_DIR envroment variable use that instead.
DIR = PlatformDirs(MODULE_NAME, False).user_data_path DIR = PlatformDirs(MODULE_NAME, False).user_data_path
LOGS_DIR = DIR / "logs"
# The root directory of the reflex library. # The root directory of the reflex library.
ROOT_DIR = Path(__file__).parents[2] ROOT_DIR = Path(__file__).parents[2]

View File

@ -1,10 +1,10 @@
"""Compiler variables.""" """Compiler variables."""
import dataclasses
import enum import enum
from enum import Enum from enum import Enum
from types import SimpleNamespace from types import SimpleNamespace
from reflex.base import Base
from reflex.constants import Dirs from reflex.constants import Dirs
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
@ -151,7 +151,8 @@ class MemoizationDisposition(enum.Enum):
NEVER = "never" NEVER = "never"
class MemoizationMode(Base): @dataclasses.dataclass(frozen=True)
class MemoizationMode:
"""The mode for memoizing a Component.""" """The mode for memoizing a Component."""
# The conditions under which the component should be memoized. # The conditions under which the component should be memoized.

View File

@ -83,7 +83,7 @@ def _get_package_config(exit_on_fail: bool = True) -> dict:
The package configuration. The package configuration.
Raises: Raises:
Exit: If the pyproject.toml file is not found. Exit: If the pyproject.toml file is not found and exit_on_fail is True.
""" """
pyproject = Path(CustomComponents.PYPROJECT_TOML) pyproject = Path(CustomComponents.PYPROJECT_TOML)
try: try:
@ -925,7 +925,7 @@ def _get_file_from_prompt_in_loop() -> Tuple[bytes, str] | None:
image_file = file_extension = None image_file = file_extension = None
while image_file is None: while image_file is None:
image_filepath = Path( image_filepath = Path(
console.ask("Upload a preview image of your demo app (enter to skip)") console.ask("Upload a preview image of your demo app (enter to skip)") # pyright: ignore [reportArgumentType]
) )
if not image_filepath: if not image_filepath:
break break

View File

@ -243,7 +243,7 @@ class EventHandler(EventActionsMixin):
raise EventHandlerTypeError( raise EventHandlerTypeError(
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}." f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
) from e ) from e
payload = tuple(zip(fn_args, values)) payload = tuple(zip(fn_args, values, strict=False))
# Return the event spec. # Return the event spec.
return EventSpec( return EventSpec(
@ -263,7 +263,7 @@ class EventSpec(EventActionsMixin):
""" """
# The event handler. # The event handler.
handler: EventHandler = dataclasses.field(default=None) # type: ignore handler: EventHandler = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
# The handler on the client to process event. # The handler on the client to process event.
client_handler_name: str = dataclasses.field(default="") client_handler_name: str = dataclasses.field(default="")
@ -337,7 +337,7 @@ class EventSpec(EventActionsMixin):
raise EventHandlerTypeError( raise EventHandlerTypeError(
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}." f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
) from e ) from e
new_payload = tuple(zip(fn_args, values)) new_payload = tuple(zip(fn_args, values, strict=False))
return self.with_args(self.args + new_payload) return self.with_args(self.args + new_payload)
@ -589,7 +589,7 @@ def no_args_event_spec() -> Tuple[()]:
Returns: Returns:
An empty tuple. An empty tuple.
""" """
return () # type: ignore return ()
# These chains can be used for their side effects when no other events are desired. # These chains can be used for their side effects when no other events are desired.
@ -617,9 +617,9 @@ class IdentityEventReturn(Generic[T], Protocol):
@overload @overload
def passthrough_event_spec( def passthrough_event_spec( # pyright: ignore [reportOverlappingOverload]
event_type: Type[T], / event_type: Type[T], /
) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore ) -> Callable[[Var[T]], Tuple[Var[T]]]: ...
@overload @overload
@ -632,7 +632,7 @@ def passthrough_event_spec(
def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: ... def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # pyright: ignore [reportInconsistentOverload]
"""A helper function that returns the input event as output. """A helper function that returns the input event as output.
Args: Args:
@ -646,9 +646,9 @@ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: #
return values return values
inner_type = tuple(Var[event_type] for event_type in event_types) inner_type = tuple(Var[event_type] for event_type in event_types)
return_annotation = Tuple[inner_type] # type: ignore return_annotation = Tuple[inner_type]
inner.__signature__ = inspect.signature(inner).replace( # type: ignore inner.__signature__ = inspect.signature(inner).replace( # pyright: ignore [reportFunctionMemberAccess]
parameters=[ parameters=[
inspect.Parameter( inspect.Parameter(
f"ev_{i}", f"ev_{i}",
@ -730,7 +730,7 @@ class FileUpload:
# Call the lambda to get the event chain. # Call the lambda to get the event chain.
events = call_event_fn( events = call_event_fn(
on_upload_progress, self.on_upload_progress_args_spec on_upload_progress, self.on_upload_progress_args_spec
) # type: ignore )
else: else:
raise ValueError(f"{on_upload_progress} is not a valid event handler.") raise ValueError(f"{on_upload_progress} is not a valid event handler.")
if isinstance(events, Var): if isinstance(events, Var):
@ -777,7 +777,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
return None return None
fn.__qualname__ = name fn.__qualname__ = name
fn.__signature__ = sig fn.__signature__ = sig # pyright: ignore [reportFunctionMemberAccess]
return EventSpec( return EventSpec(
handler=EventHandler(fn=fn, state_full_name=FRONTEND_EVENT_STATE), handler=EventHandler(fn=fn, state_full_name=FRONTEND_EVENT_STATE),
args=tuple( args=tuple(
@ -1050,13 +1050,13 @@ def download(
is_data_url = (data.js_type() == "string") & ( is_data_url = (data.js_type() == "string") & (
data.to(str).startswith("data:") data.to(str).startswith("data:")
) # type: ignore )
# If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI. # If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
url = cond( # type: ignore url = cond(
is_data_url, is_data_url,
data.to(str), data.to(str),
"data:text/plain," + data.to_string(), # type: ignore "data:text/plain," + data.to_string(),
) )
elif isinstance(data, bytes): elif isinstance(data, bytes):
# Caller provided bytes, so base64 encode it as a data: URI. # Caller provided bytes, so base64 encode it as a data: URI.
@ -1075,7 +1075,8 @@ def download(
) )
def _callback_arg_spec(eval_result): # This function seems unused. Check if we still need it. If not, remove in 0.7.0
def _callback_arg_spec(eval_result: Any):
"""ArgSpec for call_script callback function. """ArgSpec for call_script callback function.
Args: Args:
@ -1180,7 +1181,7 @@ def run_script(
return call_function(ArgsFunctionOperation.create((), javascript_code), callback) return call_function(ArgsFunctionOperation.create((), javascript_code), callback)
def get_event(state, event): def get_event(state: BaseState, event: str):
"""Get the event from the given state. """Get the event from the given state.
Args: Args:
@ -1193,7 +1194,7 @@ def get_event(state, event):
return f"{state.get_name()}.{event}" return f"{state.get_name()}.{event}"
def get_hydrate_event(state) -> str: def get_hydrate_event(state: BaseState) -> str:
"""Get the name of the hydrate event for the state. """Get the name of the hydrate event for the state.
Args: Args:
@ -1230,7 +1231,7 @@ def call_event_handler(
#noqa: DAR401 #noqa: DAR401
""" """
event_spec_args = parse_args_spec(event_spec) # type: ignore event_spec_args = parse_args_spec(event_spec)
if isinstance(event_callback, EventSpec): if isinstance(event_callback, EventSpec):
check_fn_match_arg_spec( check_fn_match_arg_spec(
@ -1340,7 +1341,7 @@ def call_event_handler(
if delayed_exceptions: if delayed_exceptions:
raise delayed_exceptions[0] raise delayed_exceptions[0]
return event_callback(*event_spec_args) # type: ignore return event_callback(*event_spec_args)
def unwrap_var_annotation(annotation: GenericType): def unwrap_var_annotation(annotation: GenericType):
@ -1574,7 +1575,7 @@ def fix_events(
if not isinstance(e, EventSpec): if not isinstance(e, EventSpec):
raise ValueError(f"Unexpected event type, {type(e)}.") raise ValueError(f"Unexpected event type, {type(e)}.")
name = format.format_event_handler(e.handler) name = format.format_event_handler(e.handler)
payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore payload = {k._js_expr: v._decode() for k, v in e.args}
# Filter router_data to reduce payload size # Filter router_data to reduce payload size
event_router_data = { event_router_data = {
@ -1623,7 +1624,7 @@ class EventVar(ObjectVar, python_types=EventSpec):
class LiteralEventVar(VarOperationCall, LiteralVar, EventVar): class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
"""A literal event var.""" """A literal event var."""
_var_value: EventSpec = dataclasses.field(default=None) # type: ignore _var_value: EventSpec = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
def __hash__(self) -> int: def __hash__(self) -> int:
"""Get the hash of the var. """Get the hash of the var.
@ -1687,7 +1688,7 @@ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar): class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar):
"""A literal event chain var.""" """A literal event chain var."""
_var_value: EventChain = dataclasses.field(default=None) # type: ignore _var_value: EventChain = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
def __hash__(self) -> int: def __hash__(self) -> int:
"""Get the hash of the var. """Get the hash of the var.
@ -1717,7 +1718,7 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
if isinstance(value.args_spec, Sequence) if isinstance(value.args_spec, Sequence)
else value.args_spec else value.args_spec
) )
sig = inspect.signature(arg_spec) # type: ignore sig = inspect.signature(arg_spec) # pyright: ignore [reportArgumentType]
if sig.parameters: if sig.parameters:
arg_def = tuple((f"_{p}" for p in sig.parameters)) arg_def = tuple((f"_{p}" for p in sig.parameters))
arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def]) arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
@ -1819,7 +1820,7 @@ class EventCallback(Generic[P, T]):
value4: V4 | Var[V4], value4: V4 | Var[V4],
) -> EventCallback[Q, T]: ... ) -> EventCallback[Q, T]: ...
def __call__(self, *values) -> EventCallback: # type: ignore def __call__(self, *values) -> EventCallback: # pyright: ignore [reportInconsistentOverload]
"""Call the function with the values. """Call the function with the values.
Args: Args:
@ -1828,17 +1829,17 @@ class EventCallback(Generic[P, T]):
Returns: Returns:
The function with the values. The function with the values.
""" """
return self.func(*values) # type: ignore return self.func(*values) # pyright: ignore [reportCallIssue, reportReturnType]
@overload @overload
def __get__( def __get__(
self: EventCallback[P, T], instance: None, owner self: EventCallback[P, T], instance: None, owner: Any
) -> EventCallback[P, T]: ... ) -> EventCallback[P, T]: ...
@overload @overload
def __get__(self, instance, owner) -> Callable[P, T]: ... def __get__(self, instance: Any, owner: Any) -> Callable[P, T]: ...
def __get__(self, instance, owner) -> Callable: # type: ignore def __get__(self, instance: Any, owner: Any) -> Callable:
"""Get the function with the instance bound to it. """Get the function with the instance bound to it.
Args: Args:
@ -1849,9 +1850,9 @@ class EventCallback(Generic[P, T]):
The function with the instance bound to it The function with the instance bound to it
""" """
if instance is None: if instance is None:
return self.func # type: ignore return self.func
return partial(self.func, instance) # type: ignore return partial(self.func, instance)
G = ParamSpec("G") G = ParamSpec("G")
@ -1902,7 +1903,7 @@ class EventNamespace(types.SimpleNamespace):
@staticmethod @staticmethod
def __call__( def __call__(
func: None = None, *, background: bool | None = None func: None = None, *, background: bool | None = None
) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ... ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ... # pyright: ignore [reportInvalidTypeVarUse]
@overload @overload
@staticmethod @staticmethod
@ -1945,7 +1946,7 @@ class EventNamespace(types.SimpleNamespace):
"Background task must be async function or generator." "Background task must be async function or generator."
) )
setattr(func, BACKGROUND_TASK_MARKER, True) setattr(func, BACKGROUND_TASK_MARKER, True)
return func # type: ignore return func # pyright: ignore [reportReturnType]
if func is not None: if func is not None:
return wrapper(func) return wrapper(func)

View File

@ -201,9 +201,7 @@ class ClientStateVar(Var):
) )
.to(self._var_type) .to(self._var_type)
._replace( ._replace(
merge_var_data=VarData( # type: ignore merge_var_data=VarData(imports=_refs_import if self._global_ref else {})
imports=_refs_import if self._global_ref else {}
)
) )
) )

View File

@ -11,7 +11,7 @@ def _compose_react_imports(tags: list[str]) -> dict[str, list[ImportVar]]:
return {"react": [ImportVar(tag=tag) for tag in tags]} return {"react": [ImportVar(tag=tag) for tag in tags]}
def const(name, value) -> Var: def const(name: str | list[str], value: str | Var) -> Var:
"""Create a constant Var. """Create a constant Var.
Args: Args:
@ -26,7 +26,7 @@ def const(name, value) -> Var:
return Var(_js_expr=f"const {name} = {value}") return Var(_js_expr=f"const {name} = {value}")
def useCallback(func, deps) -> Var: # noqa: N802 def useCallback(func: str, deps: list) -> Var: # noqa: N802
"""Create a useCallback hook with a function and dependencies. """Create a useCallback hook with a function and dependencies.
Args: Args:
@ -42,7 +42,7 @@ def useCallback(func, deps) -> Var: # noqa: N802
) )
def useContext(context) -> Var: # noqa: N802 def useContext(context: str) -> Var: # noqa: N802
"""Create a useContext hook with a context. """Create a useContext hook with a context.
Args: Args:
@ -57,7 +57,7 @@ def useContext(context) -> Var: # noqa: N802
) )
def useRef(default) -> Var: # noqa: N802 def useRef(default: str) -> Var: # noqa: N802
"""Create a useRef hook with a default value. """Create a useRef hook with a default value.
Args: Args:
@ -72,7 +72,7 @@ def useRef(default) -> Var: # noqa: N802
) )
def useState(var_name, default=None) -> Var: # noqa: N802 def useState(var_name: str, default: str | None = None) -> Var: # noqa: N802
"""Create a useState hook with a variable name and setter name. """Create a useState hook with a variable name and setter name.
Args: Args:

View File

@ -12,6 +12,7 @@ from reflex.components.radix.themes.components.icon_button import IconButton
from reflex.components.radix.themes.layout.box import Box from reflex.components.radix.themes.layout.box import Box
from reflex.components.radix.themes.layout.container import Container from reflex.components.radix.themes.layout.container import Container
from reflex.components.radix.themes.layout.stack import HStack from reflex.components.radix.themes.layout.stack import HStack
from reflex.constants.compiler import MemoizationMode
from reflex.event import run_script from reflex.event import run_script
from reflex.experimental import hooks from reflex.experimental import hooks
from reflex.state import ComponentState from reflex.state import ComponentState
@ -44,10 +45,10 @@ class Sidebar(Box, MemoizationLeaf):
Returns: Returns:
The style of the component. The style of the component.
""" """
sidebar: Component = self.children[-2] # type: ignore sidebar: Component = self.children[-2] # pyright: ignore [reportAssignmentType]
spacer: Component = self.children[-1] # type: ignore spacer: Component = self.children[-1] # pyright: ignore [reportAssignmentType]
open = ( open = (
self.State.open # type: ignore self.State.open # pyright: ignore [reportAttributeAccessIssue]
if self.State if self.State
else Var(_js_expr="open") else Var(_js_expr="open")
) )
@ -146,6 +147,8 @@ sidebar_trigger_style = {
class SidebarTrigger(Fragment): class SidebarTrigger(Fragment):
"""A component that renders the sidebar trigger.""" """A component that renders the sidebar trigger."""
_memoization_mode = MemoizationMode(recursive=False)
@classmethod @classmethod
def create(cls, sidebar: Component, **props): def create(cls, sidebar: Component, **props):
"""Create the sidebar trigger component. """Create the sidebar trigger component.
@ -159,11 +162,11 @@ class SidebarTrigger(Fragment):
""" """
trigger_props = {**props, **sidebar_trigger_style} trigger_props = {**props, **sidebar_trigger_style}
inner_sidebar: Component = sidebar.children[0] # type: ignore inner_sidebar: Component = sidebar.children[0] # pyright: ignore [reportAssignmentType]
sidebar_width = inner_sidebar.style.get("width") sidebar_width = inner_sidebar.style.get("width")
if sidebar.State: if sidebar.State:
open, toggle = sidebar.State.open, sidebar.State.toggle # type: ignore open, toggle = sidebar.State.open, sidebar.State.toggle # pyright: ignore [reportAttributeAccessIssue]
else: else:
open, toggle = ( open, toggle = (
Var(_js_expr="open"), Var(_js_expr="open"),

View File

@ -1,16 +1,16 @@
"""Miscellaneous functions for the experimental package.""" """Miscellaneous functions for the experimental package."""
import asyncio import asyncio
from typing import Any from typing import Any, Callable
async def run_in_thread(func) -> Any: async def run_in_thread(func: Callable) -> Any:
"""Run a function in a separate thread. """Run a function in a separate thread.
To not block the UI event queue, run_in_thread must be inside inside a rx.event(background=True) decorated method. To not block the UI event queue, run_in_thread must be inside inside a rx.event(background=True) decorated method.
Args: Args:
func (callable): The non-async function to run. func: The non-async function to run.
Raises: Raises:
ValueError: If the function is an async function. ValueError: If the function is an async function.

View File

@ -6,7 +6,7 @@ from reflex.istate.proxy import ReadOnlyStateProxy
from reflex.state import _split_substate_key, _substate_key, get_state_manager from reflex.state import _split_substate_key, _substate_key, get_state_manager
async def get_state(token, state_cls: Any | None = None) -> ReadOnlyStateProxy: async def get_state(token: str, state_cls: Any | None = None) -> ReadOnlyStateProxy:
"""Get the instance of a state for a token. """Get the instance of a state for a token.
Args: Args:

View File

@ -18,6 +18,7 @@ import sqlalchemy
import sqlalchemy.exc import sqlalchemy.exc
import sqlalchemy.ext.asyncio import sqlalchemy.ext.asyncio
import sqlalchemy.orm import sqlalchemy.orm
from alembic.runtime.migration import MigrationContext
from reflex.base import Base from reflex.base import Base
from reflex.config import environment, get_config from reflex.config import environment, get_config
@ -242,7 +243,7 @@ class ModelRegistry:
return metadata return metadata
class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssues] class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssues,reportIncompatibleVariableOverride]
"""Base class to define a table in the database.""" """Base class to define a table in the database."""
# The primary key for the table. # The primary key for the table.
@ -261,7 +262,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
super().__init_subclass__() super().__init_subclass__()
@classmethod @classmethod
def _dict_recursive(cls, value): def _dict_recursive(cls, value: Any):
"""Recursively serialize the relationship object(s). """Recursively serialize the relationship object(s).
Args: Args:
@ -393,7 +394,11 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
writer = alembic.autogenerate.rewriter.Rewriter() writer = alembic.autogenerate.rewriter.Rewriter()
@writer.rewrites(alembic.operations.ops.AddColumnOp) @writer.rewrites(alembic.operations.ops.AddColumnOp)
def render_add_column_with_server_default(context, revision, op): def render_add_column_with_server_default(
context: MigrationContext,
revision: str | None,
op: Any,
):
# Carry the sqlmodel default as server_default so that newly added # Carry the sqlmodel default as server_default so that newly added
# columns get the desired default value in existing rows. # columns get the desired default value in existing rows.
if op.column.default is not None and op.column.server_default is None: if op.column.default is not None and op.column.server_default is None:
@ -402,7 +407,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
) )
return op return op
def run_autogenerate(rev, context): def run_autogenerate(rev: str, context: MigrationContext):
revision_context.run_autogenerate(rev, context) revision_context.run_autogenerate(rev, context)
return [] return []
@ -415,7 +420,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
connection=connection, connection=connection,
target_metadata=ModelRegistry.get_metadata(), target_metadata=ModelRegistry.get_metadata(),
render_item=cls._alembic_render_item, render_item=cls._alembic_render_item,
process_revision_directives=writer, # type: ignore process_revision_directives=writer,
compare_type=False, compare_type=False,
render_as_batch=True, # for sqlite compatibility render_as_batch=True, # for sqlite compatibility
) )
@ -444,7 +449,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
""" """
config, script_directory = cls._alembic_config() config, script_directory = cls._alembic_config()
def run_upgrade(rev, context): def run_upgrade(rev: str, context: MigrationContext):
return script_directory._upgrade_revs(to_rev, rev) return script_directory._upgrade_revs(to_rev, rev)
with alembic.runtime.environment.EnvironmentContext( with alembic.runtime.environment.EnvironmentContext(

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from collections import defaultdict from collections import defaultdict
from typing import Any, Dict, List from typing import Any, Callable, Dict, List
from reflex.config import get_config from reflex.config import get_config
from reflex.event import BASE_STATE, EventType from reflex.event import BASE_STATE, EventType
@ -42,7 +42,7 @@ def page(
The decorated function. The decorated function.
""" """
def decorator(render_fn): def decorator(render_fn: Callable):
kwargs = {} kwargs = {}
if route: if route:
kwargs["route"] = route kwargs["route"] = route
@ -66,7 +66,7 @@ def page(
return decorator return decorator
def get_decorated_pages(omit_implicit_routes=True) -> list[dict[str, Any]]: def get_decorated_pages(omit_implicit_routes: bool = True) -> list[dict[str, Any]]:
"""Get the decorated pages. """Get the decorated pages.
Args: Args:

View File

@ -17,7 +17,7 @@ from reflex.state import reset_disk_state_manager
from reflex.utils import console, telemetry from reflex.utils import console, telemetry
# Disable typer+rich integration for help panels # Disable typer+rich integration for help panels
typer.core.rich = None # type: ignore typer.core.rich = None # pyright: ignore [reportPrivateImportUsage]
# Create the app. # Create the app.
try: try:
@ -127,8 +127,8 @@ def _run(
env: constants.Env = constants.Env.DEV, env: constants.Env = constants.Env.DEV,
frontend: bool = True, frontend: bool = True,
backend: bool = True, backend: bool = True,
frontend_port: str = str(config.frontend_port), frontend_port: int = config.frontend_port,
backend_port: str = str(config.backend_port), backend_port: int = config.backend_port,
backend_host: str = config.backend_host, backend_host: str = config.backend_host,
loglevel: constants.LogLevel = config.loglevel, loglevel: constants.LogLevel = config.loglevel,
): ):
@ -162,18 +162,22 @@ def _run(
# Find the next available open port if applicable. # Find the next available open port if applicable.
if frontend: if frontend:
frontend_port = processes.handle_port( frontend_port = processes.handle_port(
"frontend", frontend_port, str(constants.DefaultPorts.FRONTEND_PORT) "frontend",
frontend_port,
constants.DefaultPorts.FRONTEND_PORT,
) )
if backend: if backend:
backend_port = processes.handle_port( backend_port = processes.handle_port(
"backend", backend_port, str(constants.DefaultPorts.BACKEND_PORT) "backend",
backend_port,
constants.DefaultPorts.BACKEND_PORT,
) )
# Apply the new ports to the config. # Apply the new ports to the config.
if frontend_port != str(config.frontend_port): if frontend_port != config.frontend_port:
config._set_persistent(frontend_port=frontend_port) config._set_persistent(frontend_port=frontend_port)
if backend_port != str(config.backend_port): if backend_port != config.backend_port:
config._set_persistent(backend_port=backend_port) config._set_persistent(backend_port=backend_port)
# Reload the config to make sure the env vars are persistent. # Reload the config to make sure the env vars are persistent.
@ -273,10 +277,10 @@ def run(
help="Execute only backend.", help="Execute only backend.",
envvar=environment.REFLEX_BACKEND_ONLY.name, envvar=environment.REFLEX_BACKEND_ONLY.name,
), ),
frontend_port: str = typer.Option( frontend_port: int = typer.Option(
config.frontend_port, help="Specify a different frontend port." config.frontend_port, help="Specify a different frontend port."
), ),
backend_port: str = typer.Option( backend_port: int = typer.Option(
config.backend_port, help="Specify a different backend port." config.backend_port, help="Specify a different backend port."
), ),
backend_host: str = typer.Option( backend_host: str = typer.Option(
@ -375,7 +379,7 @@ def logout(
check_version() check_version()
logout(loglevel) # type: ignore logout(loglevel) # pyright: ignore [reportArgumentType]
db_cli = typer.Typer() db_cli = typer.Typer()

View File

@ -103,7 +103,7 @@ def catchall_prefix(route: str) -> str:
return route.replace(pattern, "") if pattern else "" return route.replace(pattern, "") if pattern else ""
def replace_brackets_with_keywords(input_string): def replace_brackets_with_keywords(input_string: str) -> str:
"""Replace brackets and everything inside it in a string with a keyword. """Replace brackets and everything inside it in a string with a keyword.
Args: Args:

View File

@ -31,6 +31,7 @@ from typing import (
Optional, Optional,
Sequence, Sequence,
Set, Set,
SupportsIndex,
Tuple, Tuple,
Type, Type,
TypeVar, TypeVar,
@ -587,7 +588,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
if cls._item_is_event_handler(name, fn) if cls._item_is_event_handler(name, fn)
} }
for mixin in cls._mixins(): for mixin in cls._mixins(): # pyright: ignore [reportAssignmentType]
for name, value in mixin.__dict__.items(): for name, value in mixin.__dict__.items():
if name in cls.inherited_vars: if name in cls.inherited_vars:
continue continue
@ -599,7 +600,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
cls.computed_vars[newcv._js_expr] = newcv cls.computed_vars[newcv._js_expr] = newcv
cls.vars[newcv._js_expr] = newcv cls.vars[newcv._js_expr] = newcv
continue continue
if types.is_backend_base_variable(name, mixin): if types.is_backend_base_variable(name, mixin): # pyright: ignore [reportArgumentType]
cls.backend_vars[name] = copy.deepcopy(value) cls.backend_vars[name] = copy.deepcopy(value)
continue continue
if events.get(name) is not None: if events.get(name) is not None:
@ -899,7 +900,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
] ]
if len(parent_states) >= 2: if len(parent_states) >= 2:
raise ValueError(f"Only one parent state is allowed {parent_states}.") raise ValueError(f"Only one parent state is allowed {parent_states}.")
return parent_states[0] if len(parent_states) == 1 else None # type: ignore return parent_states[0] if len(parent_states) == 1 else None
@classmethod @classmethod
def get_substates(cls) -> set[Type[BaseState]]: def get_substates(cls) -> set[Type[BaseState]]:
@ -1058,7 +1059,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
setattr(cls, prop._var_field_name, prop) setattr(cls, prop._var_field_name, prop)
@classmethod @classmethod
def _create_event_handler(cls, fn): def _create_event_handler(cls, fn: Any):
"""Create an event handler for the given function. """Create an event handler for the given function.
Args: Args:
@ -1176,14 +1177,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
cls._check_overwritten_dynamic_args(list(args.keys())) cls._check_overwritten_dynamic_args(list(args.keys()))
def argsingle_factory(param): def argsingle_factory(param: str):
def inner_func(self) -> str: def inner_func(self: BaseState) -> str:
return self.router.page.params.get(param, "") return self.router.page.params.get(param, "")
return inner_func return inner_func
def arglist_factory(param): def arglist_factory(param: str):
def inner_func(self) -> List[str]: def inner_func(self: BaseState) -> List[str]:
return self.router.page.params.get(param, []) return self.router.page.params.get(param, [])
return inner_func return inner_func
@ -1268,8 +1269,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
fn = _no_chain_background_task(type(self), name, handler.fn) fn = _no_chain_background_task(type(self), name, handler.fn)
else: else:
fn = functools.partial(handler.fn, self) fn = functools.partial(handler.fn, self)
fn.__module__ = handler.fn.__module__ # type: ignore fn.__module__ = handler.fn.__module__
fn.__qualname__ = handler.fn.__qualname__ # type: ignore fn.__qualname__ = handler.fn.__qualname__
return fn return fn
backend_vars = super().__getattribute__("_backend_vars") backend_vars = super().__getattribute__("_backend_vars")
@ -1434,6 +1435,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
for part1, part2 in zip( for part1, part2 in zip(
cls.get_full_name().split("."), cls.get_full_name().split("."),
other.get_full_name().split("."), other.get_full_name().split("."),
strict=True,
): ):
if part1 != part2: if part1 != part2:
break break
@ -1633,7 +1635,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
""" """
# Oopsie case: you didn't give me a Var... so get what you give. # Oopsie case: you didn't give me a Var... so get what you give.
if not isinstance(var, Var): if not isinstance(var, Var):
return var # type: ignore return var
# Fast case: this is a literal var and the value is known. # Fast case: this is a literal var and the value is known.
if hasattr(var, "_var_value"): if hasattr(var, "_var_value"):
@ -2452,7 +2454,7 @@ class OnLoadInternalState(State):
self.router.session.client_token, self.router.session.client_token,
router_data=self.router_data, router_data=self.router_data,
), ),
State.set_is_hydrated(True), # type: ignore State.set_is_hydrated(True), # pyright: ignore [reportAttributeAccessIssue]
] ]
@ -2593,7 +2595,9 @@ class StateProxy(wrapt.ObjectProxy):
""" """
def __init__( def __init__(
self, state_instance, parent_state_proxy: Optional["StateProxy"] = None self,
state_instance: BaseState,
parent_state_proxy: Optional["StateProxy"] = None,
): ):
"""Create a proxy for a state instance. """Create a proxy for a state instance.
@ -2736,7 +2740,7 @@ class StateProxy(wrapt.ObjectProxy):
# ensure mutations to these containers are blocked unless proxy is _mutable # ensure mutations to these containers are blocked unless proxy is _mutable
return ImmutableMutableProxy( return ImmutableMutableProxy(
wrapped=value.__wrapped__, wrapped=value.__wrapped__,
state=self, # type: ignore state=self,
field_name=value._self_field_name, field_name=value._self_field_name,
) )
if isinstance(value, functools.partial) and value.args[0] is self.__wrapped__: if isinstance(value, functools.partial) and value.args[0] is self.__wrapped__:
@ -2749,7 +2753,7 @@ class StateProxy(wrapt.ObjectProxy):
) )
if isinstance(value, MethodType) and value.__self__ is self.__wrapped__: if isinstance(value, MethodType) and value.__self__ is self.__wrapped__:
# Rebind methods to the proxy instance # Rebind methods to the proxy instance
value = type(value)(value.__func__, self) # type: ignore value = type(value)(value.__func__, self)
return value return value
def __setattr__(self, name: str, value: Any) -> None: def __setattr__(self, name: str, value: Any) -> None:
@ -2949,7 +2953,7 @@ class StateManagerMemory(StateManager):
# The dict of mutexes for each client # The dict of mutexes for each client
_states_locks: Dict[str, asyncio.Lock] = pydantic.PrivateAttr({}) _states_locks: Dict[str, asyncio.Lock] = pydantic.PrivateAttr({})
class Config: class Config: # pyright: ignore [reportIncompatibleVariableOverride]
"""The Pydantic config.""" """The Pydantic config."""
fields = { fields = {
@ -3067,7 +3071,7 @@ class StateManagerDisk(StateManager):
# The token expiration time (s). # The token expiration time (s).
token_expiration: int = pydantic.Field(default_factory=_default_token_expiration) token_expiration: int = pydantic.Field(default_factory=_default_token_expiration)
class Config: class Config: # pyright: ignore [reportIncompatibleVariableOverride]
"""The Pydantic config.""" """The Pydantic config."""
fields = { fields = {
@ -3539,7 +3543,9 @@ class StateManagerRedis(StateManager):
@validator("lock_warning_threshold") @validator("lock_warning_threshold")
@classmethod @classmethod
def validate_lock_warning_threshold(cls, lock_warning_threshold: int, values): def validate_lock_warning_threshold(
cls, lock_warning_threshold: int, values: dict[str, int]
):
"""Validate the lock warning threshold. """Validate the lock warning threshold.
Args: Args:
@ -3775,9 +3781,9 @@ class MutableProxy(wrapt.ObjectProxy):
wrapper_cls_name, wrapper_cls_name,
(cls,), (cls,),
{ {
dataclasses._FIELDS: getattr( # pyright: ignore [reportGeneralTypeIssues] dataclasses._FIELDS: getattr( # pyright: ignore [reportAttributeAccessIssue]
wrapped_cls, wrapped_cls,
dataclasses._FIELDS, # pyright: ignore [reportGeneralTypeIssues] dataclasses._FIELDS, # pyright: ignore [reportAttributeAccessIssue]
), ),
}, },
) )
@ -3807,10 +3813,10 @@ class MutableProxy(wrapt.ObjectProxy):
def _mark_dirty( def _mark_dirty(
self, self,
wrapped=None, wrapped: Callable | None = None,
instance=None, instance: BaseState | None = None,
args=(), args: tuple = (),
kwargs=None, kwargs: dict | None = None,
) -> Any: ) -> Any:
"""Mark the state as dirty, then call a wrapped function. """Mark the state as dirty, then call a wrapped function.
@ -3884,7 +3890,9 @@ class MutableProxy(wrapt.ObjectProxy):
) )
return value return value
def _wrap_recursive_decorator(self, wrapped, instance, args, kwargs) -> Any: def _wrap_recursive_decorator(
self, wrapped: Callable, instance: BaseState, args: list, kwargs: dict
) -> Any:
"""Wrap a function that returns a possibly mutable value. """Wrap a function that returns a possibly mutable value.
Intended for use with `FunctionWrapper` from the `wrapt` library. Intended for use with `FunctionWrapper` from the `wrapt` library.
@ -3930,7 +3938,7 @@ class MutableProxy(wrapt.ObjectProxy):
): ):
# Wrap methods called on Base subclasses, which might do _anything_ # Wrap methods called on Base subclasses, which might do _anything_
return wrapt.FunctionWrapper( return wrapt.FunctionWrapper(
functools.partial(value.__func__, self), functools.partial(value.__func__, self), # pyright: ignore [reportFunctionMemberAccess]
self._wrap_recursive_decorator, self._wrap_recursive_decorator,
) )
@ -3943,7 +3951,7 @@ class MutableProxy(wrapt.ObjectProxy):
return value return value
def __getitem__(self, key) -> Any: def __getitem__(self, key: Any) -> Any:
"""Get the item on the proxied object and return a proxy if mutable. """Get the item on the proxied object and return a proxy if mutable.
Args: Args:
@ -3966,7 +3974,7 @@ class MutableProxy(wrapt.ObjectProxy):
# Recursively wrap mutable items retrieved through this proxy. # Recursively wrap mutable items retrieved through this proxy.
yield self._wrap_recursive(value) yield self._wrap_recursive(value)
def __delattr__(self, name): def __delattr__(self, name: str):
"""Delete the attribute on the proxied object and mark state dirty. """Delete the attribute on the proxied object and mark state dirty.
Args: Args:
@ -3974,7 +3982,7 @@ class MutableProxy(wrapt.ObjectProxy):
""" """
self._mark_dirty(super().__delattr__, args=(name,)) self._mark_dirty(super().__delattr__, args=(name,))
def __delitem__(self, key): def __delitem__(self, key: str):
"""Delete the item on the proxied object and mark state dirty. """Delete the item on the proxied object and mark state dirty.
Args: Args:
@ -3982,7 +3990,7 @@ class MutableProxy(wrapt.ObjectProxy):
""" """
self._mark_dirty(super().__delitem__, args=(key,)) self._mark_dirty(super().__delitem__, args=(key,))
def __setitem__(self, key, value): def __setitem__(self, key: str, value: Any):
"""Set the item on the proxied object and mark state dirty. """Set the item on the proxied object and mark state dirty.
Args: Args:
@ -3991,7 +3999,7 @@ class MutableProxy(wrapt.ObjectProxy):
""" """
self._mark_dirty(super().__setitem__, args=(key, value)) self._mark_dirty(super().__setitem__, args=(key, value))
def __setattr__(self, name, value): def __setattr__(self, name: str, value: Any):
"""Set the attribute on the proxied object and mark state dirty. """Set the attribute on the proxied object and mark state dirty.
If the attribute starts with "_self_", then the state is NOT marked If the attribute starts with "_self_", then the state is NOT marked
@ -4015,7 +4023,7 @@ class MutableProxy(wrapt.ObjectProxy):
""" """
return copy.copy(self.__wrapped__) return copy.copy(self.__wrapped__)
def __deepcopy__(self, memo=None) -> Any: def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Any:
"""Return a deepcopy of the proxy. """Return a deepcopy of the proxy.
Args: Args:
@ -4026,7 +4034,7 @@ class MutableProxy(wrapt.ObjectProxy):
""" """
return copy.deepcopy(self.__wrapped__, memo=memo) return copy.deepcopy(self.__wrapped__, memo=memo)
def __reduce_ex__(self, protocol_version): def __reduce_ex__(self, protocol_version: SupportsIndex):
"""Get the state for redis serialization. """Get the state for redis serialization.
This method is called by cloudpickle to serialize the object. This method is called by cloudpickle to serialize the object.
@ -4090,10 +4098,10 @@ class ImmutableMutableProxy(MutableProxy):
def _mark_dirty( def _mark_dirty(
self, self,
wrapped=None, wrapped: Callable | None = None,
instance=None, instance: BaseState | None = None,
args=(), args: tuple = (),
kwargs=None, kwargs: dict | None = None,
) -> Any: ) -> Any:
"""Raise an exception when an attempt is made to modify the object. """Raise an exception when an attempt is made to modify the object.

View File

@ -78,7 +78,7 @@ def set_color_mode(
_var_data=VarData.merge( _var_data=VarData.merge(
base_setter._get_all_var_data(), new_color_mode._get_all_var_data() base_setter._get_all_var_data(), new_color_mode._get_all_var_data()
), ),
).to(FunctionVar, EventChain) # type: ignore ).to(FunctionVar, EventChain)
# Var resolves to the current color mode for the app ("light", "dark" or "system") # Var resolves to the current color mode for the app ("light", "dark" or "system")
@ -182,7 +182,9 @@ def convert(
var_data = None # Track import/hook data from any Vars in the style dict. var_data = None # Track import/hook data from any Vars in the style dict.
out = {} out = {}
def update_out_dict(return_value, keys_to_update): def update_out_dict(
return_value: Var | dict | list | str, keys_to_update: tuple[str, ...]
):
for k in keys_to_update: for k in keys_to_update:
out[k] = return_value out[k] = return_value
@ -292,6 +294,26 @@ class Style(dict):
) )
super().__setitem__(key, value) super().__setitem__(key, value)
def __or__(self, other: Style | dict) -> Style:
"""Combine two styles.
Args:
other: The other style to combine.
Returns:
The combined style.
"""
other_var_data = None
if not isinstance(other, Style):
other_dict, other_var_data = convert(other)
else:
other_dict, other_var_data = other, other._var_data
new_style = Style(super().__or__(other_dict))
if self._var_data or other_var_data:
new_style._var_data = VarData.merge(self._var_data, other_var_data)
return new_style
def _format_emotion_style_pseudo_selector(key: str) -> str: def _format_emotion_style_pseudo_selector(key: str) -> str:
"""Format a pseudo selector for emotion CSS-in-JS. """Format a pseudo selector for emotion CSS-in-JS.

View File

@ -80,7 +80,7 @@ T = TypeVar("T")
TimeoutType = Optional[Union[int, float]] TimeoutType = Optional[Union[int, float]]
if platform.system() == "Windows": if platform.system() == "Windows":
FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue]
FRONTEND_POPEN_ARGS["shell"] = True FRONTEND_POPEN_ARGS["shell"] = True
else: else:
FRONTEND_POPEN_ARGS["start_new_session"] = True FRONTEND_POPEN_ARGS["start_new_session"] = True
@ -90,7 +90,7 @@ else:
class chdir(contextlib.AbstractContextManager): # noqa: N801 class chdir(contextlib.AbstractContextManager): # noqa: N801
"""Non thread-safe context manager to change the current working directory.""" """Non thread-safe context manager to change the current working directory."""
def __init__(self, path): def __init__(self, path: str | Path):
"""Prepare contextmanager. """Prepare contextmanager.
Args: Args:
@ -258,7 +258,7 @@ class AppHarness:
if self.app_source is not None: if self.app_source is not None:
app_globals = self._get_globals_from_signature(self.app_source) app_globals = self._get_globals_from_signature(self.app_source)
if isinstance(self.app_source, functools.partial): if isinstance(self.app_source, functools.partial):
self.app_source = self.app_source.func # type: ignore self.app_source = self.app_source.func
# get the source from a function or module object # get the source from a function or module object
source_code = "\n".join( source_code = "\n".join(
[ [
@ -294,11 +294,15 @@ class AppHarness:
if p not in before_decorated_pages if p not in before_decorated_pages
] ]
self.app_instance = self.app_module.app self.app_instance = self.app_module.app
if isinstance(self.app_instance._state_manager, StateManagerRedis): if self.app_instance and isinstance(
self.app_instance._state_manager, StateManagerRedis
):
# Create our own redis connection for testing. # Create our own redis connection for testing.
self.state_manager = StateManagerRedis.create(self.app_instance._state) self.state_manager = StateManagerRedis.create(self.app_instance._state) # pyright: ignore [reportArgumentType]
else: else:
self.state_manager = self.app_instance._state_manager self.state_manager = (
self.app_instance._state_manager if self.app_instance else None
)
def _reload_state_module(self): def _reload_state_module(self):
"""Reload the rx.State module to avoid conflict when reloading.""" """Reload the rx.State module to avoid conflict when reloading."""
@ -323,7 +327,7 @@ class AppHarness:
return _shutdown_redis return _shutdown_redis
def _start_backend(self, port=0): def _start_backend(self, port: int = 0):
if self.app_instance is None or self.app_instance.api is None: if self.app_instance is None or self.app_instance.api is None:
raise RuntimeError("App was not initialized.") raise RuntimeError("App was not initialized.")
self.backend = uvicorn.Server( self.backend = uvicorn.Server(
@ -426,7 +430,7 @@ class AppHarness:
return self return self
@staticmethod @staticmethod
def get_app_global_source(key, value): def get_app_global_source(key: str, value: Any):
"""Get the source code of a global object. """Get the source code of a global object.
If value is a function or class we render the actual If value is a function or class we render the actual
source of value otherwise we assign value to key. source of value otherwise we assign value to key.
@ -621,23 +625,23 @@ class AppHarness:
want_headless = True want_headless = True
if driver_clz is None: if driver_clz is None:
requested_driver = environment.APP_HARNESS_DRIVER.get() requested_driver = environment.APP_HARNESS_DRIVER.get()
driver_clz = getattr(webdriver, requested_driver) driver_clz = getattr(webdriver, requested_driver) # pyright: ignore [reportPossiblyUnboundVariable]
if driver_options is None: if driver_options is None:
driver_options = getattr(webdriver, f"{requested_driver}Options")() driver_options = getattr(webdriver, f"{requested_driver}Options")() # pyright: ignore [reportPossiblyUnboundVariable]
if driver_clz is webdriver.Chrome: if driver_clz is webdriver.Chrome: # pyright: ignore [reportPossiblyUnboundVariable]
if driver_options is None: if driver_options is None:
driver_options = webdriver.ChromeOptions() driver_options = webdriver.ChromeOptions() # pyright: ignore [reportPossiblyUnboundVariable]
driver_options.add_argument("--class=AppHarness") driver_options.add_argument("--class=AppHarness")
if want_headless: if want_headless:
driver_options.add_argument("--headless=new") driver_options.add_argument("--headless=new")
elif driver_clz is webdriver.Firefox: elif driver_clz is webdriver.Firefox: # pyright: ignore [reportPossiblyUnboundVariable]
if driver_options is None: if driver_options is None:
driver_options = webdriver.FirefoxOptions() driver_options = webdriver.FirefoxOptions() # pyright: ignore [reportPossiblyUnboundVariable]
if want_headless: if want_headless:
driver_options.add_argument("-headless") driver_options.add_argument("-headless")
elif driver_clz is webdriver.Edge: elif driver_clz is webdriver.Edge: # pyright: ignore [reportPossiblyUnboundVariable]
if driver_options is None: if driver_options is None:
driver_options = webdriver.EdgeOptions() driver_options = webdriver.EdgeOptions() # pyright: ignore [reportPossiblyUnboundVariable]
if want_headless: if want_headless:
driver_options.add_argument("headless") driver_options.add_argument("headless")
if driver_options is None: if driver_options is None:
@ -653,7 +657,7 @@ class AppHarness:
driver_options.set_capability(key, value) driver_options.set_capability(key, value)
if driver_kwargs is None: if driver_kwargs is None:
driver_kwargs = {} driver_kwargs = {}
driver = driver_clz(options=driver_options, **driver_kwargs) # type: ignore driver = driver_clz(options=driver_options, **driver_kwargs) # pyright: ignore [reportOptionalCall, reportArgumentType]
driver.get(self.frontend_url) driver.get(self.frontend_url)
self._frontends.append(driver) self._frontends.append(driver)
return driver return driver
@ -885,8 +889,8 @@ class Subdir404TCPServer(socketserver.TCPServer):
request, request,
client_address, client_address,
self, self,
directory=str(self.root), # type: ignore directory=str(self.root), # pyright: ignore [reportCallIssue]
error_page_map=self.error_page_map, # type: ignore error_page_map=self.error_page_map, # pyright: ignore [reportCallIssue]
) )

View File

@ -27,7 +27,7 @@ def set_env_json():
) )
def generate_sitemap_config(deploy_url: str, export=False): def generate_sitemap_config(deploy_url: str, export: bool = False):
"""Generate the sitemap config file. """Generate the sitemap config file.
Args: Args:

View File

@ -2,6 +2,7 @@
import contextlib import contextlib
import sys import sys
from typing import Any
async def windows_hot_reload_lifespan_hack(): async def windows_hot_reload_lifespan_hack():
@ -50,11 +51,11 @@ def pydantic_v1_patch():
] ]
originals = {module: sys.modules.get(module) for module in patched_modules} originals = {module: sys.modules.get(module) for module in patched_modules}
try: try:
import pydantic.v1 # type: ignore import pydantic.v1
sys.modules["pydantic.fields"] = pydantic.v1.fields # type: ignore sys.modules["pydantic.fields"] = pydantic.v1.fields # pyright: ignore [reportAttributeAccessIssue]
sys.modules["pydantic.main"] = pydantic.v1.main # type: ignore sys.modules["pydantic.main"] = pydantic.v1.main # pyright: ignore [reportAttributeAccessIssue]
sys.modules["pydantic.errors"] = pydantic.v1.errors # type: ignore sys.modules["pydantic.errors"] = pydantic.v1.errors # pyright: ignore [reportAttributeAccessIssue]
sys.modules["pydantic"] = pydantic.v1 sys.modules["pydantic"] = pydantic.v1
yield yield
except (ImportError, AttributeError): except (ImportError, AttributeError):
@ -74,7 +75,7 @@ with pydantic_v1_patch():
import sqlmodel as sqlmodel import sqlmodel as sqlmodel
def sqlmodel_field_has_primary_key(field) -> bool: def sqlmodel_field_has_primary_key(field: Any) -> bool:
"""Determines if a field is a priamary. """Determines if a field is a priamary.
Args: Args:

View File

@ -196,7 +196,7 @@ def _get_first_non_framework_frame() -> FrameType | None:
exclude_modules = [click, rx, typer, typing_extensions] exclude_modules = [click, rx, typer, typing_extensions]
exclude_roots = [ exclude_roots = [
p.parent.resolve() p.parent.resolve()
if (p := Path(m.__file__)).name == "__init__.py" if (p := Path(m.__file__)).name == "__init__.py" # pyright: ignore [reportArgumentType]
else p.resolve() else p.resolve()
for m in exclude_modules for m in exclude_modules
] ]
@ -275,7 +275,7 @@ def ask(
choices: list[str] | None = None, choices: list[str] | None = None,
default: str | None = None, default: str | None = None,
show_choices: bool = True, show_choices: bool = True,
) -> str: ) -> str | None:
"""Takes a prompt question and optionally a list of choices """Takes a prompt question and optionally a list of choices
and returns the user input. and returns the user input.
@ -290,7 +290,7 @@ def ask(
""" """
return Prompt.ask( return Prompt.ask(
question, choices=choices, default=default, show_choices=show_choices question, choices=choices, default=default, show_choices=show_choices
) # type: ignore )
def progress(): def progress():

View File

@ -78,7 +78,7 @@ class VarAttributeError(ReflexError, AttributeError):
class UntypedComputedVarError(ReflexError, TypeError): class UntypedComputedVarError(ReflexError, TypeError):
"""Custom TypeError for untyped computed var errors.""" """Custom TypeError for untyped computed var errors."""
def __init__(self, var_name): def __init__(self, var_name: str):
"""Initialize the UntypedComputedVarError. """Initialize the UntypedComputedVarError.
Args: Args:
@ -90,7 +90,7 @@ class UntypedComputedVarError(ReflexError, TypeError):
class MissingAnnotationError(ReflexError, TypeError): class MissingAnnotationError(ReflexError, TypeError):
"""Custom TypeError for missing annotations.""" """Custom TypeError for missing annotations."""
def __init__(self, var_name): def __init__(self, var_name: str):
"""Initialize the MissingAnnotationError. """Initialize the MissingAnnotationError.
Args: Args:

View File

@ -71,7 +71,9 @@ def notify_backend():
# run_process_and_launch_url is assumed to be used # run_process_and_launch_url is assumed to be used
# only to launch the frontend # only to launch the frontend
# If this is not the case, might have to change the logic # If this is not the case, might have to change the logic
def run_process_and_launch_url(run_command: list[str], backend_present=True): def run_process_and_launch_url(
run_command: list[str | None], backend_present: bool = True
):
"""Run the process and launch the URL. """Run the process and launch the URL.
Args: Args:
@ -89,7 +91,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
if process is None: if process is None:
kwargs = {} kwargs = {}
if constants.IS_WINDOWS and backend_present: if constants.IS_WINDOWS and backend_present:
kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue]
process = processes.new_process( process = processes.new_process(
run_command, run_command,
cwd=get_web_dir(), cwd=get_web_dir(),
@ -134,7 +136,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
break # while True break # while True
def run_frontend(root: Path, port: str, backend_present=True): def run_frontend(root: Path, port: str, backend_present: bool = True):
"""Run the frontend. """Run the frontend.
Args: Args:
@ -151,12 +153,12 @@ def run_frontend(root: Path, port: str, backend_present=True):
console.rule("[bold green]App Running") console.rule("[bold green]App Running")
os.environ["PORT"] = str(get_config().frontend_port if port is None else port) os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
run_process_and_launch_url( run_process_and_launch_url(
[prerequisites.get_package_manager(), "run", "dev"], # type: ignore [prerequisites.get_package_manager(), "run", "dev"],
backend_present, backend_present,
) )
def run_frontend_prod(root: Path, port: str, backend_present=True): def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
"""Run the frontend. """Run the frontend.
Args: Args:
@ -173,7 +175,7 @@ def run_frontend_prod(root: Path, port: str, backend_present=True):
# Run the frontend in production mode. # Run the frontend in production mode.
console.rule("[bold green]App Running") console.rule("[bold green]App Running")
run_process_and_launch_url( run_process_and_launch_url(
[prerequisites.get_package_manager(), "run", "prod"], # type: ignore [prerequisites.get_package_manager(), "run", "prod"],
backend_present, backend_present,
) )
@ -265,7 +267,7 @@ def get_reload_dirs() -> list[Path]:
return reload_dirs return reload_dirs
def run_uvicorn_backend(host, port, loglevel: LogLevel): def run_uvicorn_backend(host: str, port: int, loglevel: LogLevel):
"""Run the backend in development mode using Uvicorn. """Run the backend in development mode using Uvicorn.
Args: Args:
@ -285,7 +287,7 @@ def run_uvicorn_backend(host, port, loglevel: LogLevel):
) )
def run_granian_backend(host, port, loglevel: LogLevel): def run_granian_backend(host: str, port: int, loglevel: LogLevel):
"""Run the backend in development mode using Granian. """Run the backend in development mode using Granian.
Args: Args:
@ -295,9 +297,11 @@ def run_granian_backend(host, port, loglevel: LogLevel):
""" """
console.debug("Using Granian for backend") console.debug("Using Granian for backend")
try: try:
from granian import Granian # type: ignore from granian import Granian # pyright: ignore [reportMissingImports]
from granian.constants import Interfaces # type: ignore from granian.constants import ( # pyright: ignore [reportMissingImports]
from granian.log import LogLevels # type: ignore Interfaces,
)
from granian.log import LogLevels # pyright: ignore [reportMissingImports]
Granian( Granian(
target=get_granian_target(), target=get_granian_target(),
@ -350,7 +354,7 @@ def run_backend_prod(
run_uvicorn_backend_prod(host, port, loglevel) run_uvicorn_backend_prod(host, port, loglevel)
def run_uvicorn_backend_prod(host, port, loglevel): def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
"""Run the backend in production mode using Uvicorn. """Run the backend in production mode using Uvicorn.
Args: Args:
@ -402,7 +406,7 @@ def run_uvicorn_backend_prod(host, port, loglevel):
) )
def run_granian_backend_prod(host, port, loglevel): def run_granian_backend_prod(host: str, port: int, loglevel: LogLevel):
"""Run the backend in production mode using Granian. """Run the backend in production mode using Granian.
Args: Args:
@ -413,7 +417,9 @@ def run_granian_backend_prod(host, port, loglevel):
from reflex.utils import processes from reflex.utils import processes
try: try:
from granian.constants import Interfaces # type: ignore from granian.constants import ( # pyright: ignore [reportMissingImports]
Interfaces,
)
command = [ command = [
"granian", "granian",
@ -467,22 +473,22 @@ def output_system_info():
system = platform.system() system = platform.system()
fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
if system != "Windows" or ( if system != "Windows" or (
system == "Windows" and prerequisites.is_windows_bun_supported() system == "Windows" and prerequisites.is_windows_bun_supported()
): ):
dependencies.extend( dependencies.extend(
[ [
f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]", fnm_info,
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {config.bun_path})]", f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
], ],
) )
else: else:
dependencies.append( dependencies.append(fnm_info)
f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
)
if system == "Linux": if system == "Linux":
import distro # type: ignore import distro
os_version = distro.name(pretty=True) os_version = distro.name(pretty=True)
else: else:
@ -494,11 +500,11 @@ def output_system_info():
console.debug(f"{dep}") console.debug(f"{dep}")
console.debug( console.debug(
f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}" # type: ignore f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}"
) )
console.debug( console.debug(
f"Using package executer at: {prerequisites.get_package_manager(on_failure_return_none=True)}" f"Using package executer at: {prerequisites.get_package_manager(on_failure_return_none=True)}"
) # type: ignore )
if system != "Windows": if system != "Windows":
console.debug(f"Unzip path: {path_ops.which('unzip')}") console.debug(f"Unzip path: {path_ops.which('unzip')}")

View File

@ -220,7 +220,7 @@ def _escape_js_string(string: str) -> str:
""" """
# TODO: we may need to re-vist this logic after new Var API is implemented. # TODO: we may need to re-vist this logic after new Var API is implemented.
def escape_outside_segments(segment): def escape_outside_segments(segment: str):
"""Escape backticks in segments outside of `${}`. """Escape backticks in segments outside of `${}`.
Args: Args:
@ -283,7 +283,7 @@ def format_var(var: Var) -> str:
return str(var) return str(var)
def format_route(route: str, format_case=True) -> str: def format_route(route: str, format_case: bool = True) -> str:
"""Format the given route. """Format the given route.
Args: Args:
@ -377,7 +377,7 @@ def format_prop(
# For dictionaries, convert any properties to strings. # For dictionaries, convert any properties to strings.
elif isinstance(prop, dict): elif isinstance(prop, dict):
prop = serializers.serialize_dict(prop) # type: ignore prop = serializers.serialize_dict(prop) # pyright: ignore [reportAttributeAccessIssue]
else: else:
# Dump the prop as JSON. # Dump the prop as JSON.
@ -533,14 +533,14 @@ def format_queue_events(
from reflex.vars import FunctionVar, Var from reflex.vars import FunctionVar, Var
if not events: if not events:
return Var("(() => null)").to(FunctionVar, EventChain) # type: ignore return Var("(() => null)").to(FunctionVar, EventChain)
# If no spec is provided, the function will take no arguments. # If no spec is provided, the function will take no arguments.
def _default_args_spec(): def _default_args_spec():
return [] return []
# Construct the arguments that the function accepts. # Construct the arguments that the function accepts.
sig = inspect.signature(args_spec or _default_args_spec) # type: ignore sig = inspect.signature(args_spec or _default_args_spec)
if sig.parameters: if sig.parameters:
arg_def = ",".join(f"_{p}" for p in sig.parameters) arg_def = ",".join(f"_{p}" for p in sig.parameters)
arg_def = f"({arg_def})" arg_def = f"({arg_def})"
@ -557,7 +557,7 @@ def format_queue_events(
if isinstance(spec, (EventHandler, EventSpec)): if isinstance(spec, (EventHandler, EventSpec)):
specs = [call_event_handler(spec, args_spec or _default_args_spec)] specs = [call_event_handler(spec, args_spec or _default_args_spec)]
elif isinstance(spec, type(lambda: None)): elif isinstance(spec, type(lambda: None)):
specs = call_event_fn(spec, args_spec or _default_args_spec) # type: ignore specs = call_event_fn(spec, args_spec or _default_args_spec) # pyright: ignore [reportAssignmentType, reportArgumentType]
if isinstance(specs, Var): if isinstance(specs, Var):
raise ValueError( raise ValueError(
f"Invalid event spec: {specs}. Expected a list of EventSpecs." f"Invalid event spec: {specs}. Expected a list of EventSpecs."
@ -569,7 +569,7 @@ def format_queue_events(
return Var( return Var(
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); " f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
f"processEvent({constants.CompileVars.SOCKET})}}", f"processEvent({constants.CompileVars.SOCKET})}}",
).to(FunctionVar, EventChain) # type: ignore ).to(FunctionVar, EventChain)
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]: def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:

View File

@ -90,7 +90,7 @@ def collapse_imports(
} }
@dataclasses.dataclass(order=True, frozen=True) @dataclasses.dataclass(frozen=True)
class ImportVar: class ImportVar:
"""An import var.""" """An import var."""
@ -122,7 +122,7 @@ class ImportVar:
""" """
if self.alias: if self.alias:
return ( return (
self.alias if self.is_default else " as ".join([self.tag, self.alias]) # type: ignore self.alias if self.is_default else " as ".join([self.tag, self.alias]) # pyright: ignore [reportCallIssue,reportArgumentType]
) )
else: else:
return self.tag or "" return self.tag or ""

View File

@ -1,11 +1,17 @@
"""Module to implement lazy loading in reflex.""" """Module to implement lazy loading in reflex."""
from __future__ import annotations
import copy import copy
import lazy_loader as lazy import lazy_loader as lazy
def attach(package_name, submodules=None, submod_attrs=None): def attach(
package_name: str,
submodules: set | None = None,
submod_attrs: dict | None = None,
):
"""Replaces a package's __getattr__, __dir__, and __all__ attributes using lazy.attach. """Replaces a package's __getattr__, __dir__, and __all__ attributes using lazy.attach.
The lazy loader __getattr__ doesn't support tuples as list values. We needed to add The lazy loader __getattr__ doesn't support tuples as list values. We needed to add
this functionality (tuples) in Reflex to support 'import as _' statements. This function this functionality (tuples) in Reflex to support 'import as _' statements. This function

Some files were not shown because too many files have changed in this diff Show More