fix conflicts
Merge remote-tracking branch 'upstream/main' into guess-type-fallback
This commit is contained in:
commit
9138f23923
@ -130,7 +130,6 @@ def render_multiple_pages(app, num: int):
|
|||||||
|
|
||||||
def AppWithOnePage():
|
def AppWithOnePage():
|
||||||
"""A reflex app with one page."""
|
"""A reflex app with one page."""
|
||||||
import reflex_chakra as rc
|
|
||||||
from rxconfig import config # type: ignore
|
from rxconfig import config # type: ignore
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
@ -145,7 +144,7 @@ def AppWithOnePage():
|
|||||||
|
|
||||||
def index() -> rx.Component:
|
def index() -> rx.Component:
|
||||||
return rx.center(
|
return rx.center(
|
||||||
rc.input(
|
rx.input(
|
||||||
id="token", value=State.router.session.client_token, is_read_only=True
|
id="token", value=State.router.session.client_token, is_read_only=True
|
||||||
),
|
),
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
|
@ -13,7 +13,6 @@ def BackgroundTask():
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
from reflex.state import ImmutableStateError
|
from reflex.state import ImmutableStateError
|
||||||
@ -116,11 +115,11 @@ def BackgroundTask():
|
|||||||
|
|
||||||
def index() -> rx.Component:
|
def index() -> rx.Component:
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rc.input(
|
rx.input(
|
||||||
id="token", value=State.router.session.client_token, is_read_only=True
|
id="token", value=State.router.session.client_token, is_read_only=True
|
||||||
),
|
),
|
||||||
rx.heading(State.counter, id="counter"),
|
rx.heading(State.counter, id="counter"),
|
||||||
rc.input(
|
rx.input(
|
||||||
id="iterations",
|
id="iterations",
|
||||||
placeholder="Iterations",
|
placeholder="Iterations",
|
||||||
value=State.iterations.to_string(), # type: ignore
|
value=State.iterations.to_string(), # type: ignore
|
||||||
|
@ -17,8 +17,6 @@ from . import utils
|
|||||||
|
|
||||||
def ClientSide():
|
def ClientSide():
|
||||||
"""App for testing client-side state."""
|
"""App for testing client-side state."""
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class ClientSideState(rx.State):
|
class ClientSideState(rx.State):
|
||||||
@ -72,18 +70,18 @@ def ClientSide():
|
|||||||
|
|
||||||
def index():
|
def index():
|
||||||
return rx.fragment(
|
return rx.fragment(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=ClientSideState.router.session.client_token,
|
value=ClientSideState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
rc.input(
|
rx.input(
|
||||||
placeholder="state var",
|
placeholder="state var",
|
||||||
value=ClientSideState.state_var,
|
value=ClientSideState.state_var,
|
||||||
on_change=ClientSideState.set_state_var, # type: ignore
|
on_change=ClientSideState.set_state_var, # type: ignore
|
||||||
id="state_var",
|
id="state_var",
|
||||||
),
|
),
|
||||||
rc.input(
|
rx.input(
|
||||||
placeholder="input value",
|
placeholder="input value",
|
||||||
value=ClientSideState.input_value,
|
value=ClientSideState.input_value,
|
||||||
on_change=ClientSideState.set_input_value, # type: ignore
|
on_change=ClientSideState.set_input_value, # type: ignore
|
||||||
@ -313,7 +311,6 @@ async def test_client_side_state(
|
|||||||
# no cookies should be set yet!
|
# no cookies should be set yet!
|
||||||
assert not driver.get_cookies()
|
assert not driver.get_cookies()
|
||||||
local_storage_items = local_storage.items()
|
local_storage_items = local_storage.items()
|
||||||
local_storage_items.pop("chakra-ui-color-mode", None)
|
|
||||||
local_storage_items.pop("last_compiled_time", None)
|
local_storage_items.pop("last_compiled_time", None)
|
||||||
assert not local_storage_items
|
assert not local_storage_items
|
||||||
|
|
||||||
@ -429,7 +426,6 @@ async def test_client_side_state(
|
|||||||
assert f"{sub_state_name}.c3" not in cookie_info_map(driver)
|
assert f"{sub_state_name}.c3" not in cookie_info_map(driver)
|
||||||
|
|
||||||
local_storage_items = local_storage.items()
|
local_storage_items = local_storage.items()
|
||||||
local_storage_items.pop("chakra-ui-color-mode", None)
|
|
||||||
local_storage_items.pop("last_compiled_time", None)
|
local_storage_items.pop("last_compiled_time", None)
|
||||||
assert local_storage_items.pop(f"{sub_state_name}.l1") == "l1 value"
|
assert local_storage_items.pop(f"{sub_state_name}.l1") == "l1 value"
|
||||||
assert local_storage_items.pop(f"{sub_state_name}.l2") == "l2 value"
|
assert local_storage_items.pop(f"{sub_state_name}.l2") == "l2 value"
|
||||||
|
@ -17,8 +17,6 @@ def DynamicRoute():
|
|||||||
"""App for testing dynamic routes."""
|
"""App for testing dynamic routes."""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class DynamicState(rx.State):
|
class DynamicState(rx.State):
|
||||||
@ -41,13 +39,13 @@ def DynamicRoute():
|
|||||||
|
|
||||||
def index():
|
def index():
|
||||||
return rx.fragment(
|
return rx.fragment(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=DynamicState.router.session.client_token,
|
value=DynamicState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
rc.input(value=rx.State.page_id, is_read_only=True, id="page_id"), # type: ignore
|
rx.input(value=rx.State.page_id, is_read_only=True, id="page_id"), # type: ignore
|
||||||
rc.input(
|
rx.input(
|
||||||
value=DynamicState.router.page.raw_path,
|
value=DynamicState.router.page.raw_path,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="raw_path",
|
id="raw_path",
|
||||||
@ -60,10 +58,10 @@ def DynamicRoute():
|
|||||||
id="link_page_next", # type: ignore
|
id="link_page_next", # type: ignore
|
||||||
),
|
),
|
||||||
rx.link("missing", href="/missing", id="link_missing"),
|
rx.link("missing", href="/missing", id="link_missing"),
|
||||||
rc.list(
|
rx.list( # type: ignore
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
DynamicState.order, # type: ignore
|
DynamicState.order, # type: ignore
|
||||||
lambda i: rc.list_item(rx.text(i)),
|
lambda i: rx.list_item(rx.text(i)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -16,8 +16,6 @@ def TestEventAction():
|
|||||||
"""App for testing event_actions."""
|
"""App for testing event_actions."""
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class EventActionState(rx.State):
|
class EventActionState(rx.State):
|
||||||
@ -55,7 +53,7 @@ def TestEventAction():
|
|||||||
|
|
||||||
def index():
|
def index():
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=EventActionState.router.session.client_token,
|
value=EventActionState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
@ -148,10 +146,10 @@ def TestEventAction():
|
|||||||
200
|
200
|
||||||
).stop_propagation,
|
).stop_propagation,
|
||||||
),
|
),
|
||||||
rc.list(
|
rx.list( # type: ignore
|
||||||
rx.foreach(
|
rx.foreach(
|
||||||
EventActionState.order, # type: ignore
|
EventActionState.order, # type: ignore
|
||||||
rc.list_item,
|
rx.list_item,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
on_click=EventActionState.on_click("outer"), # type: ignore
|
on_click=EventActionState.on_click("outer"), # type: ignore
|
||||||
|
@ -18,8 +18,6 @@ def EventChain():
|
|||||||
import time
|
import time
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
# repeated here since the outer global isn't exported into the App module
|
# repeated here since the outer global isn't exported into the App module
|
||||||
@ -129,7 +127,7 @@ def EventChain():
|
|||||||
|
|
||||||
app = rx.App(state=rx.State)
|
app = rx.App(state=rx.State)
|
||||||
|
|
||||||
token_input = rc.input(
|
token_input = rx.input(
|
||||||
value=State.router.session.client_token, is_read_only=True, id="token"
|
value=State.router.session.client_token, is_read_only=True, id="token"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -137,7 +135,7 @@ def EventChain():
|
|||||||
def index():
|
def index():
|
||||||
return rx.fragment(
|
return rx.fragment(
|
||||||
token_input,
|
token_input,
|
||||||
rc.input(value=State.interim_value, is_read_only=True, id="interim_value"),
|
rx.input(value=State.interim_value, is_read_only=True, id="interim_value"),
|
||||||
rx.button(
|
rx.button(
|
||||||
"Return Event",
|
"Return Event",
|
||||||
id="return_event",
|
id="return_event",
|
||||||
|
@ -20,8 +20,6 @@ def FormSubmit(form_component):
|
|||||||
"""
|
"""
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class FormState(rx.State):
|
class FormState(rx.State):
|
||||||
@ -37,28 +35,29 @@ def FormSubmit(form_component):
|
|||||||
@app.add_page
|
@app.add_page
|
||||||
def index():
|
def index():
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=FormState.router.session.client_token,
|
value=FormState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
eval(form_component)(
|
eval(form_component)(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rc.input(id="name_input"),
|
rx.input(id="name_input"),
|
||||||
rx.hstack(rc.pin_input(length=4, id="pin_input")),
|
|
||||||
rc.number_input(id="number_input"),
|
|
||||||
rx.checkbox(id="bool_input"),
|
rx.checkbox(id="bool_input"),
|
||||||
rx.switch(id="bool_input2"),
|
rx.switch(id="bool_input2"),
|
||||||
rx.checkbox(id="bool_input3"),
|
rx.checkbox(id="bool_input3"),
|
||||||
rx.switch(id="bool_input4"),
|
rx.switch(id="bool_input4"),
|
||||||
rx.slider(id="slider_input", default_value=[50], width="100%"),
|
rx.slider(id="slider_input", default_value=[50], width="100%"),
|
||||||
rc.range_slider(id="range_input"),
|
|
||||||
rx.radio(["option1", "option2"], id="radio_input"),
|
rx.radio(["option1", "option2"], id="radio_input"),
|
||||||
rx.radio(FormState.var_options, id="radio_input_var"),
|
rx.radio(FormState.var_options, id="radio_input_var"),
|
||||||
rc.select(["option1", "option2"], id="select_input"),
|
rx.select(
|
||||||
rc.select(FormState.var_options, id="select_input_var"),
|
["option1", "option2"],
|
||||||
|
name="select_input",
|
||||||
|
default_value="option1",
|
||||||
|
),
|
||||||
|
rx.select(FormState.var_options, id="select_input_var"),
|
||||||
rx.text_area(id="text_area_input"),
|
rx.text_area(id="text_area_input"),
|
||||||
rc.input(
|
rx.input(
|
||||||
id="debounce_input",
|
id="debounce_input",
|
||||||
debounce_timeout=0,
|
debounce_timeout=0,
|
||||||
on_change=rx.console_log,
|
on_change=rx.console_log,
|
||||||
@ -81,8 +80,6 @@ def FormSubmitName(form_component):
|
|||||||
"""
|
"""
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class FormState(rx.State):
|
class FormState(rx.State):
|
||||||
@ -98,22 +95,19 @@ def FormSubmitName(form_component):
|
|||||||
@app.add_page
|
@app.add_page
|
||||||
def index():
|
def index():
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=FormState.router.session.client_token,
|
value=FormState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
eval(form_component)(
|
eval(form_component)(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rc.input(name="name_input"),
|
rx.input(name="name_input"),
|
||||||
rx.hstack(rc.pin_input(length=4, name="pin_input")),
|
|
||||||
rc.number_input(name="number_input"),
|
|
||||||
rx.checkbox(name="bool_input"),
|
rx.checkbox(name="bool_input"),
|
||||||
rx.switch(name="bool_input2"),
|
rx.switch(name="bool_input2"),
|
||||||
rx.checkbox(name="bool_input3"),
|
rx.checkbox(name="bool_input3"),
|
||||||
rx.switch(name="bool_input4"),
|
rx.switch(name="bool_input4"),
|
||||||
rx.slider(name="slider_input", default_value=[50], width="100%"),
|
rx.slider(name="slider_input", default_value=[50], width="100%"),
|
||||||
rc.range_slider(name="range_input"),
|
|
||||||
rx.radio(FormState.options, name="radio_input"),
|
rx.radio(FormState.options, name="radio_input"),
|
||||||
rx.select(
|
rx.select(
|
||||||
FormState.options,
|
FormState.options,
|
||||||
@ -121,21 +115,13 @@ def FormSubmitName(form_component):
|
|||||||
default_value=FormState.options[0],
|
default_value=FormState.options[0],
|
||||||
),
|
),
|
||||||
rx.text_area(name="text_area_input"),
|
rx.text_area(name="text_area_input"),
|
||||||
rc.input_group(
|
rx.input(
|
||||||
rc.input_left_element(rx.icon(tag="chevron_right")),
|
name="debounce_input",
|
||||||
rc.input(
|
debounce_timeout=0,
|
||||||
name="debounce_input",
|
on_change=rx.console_log,
|
||||||
debounce_timeout=0,
|
|
||||||
on_change=rx.console_log,
|
|
||||||
),
|
|
||||||
rc.input_right_element(rx.icon(tag="chevron_left")),
|
|
||||||
),
|
|
||||||
rc.button_group(
|
|
||||||
rx.button("Submit", type_="submit"),
|
|
||||||
rx.icon_button(FormState.val, icon=rx.icon(tag="plus")),
|
|
||||||
variant="outline",
|
|
||||||
is_attached=True,
|
|
||||||
),
|
),
|
||||||
|
rx.button("Submit", type_="submit"),
|
||||||
|
rx.icon_button(FormState.val, icon=rx.icon(tag="plus")),
|
||||||
),
|
),
|
||||||
on_submit=FormState.form_submit,
|
on_submit=FormState.form_submit,
|
||||||
custom_attrs={"action": "/invalid"},
|
custom_attrs={"action": "/invalid"},
|
||||||
@ -152,16 +138,12 @@ def FormSubmitName(form_component):
|
|||||||
functools.partial(FormSubmitName, form_component="rx.form.root"),
|
functools.partial(FormSubmitName, form_component="rx.form.root"),
|
||||||
functools.partial(FormSubmit, form_component="rx.el.form"),
|
functools.partial(FormSubmit, form_component="rx.el.form"),
|
||||||
functools.partial(FormSubmitName, form_component="rx.el.form"),
|
functools.partial(FormSubmitName, form_component="rx.el.form"),
|
||||||
functools.partial(FormSubmit, form_component="rc.form"),
|
|
||||||
functools.partial(FormSubmitName, form_component="rc.form"),
|
|
||||||
],
|
],
|
||||||
ids=[
|
ids=[
|
||||||
"id-radix",
|
"id-radix",
|
||||||
"name-radix",
|
"name-radix",
|
||||||
"id-html",
|
"id-html",
|
||||||
"name-html",
|
"name-html",
|
||||||
"id-chakra",
|
|
||||||
"name-chakra",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||||
@ -224,16 +206,6 @@ async def test_submit(driver, form_submit: AppHarness):
|
|||||||
name_input = driver.find_element(by, "name_input")
|
name_input = driver.find_element(by, "name_input")
|
||||||
name_input.send_keys("foo")
|
name_input.send_keys("foo")
|
||||||
|
|
||||||
pin_inputs = driver.find_elements(By.CLASS_NAME, "chakra-pin-input")
|
|
||||||
pin_values = ["8", "1", "6", "4"]
|
|
||||||
for i, pin_input in enumerate(pin_inputs):
|
|
||||||
pin_input.send_keys(pin_values[i])
|
|
||||||
|
|
||||||
number_input = driver.find_element(By.CLASS_NAME, "chakra-numberinput")
|
|
||||||
buttons = number_input.find_elements(By.XPATH, "//div[@role='button']")
|
|
||||||
for _ in range(3):
|
|
||||||
buttons[1].click()
|
|
||||||
|
|
||||||
checkbox_input = driver.find_element(By.XPATH, "//button[@role='checkbox']")
|
checkbox_input = driver.find_element(By.XPATH, "//button[@role='checkbox']")
|
||||||
checkbox_input.click()
|
checkbox_input.click()
|
||||||
|
|
||||||
@ -275,15 +247,12 @@ async def test_submit(driver, form_submit: AppHarness):
|
|||||||
print(form_data)
|
print(form_data)
|
||||||
|
|
||||||
assert form_data["name_input"] == "foo"
|
assert form_data["name_input"] == "foo"
|
||||||
assert form_data["pin_input"] == pin_values
|
|
||||||
assert form_data["number_input"] == "-3"
|
|
||||||
assert form_data["bool_input"]
|
assert form_data["bool_input"]
|
||||||
assert form_data["bool_input2"]
|
assert form_data["bool_input2"]
|
||||||
assert not form_data.get("bool_input3", False)
|
assert not form_data.get("bool_input3", False)
|
||||||
assert not form_data.get("bool_input4", False)
|
assert not form_data.get("bool_input4", False)
|
||||||
|
|
||||||
assert form_data["slider_input"] == "50"
|
assert form_data["slider_input"] == "50"
|
||||||
assert form_data["range_input"] == ["25", "75"]
|
|
||||||
assert form_data["radio_input"] == "option2"
|
assert form_data["radio_input"] == "option2"
|
||||||
assert form_data["select_input"] == "option1"
|
assert form_data["select_input"] == "option1"
|
||||||
assert form_data["text_area_input"] == "Some\nText"
|
assert form_data["text_area_input"] == "Some\nText"
|
||||||
|
@ -11,8 +11,6 @@ from reflex.testing import AppHarness
|
|||||||
|
|
||||||
def ServerSideEvent():
|
def ServerSideEvent():
|
||||||
"""App with inputs set via event handlers and set_value."""
|
"""App with inputs set via event handlers and set_value."""
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class SSState(rx.State):
|
class SSState(rx.State):
|
||||||
@ -41,12 +39,12 @@ def ServerSideEvent():
|
|||||||
@app.add_page
|
@app.add_page
|
||||||
def index():
|
def index():
|
||||||
return rx.fragment(
|
return rx.fragment(
|
||||||
rc.input(
|
rx.input(
|
||||||
id="token", value=SSState.router.session.client_token, is_read_only=True
|
id="token", value=SSState.router.session.client_token, is_read_only=True
|
||||||
),
|
),
|
||||||
rc.input(default_value="a", id="a"),
|
rx.input(default_value="a", id="a"),
|
||||||
rc.input(default_value="b", id="b"),
|
rx.input(default_value="b", id="b"),
|
||||||
rc.input(default_value="c", id="c"),
|
rx.input(default_value="c", id="c"),
|
||||||
rx.button(
|
rx.button(
|
||||||
"Clear Immediate",
|
"Clear Immediate",
|
||||||
id="clear_immediate",
|
id="clear_immediate",
|
||||||
|
@ -10,91 +10,47 @@ from reflex.testing import AppHarness
|
|||||||
|
|
||||||
def Table():
|
def Table():
|
||||||
"""App using table component."""
|
"""App using table component."""
|
||||||
from typing import List
|
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class TableState(rx.State):
|
|
||||||
rows: List[List[str]] = [
|
|
||||||
["John", "30", "New York"],
|
|
||||||
["Jane", "31", "San Fransisco"],
|
|
||||||
["Joe", "32", "Los Angeles"],
|
|
||||||
]
|
|
||||||
|
|
||||||
headers: List[str] = ["Name", "Age", "Location"]
|
|
||||||
|
|
||||||
footers: List[str] = ["footer1", "footer2", "footer3"]
|
|
||||||
|
|
||||||
caption: str = "random caption"
|
|
||||||
|
|
||||||
app = rx.App(state=rx.State)
|
app = rx.App(state=rx.State)
|
||||||
|
|
||||||
@app.add_page
|
@app.add_page
|
||||||
def index():
|
def index():
|
||||||
return rx.center(
|
return rx.center(
|
||||||
rc.input(
|
rx.input(
|
||||||
id="token",
|
id="token",
|
||||||
value=TableState.router.session.client_token,
|
value=rx.State.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
),
|
),
|
||||||
rc.table_container(
|
rx.table.root(
|
||||||
rc.table(
|
rx.table.header(
|
||||||
headers=TableState.headers,
|
rx.table.row(
|
||||||
rows=TableState.rows,
|
rx.table.column_header_cell("Name"),
|
||||||
footers=TableState.footers,
|
rx.table.column_header_cell("Age"),
|
||||||
caption=TableState.caption,
|
rx.table.column_header_cell("Location"),
|
||||||
variant="striped",
|
),
|
||||||
color_scheme="blue",
|
|
||||||
width="100%",
|
|
||||||
),
|
),
|
||||||
|
rx.table.body(
|
||||||
|
rx.table.row(
|
||||||
|
rx.table.row_header_cell("John"),
|
||||||
|
rx.table.cell(30),
|
||||||
|
rx.table.cell("New York"),
|
||||||
|
),
|
||||||
|
rx.table.row(
|
||||||
|
rx.table.row_header_cell("Jane"),
|
||||||
|
rx.table.cell(31),
|
||||||
|
rx.table.cell("San Fransisco"),
|
||||||
|
),
|
||||||
|
rx.table.row(
|
||||||
|
rx.table.row_header_cell("Joe"),
|
||||||
|
rx.table.cell(32),
|
||||||
|
rx.table.cell("Los Angeles"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
width="100%",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.add_page
|
|
||||||
def another():
|
|
||||||
return rx.center(
|
|
||||||
rc.table_container(
|
|
||||||
rc.table( # type: ignore
|
|
||||||
rc.thead( # type: ignore
|
|
||||||
rc.tr( # type: ignore
|
|
||||||
rc.th("Name"),
|
|
||||||
rc.th("Age"),
|
|
||||||
rc.th("Location"),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
rc.tbody( # type: ignore
|
|
||||||
rc.tr( # type: ignore
|
|
||||||
rc.td("John"),
|
|
||||||
rc.td(30),
|
|
||||||
rc.td("New York"),
|
|
||||||
),
|
|
||||||
rc.tr( # type: ignore
|
|
||||||
rc.td("Jane"),
|
|
||||||
rc.td(31),
|
|
||||||
rc.td("San Francisco"),
|
|
||||||
),
|
|
||||||
rc.tr( # type: ignore
|
|
||||||
rc.td("Joe"),
|
|
||||||
rc.td(32),
|
|
||||||
rc.td("Los Angeles"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
rc.tfoot( # type: ignore
|
|
||||||
rc.tr(
|
|
||||||
rc.td("footer1"),
|
|
||||||
rc.td("footer2"),
|
|
||||||
rc.td("footer3"),
|
|
||||||
) # type: ignore
|
|
||||||
),
|
|
||||||
rc.table_caption("random caption"),
|
|
||||||
variant="striped",
|
|
||||||
color_scheme="teal",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def table(tmp_path_factory) -> Generator[AppHarness, None, None]:
|
def table(tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||||
@ -138,23 +94,20 @@ def driver(table: AppHarness):
|
|||||||
driver.quit()
|
driver.quit()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("route", ["", "/another"])
|
def test_table(driver, table: AppHarness):
|
||||||
def test_table(driver, table: AppHarness, route):
|
|
||||||
"""Test that a table component is rendered properly.
|
"""Test that a table component is rendered properly.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
driver: Selenium WebDriver open to the app
|
driver: Selenium WebDriver open to the app
|
||||||
table: Harness for Table app
|
table: Harness for Table app
|
||||||
route: Page route or path.
|
|
||||||
"""
|
"""
|
||||||
driver.get(f"{table.frontend_url}/{route}")
|
|
||||||
assert table.app_instance is not None, "app is not running"
|
assert table.app_instance is not None, "app is not running"
|
||||||
|
|
||||||
thead = driver.find_element(By.TAG_NAME, "thead")
|
thead = driver.find_element(By.TAG_NAME, "thead")
|
||||||
# poll till page is fully loaded.
|
# poll till page is fully loaded.
|
||||||
table.poll_for_content(element=thead)
|
table.poll_for_content(element=thead)
|
||||||
# check headers
|
# check headers
|
||||||
assert thead.find_element(By.TAG_NAME, "tr").text == "NAME AGE LOCATION"
|
assert thead.find_element(By.TAG_NAME, "tr").text == "Name Age Location"
|
||||||
# check first row value
|
# check first row value
|
||||||
assert (
|
assert (
|
||||||
driver.find_element(By.TAG_NAME, "tbody")
|
driver.find_element(By.TAG_NAME, "tbody")
|
||||||
@ -162,12 +115,3 @@ def test_table(driver, table: AppHarness, route):
|
|||||||
.text
|
.text
|
||||||
== "John 30 New York"
|
== "John 30 New York"
|
||||||
)
|
)
|
||||||
# check footer
|
|
||||||
assert (
|
|
||||||
driver.find_element(By.TAG_NAME, "tfoot")
|
|
||||||
.find_element(By.TAG_NAME, "tr")
|
|
||||||
.text.lower()
|
|
||||||
== "footer1 footer2 footer3"
|
|
||||||
)
|
|
||||||
# check caption
|
|
||||||
assert driver.find_element(By.TAG_NAME, "caption").text == "random caption"
|
|
||||||
|
@ -27,8 +27,6 @@ def TailwindApp(
|
|||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class UnusedState(rx.State):
|
class UnusedState(rx.State):
|
||||||
@ -36,7 +34,7 @@ def TailwindApp(
|
|||||||
|
|
||||||
def index():
|
def index():
|
||||||
return rx.el.div(
|
return rx.el.div(
|
||||||
rc.text(paragraph_text, class_name=paragraph_class_name),
|
rx.text(paragraph_text, class_name=paragraph_class_name),
|
||||||
rx.el.p(paragraph_text, class_name=paragraph_class_name),
|
rx.el.p(paragraph_text, class_name=paragraph_class_name),
|
||||||
rx.text(paragraph_text, as_="p", class_name=paragraph_class_name),
|
rx.text(paragraph_text, as_="p", class_name=paragraph_class_name),
|
||||||
rx.el.div("Test external stylesheet", class_name="external"),
|
rx.el.div("Test external stylesheet", class_name="external"),
|
||||||
|
@ -16,8 +16,6 @@ def UploadFile():
|
|||||||
"""App for testing dynamic routes."""
|
"""App for testing dynamic routes."""
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class UploadState(rx.State):
|
class UploadState(rx.State):
|
||||||
@ -46,7 +44,7 @@ def UploadFile():
|
|||||||
|
|
||||||
def index():
|
def index():
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
rc.input(
|
rx.input(
|
||||||
value=UploadState.router.session.client_token,
|
value=UploadState.router.session.client_token,
|
||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
|
@ -14,8 +14,6 @@ def VarOperations():
|
|||||||
"""App with var operations."""
|
"""App with var operations."""
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
from reflex.ivars.base import LiteralVar
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.ivars.sequence import ArrayVar
|
from reflex.ivars.sequence import ArrayVar
|
||||||
@ -552,10 +550,7 @@ def VarOperations():
|
|||||||
VarOperationState.html_str,
|
VarOperationState.html_str,
|
||||||
id="html_str",
|
id="html_str",
|
||||||
),
|
),
|
||||||
rc.highlight(
|
rx.el.mark("second"),
|
||||||
"second",
|
|
||||||
query=[VarOperationState.str_var2],
|
|
||||||
),
|
|
||||||
rx.text(ArrayVar.range(2, 5).join(","), id="list_join_range1"),
|
rx.text(ArrayVar.range(2, 5).join(","), id="list_join_range1"),
|
||||||
rx.text(ArrayVar.range(2, 10, 2).join(","), id="list_join_range2"),
|
rx.text(ArrayVar.range(2, 10, 2).join(","), id="list_join_range2"),
|
||||||
rx.text(ArrayVar.range(5, 0, -1).join(","), id="list_join_range3"),
|
rx.text(ArrayVar.range(5, 0, -1).join(","), id="list_join_range3"),
|
||||||
|
153
poetry.lock
generated
153
poetry.lock
generated
@ -1,9 +1,10 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
description = "A database migration tool for SQLAlchemy."
|
description = "A database migration tool for SQLAlchemy."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -25,6 +26,7 @@ tz = ["backports.zoneinfo"]
|
|||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
description = "Reusable constraint types to use with typing.Annotated"
|
description = "Reusable constraint types to use with typing.Annotated"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -39,6 +41,7 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""}
|
|||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.4.0"
|
version = "4.4.0"
|
||||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -61,6 +64,7 @@ trio = ["trio (>=0.23)"]
|
|||||||
name = "async-timeout"
|
name = "async-timeout"
|
||||||
version = "4.0.3"
|
version = "4.0.3"
|
||||||
description = "Timeout context manager for asyncio programs"
|
description = "Timeout context manager for asyncio programs"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -72,6 +76,7 @@ files = [
|
|||||||
name = "asynctest"
|
name = "asynctest"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
description = "Enhance the standard unittest package with features for testing asyncio libraries"
|
description = "Enhance the standard unittest package with features for testing asyncio libraries"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
files = [
|
files = [
|
||||||
@ -83,6 +88,7 @@ files = [
|
|||||||
name = "attrs"
|
name = "attrs"
|
||||||
version = "24.2.0"
|
version = "24.2.0"
|
||||||
description = "Classes Without Boilerplate"
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -102,6 +108,7 @@ tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
|
|||||||
name = "backports-tarfile"
|
name = "backports-tarfile"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
description = "Backport of CPython tarfile module"
|
description = "Backport of CPython tarfile module"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -117,6 +124,7 @@ testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-ch
|
|||||||
name = "bidict"
|
name = "bidict"
|
||||||
version = "0.23.1"
|
version = "0.23.1"
|
||||||
description = "The bidirectional mapping library for Python."
|
description = "The bidirectional mapping library for Python."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -128,6 +136,7 @@ files = [
|
|||||||
name = "build"
|
name = "build"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
description = "A simple, correct Python build frontend"
|
description = "A simple, correct Python build frontend"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -153,6 +162,7 @@ virtualenv = ["virtualenv (>=20.0.35)"]
|
|||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2024.8.30"
|
version = "2024.8.30"
|
||||||
description = "Python package for providing Mozilla's CA Bundle."
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -164,6 +174,7 @@ files = [
|
|||||||
name = "cffi"
|
name = "cffi"
|
||||||
version = "1.17.1"
|
version = "1.17.1"
|
||||||
description = "Foreign Function Interface for Python calling C code."
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -243,6 +254,7 @@ pycparser = "*"
|
|||||||
name = "cfgv"
|
name = "cfgv"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
description = "Validate configuration and produce human readable error messages."
|
description = "Validate configuration and produce human readable error messages."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -254,6 +266,7 @@ files = [
|
|||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.3.2"
|
version = "3.3.2"
|
||||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
@ -353,6 +366,7 @@ files = [
|
|||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
description = "Composable command line interface toolkit"
|
description = "Composable command line interface toolkit"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -367,6 +381,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
|||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
description = "Cross-platform colored terminal text."
|
description = "Cross-platform colored terminal text."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
@ -378,6 +393,7 @@ files = [
|
|||||||
name = "coverage"
|
name = "coverage"
|
||||||
version = "7.6.1"
|
version = "7.6.1"
|
||||||
description = "Code coverage measurement for Python"
|
description = "Code coverage measurement for Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -465,6 +481,7 @@ toml = ["tomli"]
|
|||||||
name = "cryptography"
|
name = "cryptography"
|
||||||
version = "43.0.1"
|
version = "43.0.1"
|
||||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -514,6 +531,7 @@ test-randomorder = ["pytest-randomly"]
|
|||||||
name = "darglint"
|
name = "darglint"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
description = "A utility for ensuring Google-style docstrings stay up to date with the source code."
|
description = "A utility for ensuring Google-style docstrings stay up to date with the source code."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6,<4.0"
|
python-versions = ">=3.6,<4.0"
|
||||||
files = [
|
files = [
|
||||||
@ -525,6 +543,7 @@ files = [
|
|||||||
name = "dill"
|
name = "dill"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
description = "serialize all of Python"
|
description = "serialize all of Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -540,6 +559,7 @@ profile = ["gprof2dot (>=2022.7.29)"]
|
|||||||
name = "distlib"
|
name = "distlib"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
description = "Distribution utilities"
|
description = "Distribution utilities"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
@ -551,6 +571,7 @@ files = [
|
|||||||
name = "distro"
|
name = "distro"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
description = "Distro - an OS platform information API"
|
description = "Distro - an OS platform information API"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -562,14 +583,19 @@ files = [
|
|||||||
name = "docutils"
|
name = "docutils"
|
||||||
version = "0.20.1"
|
version = "0.20.1"
|
||||||
description = "Docutils -- Python Documentation Utilities"
|
description = "Docutils -- Python Documentation Utilities"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.7"
|
||||||
files = []
|
files = [
|
||||||
|
{file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"},
|
||||||
|
{file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exceptiongroup"
|
name = "exceptiongroup"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
description = "Backport of PEP 654 (exception groups)"
|
description = "Backport of PEP 654 (exception groups)"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -584,6 +610,7 @@ test = ["pytest (>=6)"]
|
|||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.114.0"
|
version = "0.114.0"
|
||||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -604,6 +631,7 @@ standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "htt
|
|||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.15.4"
|
version = "3.15.4"
|
||||||
description = "A platform independent file lock."
|
description = "A platform independent file lock."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -620,6 +648,7 @@ typing = ["typing-extensions (>=4.8)"]
|
|||||||
name = "greenlet"
|
name = "greenlet"
|
||||||
version = "3.0.3"
|
version = "3.0.3"
|
||||||
description = "Lightweight in-process concurrent programming"
|
description = "Lightweight in-process concurrent programming"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -691,6 +720,7 @@ test = ["objgraph", "psutil"]
|
|||||||
name = "gunicorn"
|
name = "gunicorn"
|
||||||
version = "23.0.0"
|
version = "23.0.0"
|
||||||
description = "WSGI HTTP Server for UNIX"
|
description = "WSGI HTTP Server for UNIX"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -712,6 +742,7 @@ tornado = ["tornado (>=0.2)"]
|
|||||||
name = "h11"
|
name = "h11"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -723,6 +754,7 @@ files = [
|
|||||||
name = "httpcore"
|
name = "httpcore"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
description = "A minimal low-level HTTP client."
|
description = "A minimal low-level HTTP client."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -737,13 +769,14 @@ h11 = ">=0.13,<0.15"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
asyncio = ["anyio (>=4.0,<5.0)"]
|
asyncio = ["anyio (>=4.0,<5.0)"]
|
||||||
http2 = ["h2 (>=3,<5)"]
|
http2 = ["h2 (>=3,<5)"]
|
||||||
socks = ["socksio (==1.*)"]
|
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||||
trio = ["trio (>=0.22.0,<0.26.0)"]
|
trio = ["trio (>=0.22.0,<0.26.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx"
|
name = "httpx"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
description = "The next generation HTTP client."
|
description = "The next generation HTTP client."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -754,21 +787,22 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
anyio = "*"
|
anyio = "*"
|
||||||
certifi = "*"
|
certifi = "*"
|
||||||
httpcore = "==1.*"
|
httpcore = ">=1.0.0,<2.0.0"
|
||||||
idna = "*"
|
idna = "*"
|
||||||
sniffio = "*"
|
sniffio = "*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
brotli = ["brotli", "brotlicffi"]
|
brotli = ["brotli", "brotlicffi"]
|
||||||
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
|
||||||
http2 = ["h2 (>=3,<5)"]
|
http2 = ["h2 (>=3,<5)"]
|
||||||
socks = ["socksio (==1.*)"]
|
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||||
zstd = ["zstandard (>=0.18.0)"]
|
zstd = ["zstandard (>=0.18.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
description = "File identification library for Python"
|
description = "File identification library for Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -783,6 +817,7 @@ license = ["ukkonen"]
|
|||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.8"
|
version = "3.8"
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -794,6 +829,7 @@ files = [
|
|||||||
name = "importlib-metadata"
|
name = "importlib-metadata"
|
||||||
version = "8.4.0"
|
version = "8.4.0"
|
||||||
description = "Read metadata from Python packages"
|
description = "Read metadata from Python packages"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -813,6 +849,7 @@ test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "p
|
|||||||
name = "importlib-resources"
|
name = "importlib-resources"
|
||||||
version = "6.4.4"
|
version = "6.4.4"
|
||||||
description = "Read resources from Python packages"
|
description = "Read resources from Python packages"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -835,6 +872,7 @@ type = ["pytest-mypy"]
|
|||||||
name = "iniconfig"
|
name = "iniconfig"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
description = "brain-dead simple config-ini parsing"
|
description = "brain-dead simple config-ini parsing"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -846,6 +884,7 @@ files = [
|
|||||||
name = "jaraco-classes"
|
name = "jaraco-classes"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
description = "Utility functions for Python class constructs"
|
description = "Utility functions for Python class constructs"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -864,6 +903,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena
|
|||||||
name = "jaraco-context"
|
name = "jaraco-context"
|
||||||
version = "6.0.1"
|
version = "6.0.1"
|
||||||
description = "Useful decorators and context managers"
|
description = "Useful decorators and context managers"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -882,6 +922,7 @@ test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-c
|
|||||||
name = "jaraco-functools"
|
name = "jaraco-functools"
|
||||||
version = "4.0.2"
|
version = "4.0.2"
|
||||||
description = "Functools like those found in stdlib"
|
description = "Functools like those found in stdlib"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -900,6 +941,7 @@ test = ["jaraco.classes", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "p
|
|||||||
name = "jeepney"
|
name = "jeepney"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
description = "Low-level, pure Python DBus protocol wrapper."
|
description = "Low-level, pure Python DBus protocol wrapper."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -915,6 +957,7 @@ trio = ["async_generator", "trio"]
|
|||||||
name = "jinja2"
|
name = "jinja2"
|
||||||
version = "3.1.4"
|
version = "3.1.4"
|
||||||
description = "A very fast and expressive template engine."
|
description = "A very fast and expressive template engine."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -932,6 +975,7 @@ i18n = ["Babel (>=2.7)"]
|
|||||||
name = "keyring"
|
name = "keyring"
|
||||||
version = "25.3.0"
|
version = "25.3.0"
|
||||||
description = "Store and access your passwords safely."
|
description = "Store and access your passwords safely."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -958,6 +1002,7 @@ test = ["pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-
|
|||||||
name = "lazy-loader"
|
name = "lazy-loader"
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
description = "Makes it easy to load subpackages and functions on demand."
|
description = "Makes it easy to load subpackages and functions on demand."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -977,6 +1022,7 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
|
|||||||
name = "mako"
|
name = "mako"
|
||||||
version = "1.3.5"
|
version = "1.3.5"
|
||||||
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -996,6 +1042,7 @@ testing = ["pytest"]
|
|||||||
name = "markdown-it-py"
|
name = "markdown-it-py"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
description = "Python port of markdown-it. Markdown parsing, done right!"
|
description = "Python port of markdown-it. Markdown parsing, done right!"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1020,6 +1067,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
|||||||
name = "markupsafe"
|
name = "markupsafe"
|
||||||
version = "2.1.5"
|
version = "2.1.5"
|
||||||
description = "Safely add untrusted strings to HTML/XML markup."
|
description = "Safely add untrusted strings to HTML/XML markup."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1089,6 +1137,7 @@ files = [
|
|||||||
name = "mdurl"
|
name = "mdurl"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
description = "Markdown URL utilities"
|
description = "Markdown URL utilities"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1100,6 +1149,7 @@ files = [
|
|||||||
name = "more-itertools"
|
name = "more-itertools"
|
||||||
version = "10.5.0"
|
version = "10.5.0"
|
||||||
description = "More routines for operating on iterables, beyond itertools"
|
description = "More routines for operating on iterables, beyond itertools"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1111,6 +1161,7 @@ files = [
|
|||||||
name = "nh3"
|
name = "nh3"
|
||||||
version = "0.2.18"
|
version = "0.2.18"
|
||||||
description = "Python bindings to the ammonia HTML sanitization library."
|
description = "Python bindings to the ammonia HTML sanitization library."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
@ -1136,6 +1187,7 @@ files = [
|
|||||||
name = "nodeenv"
|
name = "nodeenv"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
description = "Node.js virtual environment builder"
|
description = "Node.js virtual environment builder"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1147,6 +1199,7 @@ files = [
|
|||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "1.24.4"
|
version = "1.24.4"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1184,6 +1237,7 @@ files = [
|
|||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
@ -1238,6 +1292,7 @@ files = [
|
|||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.10"
|
python-versions = ">=3.10"
|
||||||
files = [
|
files = [
|
||||||
@ -1300,6 +1355,7 @@ files = [
|
|||||||
name = "outcome"
|
name = "outcome"
|
||||||
version = "1.3.0.post0"
|
version = "1.3.0.post0"
|
||||||
description = "Capture the outcome of Python function calls."
|
description = "Capture the outcome of Python function calls."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1314,6 +1370,7 @@ attrs = ">=19.2.0"
|
|||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "24.1"
|
version = "24.1"
|
||||||
description = "Core utilities for Python packages"
|
description = "Core utilities for Python packages"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1325,6 +1382,7 @@ files = [
|
|||||||
name = "pandas"
|
name = "pandas"
|
||||||
version = "1.5.3"
|
version = "1.5.3"
|
||||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1369,6 +1427,7 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"]
|
|||||||
name = "pandas"
|
name = "pandas"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
@ -1442,6 +1501,7 @@ xml = ["lxml (>=4.9.2)"]
|
|||||||
name = "pillow"
|
name = "pillow"
|
||||||
version = "10.4.0"
|
version = "10.4.0"
|
||||||
description = "Python Imaging Library (Fork)"
|
description = "Python Imaging Library (Fork)"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1539,6 +1599,7 @@ xmp = ["defusedxml"]
|
|||||||
name = "pip"
|
name = "pip"
|
||||||
version = "24.2"
|
version = "24.2"
|
||||||
description = "The PyPA recommended tool for installing Python packages."
|
description = "The PyPA recommended tool for installing Python packages."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1550,6 +1611,7 @@ files = [
|
|||||||
name = "pipdeptree"
|
name = "pipdeptree"
|
||||||
version = "2.16.2"
|
version = "2.16.2"
|
||||||
description = "Command line utility to show dependency tree of packages."
|
description = "Command line utility to show dependency tree of packages."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1568,6 +1630,7 @@ test = ["covdefaults (>=2.3)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pyte
|
|||||||
name = "pkginfo"
|
name = "pkginfo"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
description = "Query metadata from sdists / bdists / installed packages."
|
description = "Query metadata from sdists / bdists / installed packages."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -1582,6 +1645,7 @@ testing = ["pytest", "pytest-cov", "wheel"]
|
|||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "4.2.2"
|
version = "4.2.2"
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1598,6 +1662,7 @@ type = ["mypy (>=1.8)"]
|
|||||||
name = "plotly"
|
name = "plotly"
|
||||||
version = "5.24.0"
|
version = "5.24.0"
|
||||||
description = "An open-source, interactive data visualization library for Python"
|
description = "An open-source, interactive data visualization library for Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1613,6 +1678,7 @@ tenacity = ">=6.2.0"
|
|||||||
name = "pluggy"
|
name = "pluggy"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
description = "plugin and hook calling mechanisms for python"
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1628,6 +1694,7 @@ testing = ["pytest", "pytest-benchmark"]
|
|||||||
name = "pre-commit"
|
name = "pre-commit"
|
||||||
version = "3.5.0"
|
version = "3.5.0"
|
||||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1646,6 +1713,7 @@ virtualenv = ">=20.10.0"
|
|||||||
name = "psutil"
|
name = "psutil"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
description = "Cross-platform lib for process and system monitoring in Python."
|
description = "Cross-platform lib for process and system monitoring in Python."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1675,6 +1743,7 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
|
|||||||
name = "py-cpuinfo"
|
name = "py-cpuinfo"
|
||||||
version = "9.0.0"
|
version = "9.0.0"
|
||||||
description = "Get CPU info with pure Python"
|
description = "Get CPU info with pure Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
@ -1686,6 +1755,7 @@ files = [
|
|||||||
name = "pycparser"
|
name = "pycparser"
|
||||||
version = "2.22"
|
version = "2.22"
|
||||||
description = "C parser in Python"
|
description = "C parser in Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1697,6 +1767,7 @@ files = [
|
|||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
description = "Data validation using Python type hints"
|
description = "Data validation using Python type hints"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1720,6 +1791,7 @@ email = ["email-validator (>=2.0.0)"]
|
|||||||
name = "pydantic-core"
|
name = "pydantic-core"
|
||||||
version = "2.23.2"
|
version = "2.23.2"
|
||||||
description = "Core functionality for Pydantic validation and serialization"
|
description = "Core functionality for Pydantic validation and serialization"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1821,6 +1893,7 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
|||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.18.0"
|
version = "2.18.0"
|
||||||
description = "Pygments is a syntax highlighting package written in Python."
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1835,6 +1908,7 @@ windows-terminal = ["colorama (>=0.4.6)"]
|
|||||||
name = "pyproject-hooks"
|
name = "pyproject-hooks"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
description = "Wrappers to call pyproject.toml-based build backend hooks."
|
description = "Wrappers to call pyproject.toml-based build backend hooks."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1846,6 +1920,7 @@ files = [
|
|||||||
name = "pyright"
|
name = "pyright"
|
||||||
version = "1.1.334"
|
version = "1.1.334"
|
||||||
description = "Command line wrapper for pyright"
|
description = "Command line wrapper for pyright"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1864,6 +1939,7 @@ dev = ["twine (>=3.4.1)"]
|
|||||||
name = "pysocks"
|
name = "pysocks"
|
||||||
version = "1.7.1"
|
version = "1.7.1"
|
||||||
description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
|
description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
files = [
|
files = [
|
||||||
@ -1876,6 +1952,7 @@ files = [
|
|||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "7.4.4"
|
version = "7.4.4"
|
||||||
description = "pytest: simple powerful testing with Python"
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1898,6 +1975,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
|
|||||||
name = "pytest-asyncio"
|
name = "pytest-asyncio"
|
||||||
version = "0.21.2"
|
version = "0.21.2"
|
||||||
description = "Pytest support for asyncio"
|
description = "Pytest support for asyncio"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1916,6 +1994,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy
|
|||||||
name = "pytest-benchmark"
|
name = "pytest-benchmark"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
|
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1936,6 +2015,7 @@ histogram = ["pygal", "pygaljs"]
|
|||||||
name = "pytest-cov"
|
name = "pytest-cov"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
description = "Pytest plugin for measuring coverage."
|
description = "Pytest plugin for measuring coverage."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1954,6 +2034,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale
|
|||||||
name = "pytest-mock"
|
name = "pytest-mock"
|
||||||
version = "3.14.0"
|
version = "3.14.0"
|
||||||
description = "Thin-wrapper around the mock package for easier use with pytest"
|
description = "Thin-wrapper around the mock package for easier use with pytest"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -1971,6 +2052,7 @@ dev = ["pre-commit", "pytest-asyncio", "tox"]
|
|||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
version = "2.9.0.post0"
|
||||||
description = "Extensions to the standard Python datetime module"
|
description = "Extensions to the standard Python datetime module"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1985,6 +2067,7 @@ six = ">=1.5"
|
|||||||
name = "python-engineio"
|
name = "python-engineio"
|
||||||
version = "4.9.1"
|
version = "4.9.1"
|
||||||
description = "Engine.IO server and client for Python"
|
description = "Engine.IO server and client for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -2004,6 +2087,7 @@ docs = ["sphinx"]
|
|||||||
name = "python-multipart"
|
name = "python-multipart"
|
||||||
version = "0.0.9"
|
version = "0.0.9"
|
||||||
description = "A streaming multipart parser for Python"
|
description = "A streaming multipart parser for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2018,6 +2102,7 @@ dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatc
|
|||||||
name = "python-socketio"
|
name = "python-socketio"
|
||||||
version = "5.11.4"
|
version = "5.11.4"
|
||||||
description = "Socket.IO server and client for Python"
|
description = "Socket.IO server and client for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2038,6 +2123,7 @@ docs = ["sphinx"]
|
|||||||
name = "pytz"
|
name = "pytz"
|
||||||
version = "2024.1"
|
version = "2024.1"
|
||||||
description = "World timezone definitions, modern and historical"
|
description = "World timezone definitions, modern and historical"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
@ -2049,6 +2135,7 @@ files = [
|
|||||||
name = "pywin32-ctypes"
|
name = "pywin32-ctypes"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
|
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -2060,6 +2147,7 @@ files = [
|
|||||||
name = "pyyaml"
|
name = "pyyaml"
|
||||||
version = "6.0.2"
|
version = "6.0.2"
|
||||||
description = "YAML parser and emitter for Python"
|
description = "YAML parser and emitter for Python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2122,6 +2210,7 @@ files = [
|
|||||||
name = "readme-renderer"
|
name = "readme-renderer"
|
||||||
version = "43.0"
|
version = "43.0"
|
||||||
description = "readme_renderer is a library for rendering readme descriptions for Warehouse"
|
description = "readme_renderer is a library for rendering readme descriptions for Warehouse"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2141,6 +2230,7 @@ md = ["cmarkgfm (>=0.8.0)"]
|
|||||||
name = "redis"
|
name = "redis"
|
||||||
version = "5.0.8"
|
version = "5.0.8"
|
||||||
description = "Python client for Redis database and key-value store"
|
description = "Python client for Redis database and key-value store"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2157,13 +2247,14 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reflex-chakra"
|
name = "reflex-chakra"
|
||||||
version = "0.6.0a5"
|
version = "0.6.0a6"
|
||||||
description = "reflex using chakra components"
|
description = "reflex using chakra components"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "<4.0,>=3.8"
|
python-versions = "<4.0,>=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "reflex_chakra-0.6.0a5-py3-none-any.whl", hash = "sha256:9d502ddf3bd606baef4f0ff6453dcefb5e19dab4cfaf7c23df069fab70687a63"},
|
{file = "reflex_chakra-0.6.0a6-py3-none-any.whl", hash = "sha256:a526f5db8a457c68c24317d007172e77b323a34abf03f05eeb8d92c014563bfb"},
|
||||||
{file = "reflex_chakra-0.6.0a5.tar.gz", hash = "sha256:b44e73478462052f09c9677d3fd7726891b4af87711b4b6a2171f010049308c9"},
|
{file = "reflex_chakra-0.6.0a6.tar.gz", hash = "sha256:124a780ea96d36d31f46b4c97bb0c0f111f2fb6e0d66a142e1577dad740f6e35"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2173,6 +2264,7 @@ reflex = ">=0.6.0a"
|
|||||||
name = "reflex-hosting-cli"
|
name = "reflex-hosting-cli"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
description = "Reflex Hosting CLI"
|
description = "Reflex Hosting CLI"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "<4.0,>=3.8"
|
python-versions = "<4.0,>=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2196,6 +2288,7 @@ websockets = ">=10.4"
|
|||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.3"
|
version = "2.32.3"
|
||||||
description = "Python HTTP for Humans."
|
description = "Python HTTP for Humans."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2217,6 +2310,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|||||||
name = "requests-toolbelt"
|
name = "requests-toolbelt"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "A utility belt for advanced users of python-requests"
|
description = "A utility belt for advanced users of python-requests"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
files = [
|
files = [
|
||||||
@ -2231,6 +2325,7 @@ requests = ">=2.0.1,<3.0.0"
|
|||||||
name = "rfc3986"
|
name = "rfc3986"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
description = "Validating URI References per RFC 3986"
|
description = "Validating URI References per RFC 3986"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2245,6 +2340,7 @@ idna2008 = ["idna"]
|
|||||||
name = "rich"
|
name = "rich"
|
||||||
version = "13.8.0"
|
version = "13.8.0"
|
||||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
@ -2264,6 +2360,7 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
|||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2290,6 +2387,7 @@ files = [
|
|||||||
name = "secretstorage"
|
name = "secretstorage"
|
||||||
version = "3.3.3"
|
version = "3.3.3"
|
||||||
description = "Python bindings to FreeDesktop.org Secret Service API"
|
description = "Python bindings to FreeDesktop.org Secret Service API"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -2305,6 +2403,7 @@ jeepney = ">=0.6"
|
|||||||
name = "selenium"
|
name = "selenium"
|
||||||
version = "4.24.0"
|
version = "4.24.0"
|
||||||
description = "Official Python bindings for Selenium WebDriver"
|
description = "Official Python bindings for Selenium WebDriver"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2324,6 +2423,7 @@ websocket-client = ">=1.8,<2.0"
|
|||||||
name = "setuptools"
|
name = "setuptools"
|
||||||
version = "70.1.1"
|
version = "70.1.1"
|
||||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2339,6 +2439,7 @@ testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metad
|
|||||||
name = "shellingham"
|
name = "shellingham"
|
||||||
version = "1.5.4"
|
version = "1.5.4"
|
||||||
description = "Tool to Detect Surrounding Shell"
|
description = "Tool to Detect Surrounding Shell"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2350,6 +2451,7 @@ files = [
|
|||||||
name = "simple-websocket"
|
name = "simple-websocket"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "Simple WebSocket server and client for Python"
|
description = "Simple WebSocket server and client for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -2367,6 +2469,7 @@ docs = ["sphinx"]
|
|||||||
name = "six"
|
name = "six"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
files = [
|
files = [
|
||||||
@ -2378,6 +2481,7 @@ files = [
|
|||||||
name = "sniffio"
|
name = "sniffio"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
description = "Sniff out which async library your code is running under"
|
description = "Sniff out which async library your code is running under"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2389,6 +2493,7 @@ files = [
|
|||||||
name = "sortedcontainers"
|
name = "sortedcontainers"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
|
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
@ -2400,6 +2505,7 @@ files = [
|
|||||||
name = "sqlalchemy"
|
name = "sqlalchemy"
|
||||||
version = "2.0.34"
|
version = "2.0.34"
|
||||||
description = "Database Abstraction Library"
|
description = "Database Abstraction Library"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2455,7 +2561,7 @@ files = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and platform_machine == \"aarch64\" or python_version < \"3.13\" and platform_machine == \"ppc64le\" or python_version < \"3.13\" and platform_machine == \"x86_64\" or python_version < \"3.13\" and platform_machine == \"amd64\" or python_version < \"3.13\" and platform_machine == \"AMD64\" or python_version < \"3.13\" and platform_machine == \"win32\" or python_version < \"3.13\" and platform_machine == \"WIN32\""}
|
||||||
typing-extensions = ">=4.6.0"
|
typing-extensions = ">=4.6.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -2487,6 +2593,7 @@ sqlcipher = ["sqlcipher3_binary"]
|
|||||||
name = "sqlmodel"
|
name = "sqlmodel"
|
||||||
version = "0.0.22"
|
version = "0.0.22"
|
||||||
description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
|
description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2502,6 +2609,7 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
|
|||||||
name = "starlette"
|
name = "starlette"
|
||||||
version = "0.38.4"
|
version = "0.38.4"
|
||||||
description = "The little ASGI library that shines."
|
description = "The little ASGI library that shines."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2520,6 +2628,7 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7
|
|||||||
name = "starlette-admin"
|
name = "starlette-admin"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications"
|
description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2543,6 +2652,7 @@ test = ["aiomysql (>=0.1.1,<0.3.0)", "aiosqlite (>=0.17.0,<0.21.0)", "arrow (>=1
|
|||||||
name = "tabulate"
|
name = "tabulate"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
description = "Pretty-print tabular data"
|
description = "Pretty-print tabular data"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2557,6 +2667,7 @@ widechars = ["wcwidth"]
|
|||||||
name = "tenacity"
|
name = "tenacity"
|
||||||
version = "9.0.0"
|
version = "9.0.0"
|
||||||
description = "Retry code until it succeeds"
|
description = "Retry code until it succeeds"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2572,6 +2683,7 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
|||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
files = [
|
files = [
|
||||||
@ -2583,6 +2695,7 @@ files = [
|
|||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
description = "A lil' TOML parser"
|
description = "A lil' TOML parser"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2594,6 +2707,7 @@ files = [
|
|||||||
name = "tomlkit"
|
name = "tomlkit"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
description = "Style preserving TOML library"
|
description = "Style preserving TOML library"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2605,6 +2719,7 @@ files = [
|
|||||||
name = "trio"
|
name = "trio"
|
||||||
version = "0.26.2"
|
version = "0.26.2"
|
||||||
description = "A friendly Python library for async concurrency and I/O"
|
description = "A friendly Python library for async concurrency and I/O"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2625,6 +2740,7 @@ sortedcontainers = "*"
|
|||||||
name = "trio-websocket"
|
name = "trio-websocket"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
description = "WebSocket library for Trio"
|
description = "WebSocket library for Trio"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2641,6 +2757,7 @@ wsproto = ">=0.14"
|
|||||||
name = "twine"
|
name = "twine"
|
||||||
version = "5.1.1"
|
version = "5.1.1"
|
||||||
description = "Collection of utilities for publishing packages on PyPI"
|
description = "Collection of utilities for publishing packages on PyPI"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2663,6 +2780,7 @@ urllib3 = ">=1.26.0"
|
|||||||
name = "typer"
|
name = "typer"
|
||||||
version = "0.12.5"
|
version = "0.12.5"
|
||||||
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
|
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2680,6 +2798,7 @@ typing-extensions = ">=3.7.4.3"
|
|||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.12.2"
|
version = "4.12.2"
|
||||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2691,6 +2810,7 @@ files = [
|
|||||||
name = "tzdata"
|
name = "tzdata"
|
||||||
version = "2024.1"
|
version = "2024.1"
|
||||||
description = "Provider of IANA time zone data"
|
description = "Provider of IANA time zone data"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2"
|
python-versions = ">=2"
|
||||||
files = [
|
files = [
|
||||||
@ -2702,6 +2822,7 @@ files = [
|
|||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2722,6 +2843,7 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
name = "uvicorn"
|
name = "uvicorn"
|
||||||
version = "0.30.6"
|
version = "0.30.6"
|
||||||
description = "The lightning-fast ASGI server."
|
description = "The lightning-fast ASGI server."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2741,6 +2863,7 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
|||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.26.3"
|
version = "20.26.3"
|
||||||
description = "Virtual Python Environment builder"
|
description = "Virtual Python Environment builder"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -2761,6 +2884,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
|
|||||||
name = "websocket-client"
|
name = "websocket-client"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
description = "WebSocket client for Python with low level API options"
|
description = "WebSocket client for Python with low level API options"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2777,6 +2901,7 @@ test = ["websockets"]
|
|||||||
name = "websockets"
|
name = "websockets"
|
||||||
version = "13.0.1"
|
version = "13.0.1"
|
||||||
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2872,6 +2997,7 @@ files = [
|
|||||||
name = "wheel"
|
name = "wheel"
|
||||||
version = "0.44.0"
|
version = "0.44.0"
|
||||||
description = "A built-package format for Python"
|
description = "A built-package format for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2886,6 +3012,7 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
|
|||||||
name = "wrapt"
|
name = "wrapt"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
description = "Module for decorators, wrappers and monkey patching."
|
description = "Module for decorators, wrappers and monkey patching."
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -2965,6 +3092,7 @@ files = [
|
|||||||
name = "wsproto"
|
name = "wsproto"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
description = "WebSockets state-machine based protocol implementation"
|
description = "WebSockets state-machine based protocol implementation"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
@ -2979,6 +3107,7 @@ h11 = ">=0.9.0,<1"
|
|||||||
name = "zipp"
|
name = "zipp"
|
||||||
version = "3.20.1"
|
version = "3.20.1"
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
@ -2997,4 +3126,4 @@ type = ["pytest-mypy"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "0bd98b6baa48d41ec50bfa0903d89005129211f6e429d7b62504ee880f8ba523"
|
content-hash = "7a8990e432a404802c3ace9a81c3c8c33cdd60596f26cdc38e2de424cb1126dd"
|
||||||
|
@ -59,7 +59,7 @@ httpx = ">=0.25.1,<1.0"
|
|||||||
twine = ">=4.0.0,<6.0"
|
twine = ">=4.0.0,<6.0"
|
||||||
tomlkit = ">=0.12.4,<1.0"
|
tomlkit = ">=0.12.4,<1.0"
|
||||||
lazy_loader = ">=0.4"
|
lazy_loader = ">=0.4"
|
||||||
reflex-chakra = ">=0.6.0a"
|
reflex-chakra = ">=0.6.0a6"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = ">=7.1.2,<8.0"
|
pytest = ">=7.1.2,<8.0"
|
||||||
|
@ -27,7 +27,7 @@ function AppWrap({children}) {
|
|||||||
|
|
||||||
export default function MyApp({ Component, pageProps }) {
|
export default function MyApp({ Component, pageProps }) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider defaultTheme={ defaultColorMode } storageKey="chakra-ui-color-mode" attribute="class">
|
<ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
|
||||||
<AppWrap>
|
<AppWrap>
|
||||||
<StateProvider>
|
<StateProvider>
|
||||||
<EventLoopProvider>
|
<EventLoopProvider>
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import { useColorMode as chakraUseColorMode } from "@chakra-ui/react";
|
|
||||||
import { useTheme } from "next-themes";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { ColorModeContext, defaultColorMode } from "/utils/context.js";
|
|
||||||
|
|
||||||
export default function ChakraColorModeProvider({ children }) {
|
|
||||||
const { theme, resolvedTheme, setTheme } = useTheme();
|
|
||||||
const { colorMode, toggleColorMode } = chakraUseColorMode();
|
|
||||||
const [resolvedColorMode, setResolvedColorMode] = useState(colorMode);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (colorMode != resolvedTheme) {
|
|
||||||
toggleColorMode();
|
|
||||||
}
|
|
||||||
setResolvedColorMode(resolvedTheme);
|
|
||||||
}, [theme, resolvedTheme]);
|
|
||||||
|
|
||||||
const rawColorMode = colorMode;
|
|
||||||
const setColorMode = (mode) => {
|
|
||||||
const allowedModes = ["light", "dark", "system"];
|
|
||||||
if (!allowedModes.includes(mode)) {
|
|
||||||
console.error(
|
|
||||||
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`
|
|
||||||
);
|
|
||||||
mode = defaultColorMode;
|
|
||||||
}
|
|
||||||
setTheme(mode);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ColorModeContext.Provider
|
|
||||||
value={{ rawColorMode, resolvedColorMode, toggleColorMode, setColorMode }}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</ColorModeContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
@ -132,6 +132,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 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
|
||||||
|
@ -9,6 +9,7 @@ import copy
|
|||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import io
|
import io
|
||||||
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
@ -1096,6 +1097,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
|||||||
if delta:
|
if delta:
|
||||||
# When the state is modified reset dirty status and emit the delta to the frontend.
|
# When the state is modified reset dirty status and emit the delta to the frontend.
|
||||||
state._clean()
|
state._clean()
|
||||||
|
print(dir(state.router))
|
||||||
await self.event_namespace.emit_update(
|
await self.event_namespace.emit_update(
|
||||||
update=StateUpdate(delta=delta),
|
update=StateUpdate(delta=delta),
|
||||||
sid=state.router.session.session_id,
|
sid=state.router.session.session_id,
|
||||||
@ -1531,8 +1533,9 @@ class EventNamespace(AsyncNamespace):
|
|||||||
sid: The Socket.IO session id.
|
sid: The Socket.IO session id.
|
||||||
data: The event data.
|
data: The event data.
|
||||||
"""
|
"""
|
||||||
|
fields = json.loads(data)
|
||||||
# Get the event.
|
# Get the event.
|
||||||
event = Event.parse_raw(data)
|
event = Event(**{k: v for k, v in fields.items() if k != "handler"})
|
||||||
|
|
||||||
self.token_to_sid[event.token] = sid
|
self.token_to_sid[event.token] = sid
|
||||||
self.sid_to_token[sid] = event.token
|
self.sid_to_token[sid] = event.token
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import typing
|
import typing
|
||||||
|
import warnings
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from functools import lru_cache, wraps
|
from functools import lru_cache, wraps
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
@ -169,6 +170,8 @@ ComponentStyle = Dict[
|
|||||||
]
|
]
|
||||||
ComponentChild = Union[types.PrimitiveType, Var, BaseComponent]
|
ComponentChild = Union[types.PrimitiveType, Var, BaseComponent]
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", message="fields may not start with an underscore")
|
||||||
|
|
||||||
|
|
||||||
class Component(BaseComponent, ABC):
|
class Component(BaseComponent, ABC):
|
||||||
"""A component with style, event trigger and other props."""
|
"""A component with style, event trigger and other props."""
|
||||||
@ -195,7 +198,7 @@ class Component(BaseComponent, ABC):
|
|||||||
class_name: Any = None
|
class_name: Any = None
|
||||||
|
|
||||||
# Special component props.
|
# Special component props.
|
||||||
special_props: Set[ImmutableVar] = set()
|
special_props: List[ImmutableVar] = []
|
||||||
|
|
||||||
# Whether the component should take the focus once the page is loaded
|
# Whether the component should take the focus once the page is loaded
|
||||||
autofocus: bool = False
|
autofocus: bool = False
|
||||||
@ -655,7 +658,7 @@ class Component(BaseComponent, ABC):
|
|||||||
"""
|
"""
|
||||||
# Create the base tag.
|
# Create the base tag.
|
||||||
tag = Tag(
|
tag = Tag(
|
||||||
name=self.tag if not self.alias else self.alias,
|
name=(self.tag if not self.alias else self.alias) or "",
|
||||||
special_props=self.special_props,
|
special_props=self.special_props,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2244,7 +2247,7 @@ class StatefulComponent(BaseComponent):
|
|||||||
Returns:
|
Returns:
|
||||||
The tag to render.
|
The tag to render.
|
||||||
"""
|
"""
|
||||||
return dict(Tag(name=self.tag))
|
return dict(Tag(name=self.tag or ""))
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
"""Represent the component in React.
|
"""Represent the component in React.
|
||||||
|
@ -247,9 +247,9 @@ class Upload(MemoizationLeaf):
|
|||||||
}
|
}
|
||||||
# The file input to use.
|
# The file input to use.
|
||||||
upload = Input.create(type="file")
|
upload = Input.create(type="file")
|
||||||
upload.special_props = {
|
upload.special_props = [
|
||||||
ImmutableVar(_var_name="{...getInputProps()}", _var_type=None)
|
ImmutableVar(_var_name="{...getInputProps()}", _var_type=None)
|
||||||
}
|
]
|
||||||
|
|
||||||
# The dropzone to use.
|
# The dropzone to use.
|
||||||
zone = Box.create(
|
zone = Box.create(
|
||||||
@ -257,9 +257,9 @@ class Upload(MemoizationLeaf):
|
|||||||
*children,
|
*children,
|
||||||
**{k: v for k, v in props.items() if k not in supported_props},
|
**{k: v for k, v in props.items() if k not in supported_props},
|
||||||
)
|
)
|
||||||
zone.special_props = {
|
zone.special_props = [
|
||||||
ImmutableVar(_var_name="{...getRootProps()}", _var_type=None)
|
ImmutableVar(_var_name="{...getRootProps()}", _var_type=None)
|
||||||
}
|
]
|
||||||
|
|
||||||
# Create the component.
|
# Create the component.
|
||||||
upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID)
|
upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py."""
|
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py."""
|
||||||
|
|
||||||
from typing import Set, Union
|
from typing import List, Union
|
||||||
|
|
||||||
from reflex.components.el.element import Element
|
from reflex.components.el.element import Element
|
||||||
from reflex.ivars.base import ImmutableVar
|
from reflex.ivars.base import ImmutableVar
|
||||||
@ -90,9 +90,9 @@ class StyleEl(Element): # noqa: E742
|
|||||||
|
|
||||||
media: Var[Union[str, int, bool]]
|
media: Var[Union[str, int, bool]]
|
||||||
|
|
||||||
special_props: Set[ImmutableVar] = {
|
special_props: List[ImmutableVar] = [
|
||||||
ImmutableVar.create_safe("suppressHydrationWarning")
|
ImmutableVar.create_safe("suppressHydrationWarning")
|
||||||
}
|
]
|
||||||
|
|
||||||
|
|
||||||
base = Base.create
|
base = Base.create
|
||||||
|
@ -195,17 +195,17 @@ class Markdown(Component):
|
|||||||
if tag not in self.component_map:
|
if tag not in self.component_map:
|
||||||
raise ValueError(f"No markdown component found for tag: {tag}.")
|
raise ValueError(f"No markdown component found for tag: {tag}.")
|
||||||
|
|
||||||
special_props = {_PROPS_IN_TAG}
|
special_props = [_PROPS_IN_TAG]
|
||||||
children = [_CHILDREN]
|
children = [_CHILDREN]
|
||||||
|
|
||||||
# For certain tags, the props from the markdown renderer are not actually valid for the component.
|
# For certain tags, the props from the markdown renderer are not actually valid for the component.
|
||||||
if tag in NO_PROPS_TAGS:
|
if tag in NO_PROPS_TAGS:
|
||||||
special_props = set()
|
special_props = []
|
||||||
|
|
||||||
# If the children are set as a prop, don't pass them as children.
|
# If the children are set as a prop, don't pass them as children.
|
||||||
children_prop = props.pop("children", None)
|
children_prop = props.pop("children", None)
|
||||||
if children_prop is not None:
|
if children_prop is not None:
|
||||||
special_props.add(
|
special_props.append(
|
||||||
ImmutableVar.create_safe(f"children={{{str(children_prop)}}}")
|
ImmutableVar.create_safe(f"children={{{str(children_prop)}}}")
|
||||||
)
|
)
|
||||||
children = []
|
children = []
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
"""Moment component for humanized date rendering."""
|
"""Moment component for humanized date rendering."""
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.components.component import Component, NoSSRComponent
|
from reflex.components.component import Component, NoSSRComponent
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
from reflex.utils.imports import ImportDict
|
from reflex.utils.imports import ImportDict
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
class MomentDelta(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class MomentDelta:
|
||||||
"""A delta used for add/subtract prop in Moment."""
|
"""A delta used for add/subtract prop in Moment."""
|
||||||
|
|
||||||
years: Optional[int]
|
years: Optional[int] = dataclasses.field(default=None)
|
||||||
quarters: Optional[int]
|
quarters: Optional[int] = dataclasses.field(default=None)
|
||||||
months: Optional[int]
|
months: Optional[int] = dataclasses.field(default=None)
|
||||||
weeks: Optional[int]
|
weeks: Optional[int] = dataclasses.field(default=None)
|
||||||
days: Optional[int]
|
days: Optional[int] = dataclasses.field(default=None)
|
||||||
hours: Optional[int]
|
hours: Optional[int] = dataclasses.field(default=None)
|
||||||
minutess: Optional[int]
|
minutess: Optional[int] = dataclasses.field(default=None)
|
||||||
seconds: Optional[int]
|
seconds: Optional[int] = dataclasses.field(default=None)
|
||||||
milliseconds: Optional[int]
|
milliseconds: Optional[int] = dataclasses.field(default=None)
|
||||||
|
|
||||||
|
|
||||||
class Moment(NoSSRComponent):
|
class Moment(NoSSRComponent):
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
# ------------------- DO NOT EDIT ----------------------
|
# ------------------- DO NOT EDIT ----------------------
|
||||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
|
import dataclasses
|
||||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||||
|
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.components.component import NoSSRComponent
|
from reflex.components.component import NoSSRComponent
|
||||||
from reflex.event import EventHandler, EventSpec
|
from reflex.event import EventHandler, EventSpec
|
||||||
from reflex.ivars.base import ImmutableVar
|
from reflex.ivars.base import ImmutableVar
|
||||||
@ -13,7 +13,8 @@ from reflex.style import Style
|
|||||||
from reflex.utils.imports import ImportDict
|
from reflex.utils.imports import ImportDict
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
class MomentDelta(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class MomentDelta:
|
||||||
years: Optional[int]
|
years: Optional[int]
|
||||||
quarters: Optional[int]
|
quarters: Optional[int]
|
||||||
months: Optional[int]
|
months: Optional[int]
|
||||||
|
@ -267,7 +267,7 @@ const extractPoints = (points) => {
|
|||||||
template_dict = LiteralVar.create({"layout": {"template": self.template}})
|
template_dict = LiteralVar.create({"layout": {"template": self.template}})
|
||||||
merge_dicts.append(template_dict.without_data())
|
merge_dicts.append(template_dict.without_data())
|
||||||
if merge_dicts:
|
if merge_dicts:
|
||||||
tag.special_props.add(
|
tag.special_props.append(
|
||||||
# Merge all dictionaries and spread the result over props.
|
# Merge all dictionaries and spread the result over props.
|
||||||
ImmutableVar.create_safe(
|
ImmutableVar.create_safe(
|
||||||
f"{{...mergician({str(figure)},"
|
f"{{...mergician({str(figure)},"
|
||||||
@ -276,5 +276,5 @@ const extractPoints = (points) => {
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Spread the figure dict over props, nothing to merge.
|
# Spread the figure dict over props, nothing to merge.
|
||||||
tag.special_props.add(ImmutableVar.create_safe(f"{{...{str(figure)}}}"))
|
tag.special_props.append(ImmutableVar.create_safe(f"{{...{str(figure)}}}"))
|
||||||
return tag
|
return tag
|
||||||
|
@ -23,3 +23,20 @@ class PropsBase(Base):
|
|||||||
return LiteralObjectVar.create(
|
return LiteralObjectVar.create(
|
||||||
{format.to_camel_case(key): value for key, value in self.dict().items()}
|
{format.to_camel_case(key): value for key, value in self.dict().items()}
|
||||||
).json()
|
).json()
|
||||||
|
|
||||||
|
def dict(self, *args, **kwargs):
|
||||||
|
"""Convert the object to a dictionary.
|
||||||
|
|
||||||
|
Keys will be converted to camelCase.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args: Arguments to pass to the parent class.
|
||||||
|
**kwargs: Keyword arguments to pass to the parent class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The object as a dictionary.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
format.to_camel_case(key): value
|
||||||
|
for key, value in super().dict(*args, **kwargs).items()
|
||||||
|
}
|
||||||
|
@ -55,6 +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 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
|
||||||
|
@ -262,26 +262,6 @@ class ThemePanel(RadixThemesComponent):
|
|||||||
"""
|
"""
|
||||||
return {"react": "useEffect"}
|
return {"react": "useEffect"}
|
||||||
|
|
||||||
def add_hooks(self) -> list[str]:
|
|
||||||
"""Add a hook on the ThemePanel to clear chakra-ui-color-mode.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The hooks to render.
|
|
||||||
"""
|
|
||||||
# The panel freezes the tab if the user color preference differs from the
|
|
||||||
# theme "appearance", so clear it out when theme panel is used.
|
|
||||||
return [
|
|
||||||
"""
|
|
||||||
useEffect(() => {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
window.onbeforeunload = () => {
|
|
||||||
localStorage.removeItem('chakra-ui-color-mode');
|
|
||||||
}
|
|
||||||
window.onbeforeunload();
|
|
||||||
}
|
|
||||||
}, [])"""
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class RadixThemesColorModeProvider(Component):
|
class RadixThemesColorModeProvider(Component):
|
||||||
"""Next-themes integration for radix themes components."""
|
"""Next-themes integration for radix themes components."""
|
||||||
|
@ -583,7 +583,6 @@ class Theme(RadixThemesComponent):
|
|||||||
|
|
||||||
class ThemePanel(RadixThemesComponent):
|
class ThemePanel(RadixThemesComponent):
|
||||||
def add_imports(self) -> dict[str, str]: ...
|
def add_imports(self) -> dict[str, str]: ...
|
||||||
def add_hooks(self) -> list[str]: ...
|
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
|
@ -9,6 +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 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
|
||||||
|
@ -171,12 +171,12 @@ class ToastProps(PropsBase):
|
|||||||
d["cancel"] = self.cancel
|
d["cancel"] = self.cancel
|
||||||
if isinstance(self.cancel, dict):
|
if isinstance(self.cancel, dict):
|
||||||
d["cancel"] = ToastAction(**self.cancel)
|
d["cancel"] = ToastAction(**self.cancel)
|
||||||
if "on_dismiss" in d:
|
if "onDismiss" in d:
|
||||||
d["on_dismiss"] = format.format_queue_events(
|
d["onDismiss"] = format.format_queue_events(
|
||||||
self.on_dismiss, _toast_callback_signature
|
self.on_dismiss, _toast_callback_signature
|
||||||
)
|
)
|
||||||
if "on_auto_close" in d:
|
if "onAutoClose" in d:
|
||||||
d["on_auto_close"] = format.format_queue_events(
|
d["onAutoClose"] = format.format_queue_events(
|
||||||
self.on_auto_close, _toast_callback_signature
|
self.on_auto_close, _toast_callback_signature
|
||||||
)
|
)
|
||||||
return d
|
return d
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
"""Tag to conditionally render components."""
|
"""Tag to conditionally render components."""
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass()
|
||||||
class CondTag(Tag):
|
class CondTag(Tag):
|
||||||
"""A conditional tag."""
|
"""A conditional tag."""
|
||||||
|
|
||||||
# The condition to determine which component to render.
|
# The condition to determine which component to render.
|
||||||
cond: Var[Any]
|
cond: Var[Any] = dataclasses.field(default_factory=lambda: LiteralVar.create(True))
|
||||||
|
|
||||||
# The code to render if the condition is true.
|
# The code to render if the condition is true.
|
||||||
true_value: Dict
|
true_value: Dict = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
# The code to render if the condition is false.
|
# The code to render if the condition is false.
|
||||||
false_value: Optional[Dict]
|
false_value: Optional[Dict] = None
|
||||||
|
@ -2,31 +2,36 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import inspect
|
import inspect
|
||||||
from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Type, Union, get_args
|
from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Type, Union, get_args
|
||||||
|
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.ivars.base import ImmutableVar
|
from reflex.ivars.base import ImmutableVar
|
||||||
from reflex.vars import Var
|
from reflex.ivars.sequence import LiteralArrayVar
|
||||||
|
from reflex.vars import Var, get_unique_variable_name
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass()
|
||||||
class IterTag(Tag):
|
class IterTag(Tag):
|
||||||
"""An iterator tag."""
|
"""An iterator tag."""
|
||||||
|
|
||||||
# The var to iterate over.
|
# The var to iterate over.
|
||||||
iterable: Var[List]
|
iterable: Var[List] = dataclasses.field(
|
||||||
|
default_factory=lambda: LiteralArrayVar.create([])
|
||||||
|
)
|
||||||
|
|
||||||
# The component render function for each item in the iterable.
|
# The component render function for each item in the iterable.
|
||||||
render_fn: Callable
|
render_fn: Callable = dataclasses.field(default_factory=lambda: lambda x: x)
|
||||||
|
|
||||||
# The name of the arg var.
|
# The name of the arg var.
|
||||||
arg_var_name: str
|
arg_var_name: str = dataclasses.field(default_factory=get_unique_variable_name)
|
||||||
|
|
||||||
# The name of the index var.
|
# The name of the index var.
|
||||||
index_var_name: str
|
index_var_name: str = dataclasses.field(default_factory=get_unique_variable_name)
|
||||||
|
|
||||||
def get_iterable_var_type(self) -> Type:
|
def get_iterable_var_type(self) -> Type:
|
||||||
"""Get the type of the iterable var.
|
"""Get the type of the iterable var.
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
"""Tag to conditionally match cases."""
|
"""Tag to conditionally match cases."""
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
|
from reflex.ivars.base import LiteralVar
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass()
|
||||||
class MatchTag(Tag):
|
class MatchTag(Tag):
|
||||||
"""A match tag."""
|
"""A match tag."""
|
||||||
|
|
||||||
# The condition to determine which case to match.
|
# The condition to determine which case to match.
|
||||||
cond: Var[Any]
|
cond: Var[Any] = dataclasses.field(default_factory=lambda: LiteralVar.create(True))
|
||||||
|
|
||||||
# The list of match cases to be matched.
|
# The list of match cases to be matched.
|
||||||
match_cases: List[Any]
|
match_cases: List[Any] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
# The catchall case to match.
|
# The catchall case to match.
|
||||||
default: Any
|
default: Any = dataclasses.field(default=LiteralVar.create(None))
|
||||||
|
@ -2,22 +2,23 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
import dataclasses
|
||||||
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.event import EventChain
|
from reflex.event import EventChain
|
||||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
from reflex.utils import format, types
|
from reflex.utils import format, types
|
||||||
|
|
||||||
|
|
||||||
class Tag(Base):
|
@dataclasses.dataclass()
|
||||||
|
class Tag:
|
||||||
"""A React tag."""
|
"""A React tag."""
|
||||||
|
|
||||||
# The name of the tag.
|
# The name of the tag.
|
||||||
name: str = ""
|
name: str = ""
|
||||||
|
|
||||||
# The props of the tag.
|
# The props of the tag.
|
||||||
props: Dict[str, Any] = {}
|
props: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
# The inner contents of the tag.
|
# The inner contents of the tag.
|
||||||
contents: str = ""
|
contents: str = ""
|
||||||
@ -26,25 +27,18 @@ class Tag(Base):
|
|||||||
args: Optional[Tuple[str, ...]] = None
|
args: Optional[Tuple[str, ...]] = None
|
||||||
|
|
||||||
# Special props that aren't key value pairs.
|
# Special props that aren't key value pairs.
|
||||||
special_props: Set[ImmutableVar] = set()
|
special_props: List[ImmutableVar] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
# The children components.
|
# The children components.
|
||||||
children: List[Any] = []
|
children: List[Any] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __post_init__(self):
|
||||||
"""Initialize the tag.
|
"""Post initialize the tag."""
|
||||||
|
object.__setattr__(
|
||||||
Args:
|
self,
|
||||||
*args: Args to initialize the tag.
|
"props",
|
||||||
**kwargs: Kwargs to initialize the tag.
|
{name: LiteralVar.create(value) for name, value in self.props.items()},
|
||||||
"""
|
)
|
||||||
# Convert any props to vars.
|
|
||||||
if "props" in kwargs:
|
|
||||||
kwargs["props"] = {
|
|
||||||
name: LiteralVar.create(value)
|
|
||||||
for name, value in kwargs["props"].items()
|
|
||||||
}
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def format_props(self) -> List:
|
def format_props(self) -> List:
|
||||||
"""Format the tag's props.
|
"""Format the tag's props.
|
||||||
@ -54,6 +48,29 @@ class Tag(Base):
|
|||||||
"""
|
"""
|
||||||
return format.format_props(*self.special_props, **self.props)
|
return format.format_props(*self.special_props, **self.props)
|
||||||
|
|
||||||
|
def set(self, **kwargs: Any):
|
||||||
|
"""Set the tag's fields.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
kwargs: The fields to set.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The tag with the fields
|
||||||
|
"""
|
||||||
|
for name, value in kwargs.items():
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Iterate over the tag's fields.
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Tuple[str, Any]: The field name and value.
|
||||||
|
"""
|
||||||
|
for field in dataclasses.fields(self):
|
||||||
|
yield field.name, getattr(self, field.name)
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -117,7 +117,9 @@ class Templates(SimpleNamespace):
|
|||||||
REFLEX_BUILD_POLL_URL = REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
REFLEX_BUILD_POLL_URL = REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
||||||
|
|
||||||
# The URL to fetch the generation's reflex code
|
# The URL to fetch the generation's reflex code
|
||||||
REFLEX_BUILD_CODE_URL = REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}"
|
REFLEX_BUILD_CODE_URL = (
|
||||||
|
REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
|
||||||
|
)
|
||||||
|
|
||||||
class Dirs(SimpleNamespace):
|
class Dirs(SimpleNamespace):
|
||||||
"""Folders used by the template system of Reflex."""
|
"""Folders used by the template system of Reflex."""
|
||||||
|
126
reflex/event.py
126
reflex/event.py
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import inspect
|
import inspect
|
||||||
import types
|
import types
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
@ -18,7 +19,6 @@ from typing import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
from reflex.ivars.function import FunctionStringVar, FunctionVar
|
from reflex.ivars.function import FunctionStringVar, FunctionVar
|
||||||
from reflex.ivars.object import ObjectVar
|
from reflex.ivars.object import ObjectVar
|
||||||
@ -33,7 +33,11 @@ except ImportError:
|
|||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
|
|
||||||
class Event(Base):
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class Event:
|
||||||
"""An event that describes any state change in the app."""
|
"""An event that describes any state change in the app."""
|
||||||
|
|
||||||
# The token to specify the client that the event is for.
|
# The token to specify the client that the event is for.
|
||||||
@ -43,10 +47,10 @@ class Event(Base):
|
|||||||
name: str
|
name: str
|
||||||
|
|
||||||
# The routing data where event occurred
|
# The routing data where event occurred
|
||||||
router_data: Dict[str, Any] = {}
|
router_data: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
# The event payload.
|
# The event payload.
|
||||||
payload: Dict[str, Any] = {}
|
payload: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def substate_token(self) -> str:
|
def substate_token(self) -> str:
|
||||||
@ -81,11 +85,15 @@ def background(fn):
|
|||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
class EventActionsMixin(Base):
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class EventActionsMixin:
|
||||||
"""Mixin for DOM event actions."""
|
"""Mixin for DOM event actions."""
|
||||||
|
|
||||||
# Whether to `preventDefault` or `stopPropagation` on the event.
|
# Whether to `preventDefault` or `stopPropagation` on the event.
|
||||||
event_actions: Dict[str, Union[bool, int]] = {}
|
event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stop_propagation(self):
|
def stop_propagation(self):
|
||||||
@ -94,8 +102,9 @@ class EventActionsMixin(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
New EventHandler-like with stopPropagation set to True.
|
New EventHandler-like with stopPropagation set to True.
|
||||||
"""
|
"""
|
||||||
return self.copy(
|
return dataclasses.replace(
|
||||||
update={"event_actions": {"stopPropagation": True, **self.event_actions}},
|
self,
|
||||||
|
event_actions={"stopPropagation": True, **self.event_actions},
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -105,8 +114,9 @@ class EventActionsMixin(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
New EventHandler-like with preventDefault set to True.
|
New EventHandler-like with preventDefault set to True.
|
||||||
"""
|
"""
|
||||||
return self.copy(
|
return dataclasses.replace(
|
||||||
update={"event_actions": {"preventDefault": True, **self.event_actions}},
|
self,
|
||||||
|
event_actions={"preventDefault": True, **self.event_actions},
|
||||||
)
|
)
|
||||||
|
|
||||||
def throttle(self, limit_ms: int):
|
def throttle(self, limit_ms: int):
|
||||||
@ -118,8 +128,9 @@ class EventActionsMixin(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
New EventHandler-like with throttle set to limit_ms.
|
New EventHandler-like with throttle set to limit_ms.
|
||||||
"""
|
"""
|
||||||
return self.copy(
|
return dataclasses.replace(
|
||||||
update={"event_actions": {"throttle": limit_ms, **self.event_actions}},
|
self,
|
||||||
|
event_actions={"throttle": limit_ms, **self.event_actions},
|
||||||
)
|
)
|
||||||
|
|
||||||
def debounce(self, delay_ms: int):
|
def debounce(self, delay_ms: int):
|
||||||
@ -131,26 +142,25 @@ class EventActionsMixin(Base):
|
|||||||
Returns:
|
Returns:
|
||||||
New EventHandler-like with debounce set to delay_ms.
|
New EventHandler-like with debounce set to delay_ms.
|
||||||
"""
|
"""
|
||||||
return self.copy(
|
return dataclasses.replace(
|
||||||
update={"event_actions": {"debounce": delay_ms, **self.event_actions}},
|
self,
|
||||||
|
event_actions={"debounce": delay_ms, **self.event_actions},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
class EventHandler(EventActionsMixin):
|
class EventHandler(EventActionsMixin):
|
||||||
"""An event handler responds to an event to update the state."""
|
"""An event handler responds to an event to update the state."""
|
||||||
|
|
||||||
# The function to call in response to the event.
|
# The function to call in response to the event.
|
||||||
fn: Any
|
fn: Any = dataclasses.field(default=None)
|
||||||
|
|
||||||
# The full name of the state class this event handler is attached to.
|
# The full name of the state class this event handler is attached to.
|
||||||
# Empty string means this event handler is a server side event.
|
# Empty string means this event handler is a server side event.
|
||||||
state_full_name: str = ""
|
state_full_name: str = dataclasses.field(default="")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""The Pydantic config."""
|
|
||||||
|
|
||||||
# Needed to allow serialization of Callable.
|
|
||||||
frozen = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __class_getitem__(cls, args_spec: str) -> Annotated:
|
def __class_getitem__(cls, args_spec: str) -> Annotated:
|
||||||
@ -215,6 +225,10 @@ class EventHandler(EventActionsMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
class EventSpec(EventActionsMixin):
|
class EventSpec(EventActionsMixin):
|
||||||
"""An event specification.
|
"""An event specification.
|
||||||
|
|
||||||
@ -223,19 +237,37 @@ class EventSpec(EventActionsMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# The event handler.
|
# The event handler.
|
||||||
handler: EventHandler
|
handler: EventHandler = dataclasses.field(default=None) # type: ignore
|
||||||
|
|
||||||
# The handler on the client to process event.
|
# The handler on the client to process event.
|
||||||
client_handler_name: str = ""
|
client_handler_name: str = dataclasses.field(default="")
|
||||||
|
|
||||||
# The arguments to pass to the function.
|
# The arguments to pass to the function.
|
||||||
args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...] = ()
|
args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...] = dataclasses.field(
|
||||||
|
default_factory=tuple
|
||||||
|
)
|
||||||
|
|
||||||
class Config:
|
def __init__(
|
||||||
"""The Pydantic config."""
|
self,
|
||||||
|
handler: EventHandler,
|
||||||
|
event_actions: Dict[str, Union[bool, int]] | None = None,
|
||||||
|
client_handler_name: str = "",
|
||||||
|
args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...] = tuple(),
|
||||||
|
):
|
||||||
|
"""Initialize an EventSpec.
|
||||||
|
|
||||||
# Required to allow tuple fields.
|
Args:
|
||||||
frozen = True
|
event_actions: The event actions.
|
||||||
|
handler: The event handler.
|
||||||
|
client_handler_name: The client handler name.
|
||||||
|
args: The arguments to pass to the function.
|
||||||
|
"""
|
||||||
|
if event_actions is None:
|
||||||
|
event_actions = {}
|
||||||
|
object.__setattr__(self, "event_actions", event_actions)
|
||||||
|
object.__setattr__(self, "handler", handler)
|
||||||
|
object.__setattr__(self, "client_handler_name", client_handler_name)
|
||||||
|
object.__setattr__(self, "args", args or tuple())
|
||||||
|
|
||||||
def with_args(
|
def with_args(
|
||||||
self, args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...]
|
self, args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...]
|
||||||
@ -286,6 +318,9 @@ class EventSpec(EventActionsMixin):
|
|||||||
return self.with_args(self.args + new_payload)
|
return self.with_args(self.args + new_payload)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
class CallableEventSpec(EventSpec):
|
class CallableEventSpec(EventSpec):
|
||||||
"""Decorate an EventSpec-returning function to act as both a EventSpec and a function.
|
"""Decorate an EventSpec-returning function to act as both a EventSpec and a function.
|
||||||
|
|
||||||
@ -305,10 +340,13 @@ class CallableEventSpec(EventSpec):
|
|||||||
if fn is not None:
|
if fn is not None:
|
||||||
default_event_spec = fn()
|
default_event_spec = fn()
|
||||||
super().__init__(
|
super().__init__(
|
||||||
fn=fn, # type: ignore
|
event_actions=default_event_spec.event_actions,
|
||||||
**default_event_spec.dict(),
|
client_handler_name=default_event_spec.client_handler_name,
|
||||||
|
args=default_event_spec.args,
|
||||||
|
handler=default_event_spec.handler,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
object.__setattr__(self, "fn", fn)
|
||||||
else:
|
else:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
@ -332,12 +370,16 @@ class CallableEventSpec(EventSpec):
|
|||||||
return self.fn(*args, **kwargs)
|
return self.fn(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
class EventChain(EventActionsMixin):
|
class EventChain(EventActionsMixin):
|
||||||
"""Container for a chain of events that will be executed in order."""
|
"""Container for a chain of events that will be executed in order."""
|
||||||
|
|
||||||
events: List[EventSpec]
|
events: List[EventSpec] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
args_spec: Optional[Callable]
|
args_spec: Optional[Callable] = dataclasses.field(default=None)
|
||||||
|
|
||||||
|
|
||||||
# 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.
|
||||||
@ -345,14 +387,22 @@ stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
|
|||||||
prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
|
prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
|
||||||
|
|
||||||
|
|
||||||
class Target(Base):
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class Target:
|
||||||
"""A Javascript event target."""
|
"""A Javascript event target."""
|
||||||
|
|
||||||
checked: bool = False
|
checked: bool = False
|
||||||
value: Any = None
|
value: Any = None
|
||||||
|
|
||||||
|
|
||||||
class FrontendEvent(Base):
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class FrontendEvent:
|
||||||
"""A Javascript event."""
|
"""A Javascript event."""
|
||||||
|
|
||||||
target: Target = Target()
|
target: Target = Target()
|
||||||
@ -360,7 +410,11 @@ class FrontendEvent(Base):
|
|||||||
value: Any = None
|
value: Any = None
|
||||||
|
|
||||||
|
|
||||||
class FileUpload(Base):
|
@dataclasses.dataclass(
|
||||||
|
init=True,
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class FileUpload:
|
||||||
"""Class to represent a file upload."""
|
"""Class to represent a file upload."""
|
||||||
|
|
||||||
upload_id: Optional[str] = None
|
upload_id: Optional[str] = None
|
||||||
|
@ -421,6 +421,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|||||||
if issubclass(output, (ObjectVar, Base)):
|
if issubclass(output, (ObjectVar, Base)):
|
||||||
return ToObjectOperation.create(self, var_type or dict)
|
return ToObjectOperation.create(self, var_type or dict)
|
||||||
|
|
||||||
|
if dataclasses.is_dataclass(output):
|
||||||
|
return ToObjectOperation.create(self, var_type or dict)
|
||||||
|
|
||||||
if issubclass(output, FunctionVar):
|
if issubclass(output, FunctionVar):
|
||||||
# if fixed_type is not None and not issubclass(fixed_type, Callable):
|
# if fixed_type is not None and not issubclass(fixed_type, Callable):
|
||||||
# raise TypeError(
|
# raise TypeError(
|
||||||
@ -479,7 +482,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|||||||
):
|
):
|
||||||
return self.to(NumberVar, self._var_type)
|
return self.to(NumberVar, self._var_type)
|
||||||
|
|
||||||
if all(inspect.isclass(t) and issubclass(t, Base) for t in inner_types):
|
if all(
|
||||||
|
inspect.isclass(t)
|
||||||
|
and (issubclass(t, Base) or dataclasses.is_dataclass(t))
|
||||||
|
for t in inner_types
|
||||||
|
):
|
||||||
return self.to(ObjectVar, self._var_type)
|
return self.to(ObjectVar, self._var_type)
|
||||||
|
|
||||||
return self.to(ObjectVar, self._var_type)
|
return self.to(ObjectVar, self._var_type)
|
||||||
@ -982,6 +989,16 @@ class LiteralVar(ImmutableVar):
|
|||||||
)
|
)
|
||||||
return LiteralVar.create(serialized_value, _var_data=_var_data)
|
return LiteralVar.create(serialized_value, _var_data=_var_data)
|
||||||
|
|
||||||
|
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
||||||
|
return LiteralObjectVar.create(
|
||||||
|
{
|
||||||
|
k: (None if callable(v) else v)
|
||||||
|
for k, v in dataclasses.asdict(value).items()
|
||||||
|
},
|
||||||
|
_var_type=type(value),
|
||||||
|
_var_data=_var_data,
|
||||||
|
)
|
||||||
|
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
|
f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
@ -14,6 +15,7 @@ if TYPE_CHECKING:
|
|||||||
from reflex.app import App
|
from reflex.app import App
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(init=True)
|
||||||
class HydrateMiddleware(Middleware):
|
class HydrateMiddleware(Middleware):
|
||||||
"""Middleware to handle initial app hydration."""
|
"""Middleware to handle initial app hydration."""
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC
|
from abc import ABC, abstractmethod
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.event import Event
|
from reflex.event import Event
|
||||||
from reflex.state import BaseState, StateUpdate
|
from reflex.state import BaseState, StateUpdate
|
||||||
|
|
||||||
@ -13,9 +12,10 @@ if TYPE_CHECKING:
|
|||||||
from reflex.app import App
|
from reflex.app import App
|
||||||
|
|
||||||
|
|
||||||
class Middleware(Base, ABC):
|
class Middleware(ABC):
|
||||||
"""Middleware to preprocess and postprocess requests."""
|
"""Middleware to preprocess and postprocess requests."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
async def preprocess(
|
async def preprocess(
|
||||||
self, app: App, state: BaseState, event: Event
|
self, app: App, state: BaseState, event: Event
|
||||||
) -> Optional[StateUpdate]:
|
) -> Optional[StateUpdate]:
|
||||||
|
131
reflex/state.py
131
reflex/state.py
@ -5,8 +5,10 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
|
import dataclasses
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
@ -83,13 +85,15 @@ var = immutable_computed_var
|
|||||||
TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
|
TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
|
||||||
|
|
||||||
|
|
||||||
class HeaderData(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class HeaderData:
|
||||||
"""An object containing headers data."""
|
"""An object containing headers data."""
|
||||||
|
|
||||||
host: str = ""
|
host: str = ""
|
||||||
origin: str = ""
|
origin: str = ""
|
||||||
upgrade: str = ""
|
upgrade: str = ""
|
||||||
connection: str = ""
|
connection: str = ""
|
||||||
|
cookie: str = ""
|
||||||
pragma: str = ""
|
pragma: str = ""
|
||||||
cache_control: str = ""
|
cache_control: str = ""
|
||||||
user_agent: str = ""
|
user_agent: str = ""
|
||||||
@ -105,13 +109,16 @@ class HeaderData(Base):
|
|||||||
Args:
|
Args:
|
||||||
router_data: the router_data dict.
|
router_data: the router_data dict.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
|
||||||
if router_data:
|
if router_data:
|
||||||
for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items():
|
for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items():
|
||||||
setattr(self, format.to_snake_case(k), v)
|
object.__setattr__(self, format.to_snake_case(k), v)
|
||||||
|
else:
|
||||||
|
for k in dataclasses.fields(self):
|
||||||
|
object.__setattr__(self, k.name, "")
|
||||||
|
|
||||||
|
|
||||||
class PageData(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class PageData:
|
||||||
"""An object containing page data."""
|
"""An object containing page data."""
|
||||||
|
|
||||||
host: str = "" # repeated with self.headers.origin (remove or keep the duplicate?)
|
host: str = "" # repeated with self.headers.origin (remove or keep the duplicate?)
|
||||||
@ -119,7 +126,7 @@ class PageData(Base):
|
|||||||
raw_path: str = ""
|
raw_path: str = ""
|
||||||
full_path: str = ""
|
full_path: str = ""
|
||||||
full_raw_path: str = ""
|
full_raw_path: str = ""
|
||||||
params: dict = {}
|
params: dict = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
def __init__(self, router_data: Optional[dict] = None):
|
def __init__(self, router_data: Optional[dict] = None):
|
||||||
"""Initalize the PageData object based on router_data.
|
"""Initalize the PageData object based on router_data.
|
||||||
@ -127,17 +134,34 @@ class PageData(Base):
|
|||||||
Args:
|
Args:
|
||||||
router_data: the router_data dict.
|
router_data: the router_data dict.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
|
||||||
if router_data:
|
if router_data:
|
||||||
self.host = router_data.get(constants.RouteVar.HEADERS, {}).get("origin")
|
object.__setattr__(
|
||||||
self.path = router_data.get(constants.RouteVar.PATH, "")
|
self,
|
||||||
self.raw_path = router_data.get(constants.RouteVar.ORIGIN, "")
|
"host",
|
||||||
self.full_path = f"{self.host}{self.path}"
|
router_data.get(constants.RouteVar.HEADERS, {}).get("origin", ""),
|
||||||
self.full_raw_path = f"{self.host}{self.raw_path}"
|
)
|
||||||
self.params = router_data.get(constants.RouteVar.QUERY, {})
|
object.__setattr__(
|
||||||
|
self, "path", router_data.get(constants.RouteVar.PATH, "")
|
||||||
|
)
|
||||||
|
object.__setattr__(
|
||||||
|
self, "raw_path", router_data.get(constants.RouteVar.ORIGIN, "")
|
||||||
|
)
|
||||||
|
object.__setattr__(self, "full_path", f"{self.host}{self.path}")
|
||||||
|
object.__setattr__(self, "full_raw_path", f"{self.host}{self.raw_path}")
|
||||||
|
object.__setattr__(
|
||||||
|
self, "params", router_data.get(constants.RouteVar.QUERY, {})
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
object.__setattr__(self, "host", "")
|
||||||
|
object.__setattr__(self, "path", "")
|
||||||
|
object.__setattr__(self, "raw_path", "")
|
||||||
|
object.__setattr__(self, "full_path", "")
|
||||||
|
object.__setattr__(self, "full_raw_path", "")
|
||||||
|
object.__setattr__(self, "params", {})
|
||||||
|
|
||||||
|
|
||||||
class SessionData(Base):
|
@dataclasses.dataclass(frozen=True, init=False)
|
||||||
|
class SessionData:
|
||||||
"""An object containing session data."""
|
"""An object containing session data."""
|
||||||
|
|
||||||
client_token: str = ""
|
client_token: str = ""
|
||||||
@ -150,19 +174,24 @@ class SessionData(Base):
|
|||||||
Args:
|
Args:
|
||||||
router_data: the router_data dict.
|
router_data: the router_data dict.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
|
||||||
if router_data:
|
if router_data:
|
||||||
self.client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
|
client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
|
||||||
self.client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
|
client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
|
||||||
self.session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
|
session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
|
||||||
|
else:
|
||||||
|
client_token = client_ip = session_id = ""
|
||||||
|
object.__setattr__(self, "client_token", client_token)
|
||||||
|
object.__setattr__(self, "client_ip", client_ip)
|
||||||
|
object.__setattr__(self, "session_id", session_id)
|
||||||
|
|
||||||
|
|
||||||
class RouterData(Base):
|
@dataclasses.dataclass(frozen=True, init=False)
|
||||||
|
class RouterData:
|
||||||
"""An object containing RouterData."""
|
"""An object containing RouterData."""
|
||||||
|
|
||||||
session: SessionData = SessionData()
|
session: SessionData = dataclasses.field(default_factory=SessionData)
|
||||||
headers: HeaderData = HeaderData()
|
headers: HeaderData = dataclasses.field(default_factory=HeaderData)
|
||||||
page: PageData = PageData()
|
page: PageData = dataclasses.field(default_factory=PageData)
|
||||||
|
|
||||||
def __init__(self, router_data: Optional[dict] = None):
|
def __init__(self, router_data: Optional[dict] = None):
|
||||||
"""Initialize the RouterData object.
|
"""Initialize the RouterData object.
|
||||||
@ -170,10 +199,30 @@ class RouterData(Base):
|
|||||||
Args:
|
Args:
|
||||||
router_data: the router_data dict.
|
router_data: the router_data dict.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
object.__setattr__(self, "session", SessionData(router_data))
|
||||||
self.session = SessionData(router_data)
|
object.__setattr__(self, "headers", HeaderData(router_data))
|
||||||
self.headers = HeaderData(router_data)
|
object.__setattr__(self, "page", PageData(router_data))
|
||||||
self.page = PageData(router_data)
|
|
||||||
|
def toJson(self) -> str:
|
||||||
|
"""Convert the object to a JSON string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The JSON string.
|
||||||
|
"""
|
||||||
|
return json.dumps(dataclasses.asdict(self))
|
||||||
|
|
||||||
|
|
||||||
|
@serializer
|
||||||
|
def serialize_routerdata(value: RouterData) -> str:
|
||||||
|
"""Serialize a RouterData instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The RouterData to serialize.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The serialized RouterData.
|
||||||
|
"""
|
||||||
|
return value.toJson()
|
||||||
|
|
||||||
|
|
||||||
def _no_chain_background_task(
|
def _no_chain_background_task(
|
||||||
@ -249,10 +298,11 @@ def _split_substate_key(substate_key: str) -> tuple[str, str]:
|
|||||||
return token, state_name
|
return token, state_name
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(frozen=True, init=False)
|
||||||
class EventHandlerSetVar(EventHandler):
|
class EventHandlerSetVar(EventHandler):
|
||||||
"""A special event handler to wrap setvar functionality."""
|
"""A special event handler to wrap setvar functionality."""
|
||||||
|
|
||||||
state_cls: Type[BaseState]
|
state_cls: Type[BaseState] = dataclasses.field(init=False)
|
||||||
|
|
||||||
def __init__(self, state_cls: Type[BaseState]):
|
def __init__(self, state_cls: Type[BaseState]):
|
||||||
"""Initialize the EventHandlerSetVar.
|
"""Initialize the EventHandlerSetVar.
|
||||||
@ -263,8 +313,8 @@ class EventHandlerSetVar(EventHandler):
|
|||||||
super().__init__(
|
super().__init__(
|
||||||
fn=type(self).setvar,
|
fn=type(self).setvar,
|
||||||
state_full_name=state_cls.get_full_name(),
|
state_full_name=state_cls.get_full_name(),
|
||||||
state_cls=state_cls, # type: ignore
|
|
||||||
)
|
)
|
||||||
|
object.__setattr__(self, "state_cls", state_cls)
|
||||||
|
|
||||||
def setvar(self, var_name: str, value: Any):
|
def setvar(self, var_name: str, value: Any):
|
||||||
"""Set the state variable to the value of the event.
|
"""Set the state variable to the value of the event.
|
||||||
@ -1826,8 +1876,13 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
self.dirty_vars.update(self._always_dirty_computed_vars)
|
self.dirty_vars.update(self._always_dirty_computed_vars)
|
||||||
self._mark_dirty()
|
self._mark_dirty()
|
||||||
|
|
||||||
|
def dictify(value: Any):
|
||||||
|
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
||||||
|
return dataclasses.asdict(value)
|
||||||
|
return value
|
||||||
|
|
||||||
base_vars = {
|
base_vars = {
|
||||||
prop_name: self.get_value(getattr(self, prop_name))
|
prop_name: dictify(self.get_value(getattr(self, prop_name)))
|
||||||
for prop_name in self.base_vars
|
for prop_name in self.base_vars
|
||||||
}
|
}
|
||||||
if initial and include_computed:
|
if initial and include_computed:
|
||||||
@ -1907,9 +1962,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
EventHandlerSetVar.update_forward_refs()
|
|
||||||
|
|
||||||
|
|
||||||
class State(BaseState):
|
class State(BaseState):
|
||||||
"""The app Base State."""
|
"""The app Base State."""
|
||||||
|
|
||||||
@ -2341,18 +2393,29 @@ class StateProxy(wrapt.ObjectProxy):
|
|||||||
self._self_mutable = original_mutable
|
self._self_mutable = original_mutable
|
||||||
|
|
||||||
|
|
||||||
class StateUpdate(Base):
|
@dataclasses.dataclass(
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
class StateUpdate:
|
||||||
"""A state update sent to the frontend."""
|
"""A state update sent to the frontend."""
|
||||||
|
|
||||||
# The state delta.
|
# The state delta.
|
||||||
delta: Delta = {}
|
delta: Delta = dataclasses.field(default_factory=dict)
|
||||||
|
|
||||||
# Events to be added to the event queue.
|
# Events to be added to the event queue.
|
||||||
events: List[Event] = []
|
events: List[Event] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
# Whether this is the final state update for the event.
|
# Whether this is the final state update for the event.
|
||||||
final: bool = True
|
final: bool = True
|
||||||
|
|
||||||
|
def json(self) -> str:
|
||||||
|
"""Convert the state update to a JSON string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The state update as a JSON string.
|
||||||
|
"""
|
||||||
|
return json.dumps(dataclasses.asdict(self))
|
||||||
|
|
||||||
|
|
||||||
class StateManager(Base, ABC):
|
class StateManager(Base, ABC):
|
||||||
"""A class to manage many client states."""
|
"""A class to manage many client states."""
|
||||||
|
@ -290,7 +290,6 @@ def _format_emotion_style_pseudo_selector(key: str) -> str:
|
|||||||
"""
|
"""
|
||||||
prefix = None
|
prefix = None
|
||||||
if key.startswith("_"):
|
if key.startswith("_"):
|
||||||
# Handle pseudo selectors in chakra style format.
|
|
||||||
prefix = "&:"
|
prefix = "&:"
|
||||||
key = key[1:]
|
key = key[1:]
|
||||||
if key.startswith(":"):
|
if key.startswith(":"):
|
||||||
|
@ -91,3 +91,7 @@ class EventFnArgMismatch(ReflexError, TypeError):
|
|||||||
|
|
||||||
class DynamicRouteArgShadowsStateVar(ReflexError, NameError):
|
class DynamicRouteArgShadowsStateVar(ReflexError, NameError):
|
||||||
"""Raised when a dynamic route arg shadows a state var."""
|
"""Raised when a dynamic route arg shadows a state var."""
|
||||||
|
|
||||||
|
|
||||||
|
class GeneratedCodeHasNoFunctionDefs(ReflexError):
|
||||||
|
"""Raised when refactored code generated with flexgen has no functions defined."""
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -623,6 +624,14 @@ def format_state(value: Any, key: Optional[str] = None) -> Any:
|
|||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
return {k: format_state(v, k) for k, v in value.items()}
|
return {k: format_state(v, k) for k, v in value.items()}
|
||||||
|
|
||||||
|
# Hand dataclasses.
|
||||||
|
if dataclasses.is_dataclass(value):
|
||||||
|
if isinstance(value, type):
|
||||||
|
raise TypeError(
|
||||||
|
f"Cannot format state of type {type(value)}. Please provide an instance of the dataclass."
|
||||||
|
)
|
||||||
|
return {k: format_state(v, k) for k, v in dataclasses.asdict(value).items()}
|
||||||
|
|
||||||
# Handle lists, sets, typles.
|
# Handle lists, sets, typles.
|
||||||
if isinstance(value, types.StateIterBases):
|
if isinstance(value, types.StateIterBases):
|
||||||
return [format_state(v) for v in value]
|
return [format_state(v) for v in value]
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, List, Optional, Tuple, Union
|
from typing import DefaultDict, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from reflex.base import Base
|
|
||||||
|
|
||||||
|
|
||||||
def merge_imports(
|
def merge_imports(
|
||||||
@ -19,12 +18,22 @@ def merge_imports(
|
|||||||
Returns:
|
Returns:
|
||||||
The merged import dicts.
|
The merged import dicts.
|
||||||
"""
|
"""
|
||||||
all_imports = defaultdict(list)
|
all_imports: DefaultDict[str, List[ImportVar]] = defaultdict(list)
|
||||||
for import_dict in imports:
|
for import_dict in imports:
|
||||||
for lib, fields in (
|
for lib, fields in (
|
||||||
import_dict if isinstance(import_dict, tuple) else import_dict.items()
|
import_dict if isinstance(import_dict, tuple) else import_dict.items()
|
||||||
):
|
):
|
||||||
all_imports[lib].extend(fields)
|
if isinstance(fields, (list, tuple, set)):
|
||||||
|
all_imports[lib].extend(
|
||||||
|
(
|
||||||
|
ImportVar(field) if isinstance(field, str) else field
|
||||||
|
for field in fields
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
all_imports[lib].append(
|
||||||
|
ImportVar(fields) if isinstance(fields, str) else fields
|
||||||
|
)
|
||||||
return all_imports
|
return all_imports
|
||||||
|
|
||||||
|
|
||||||
@ -75,7 +84,8 @@ def collapse_imports(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ImportVar(Base):
|
@dataclasses.dataclass(order=True, frozen=True)
|
||||||
|
class ImportVar:
|
||||||
"""An import var."""
|
"""An import var."""
|
||||||
|
|
||||||
# The name of the import tag.
|
# The name of the import tag.
|
||||||
@ -111,73 +121,6 @@ class ImportVar(Base):
|
|||||||
else:
|
else:
|
||||||
return self.tag or ""
|
return self.tag or ""
|
||||||
|
|
||||||
def __lt__(self, other: ImportVar) -> bool:
|
|
||||||
"""Compare two ImportVar objects.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other ImportVar object to compare.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Whether this ImportVar object is less than the other.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
self.tag,
|
|
||||||
self.is_default,
|
|
||||||
self.alias,
|
|
||||||
self.install,
|
|
||||||
self.render,
|
|
||||||
self.transpile,
|
|
||||||
) < (
|
|
||||||
other.tag,
|
|
||||||
other.is_default,
|
|
||||||
other.alias,
|
|
||||||
other.install,
|
|
||||||
other.render,
|
|
||||||
other.transpile,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __eq__(self, other: ImportVar) -> bool:
|
|
||||||
"""Check if two ImportVar objects are equal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
other: The other ImportVar object to compare.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Whether the two ImportVar objects are equal.
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
self.tag,
|
|
||||||
self.is_default,
|
|
||||||
self.alias,
|
|
||||||
self.install,
|
|
||||||
self.render,
|
|
||||||
self.transpile,
|
|
||||||
) == (
|
|
||||||
other.tag,
|
|
||||||
other.is_default,
|
|
||||||
other.alias,
|
|
||||||
other.install,
|
|
||||||
other.render,
|
|
||||||
other.transpile,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
"""Hash the ImportVar object.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The hash of the ImportVar object.
|
|
||||||
"""
|
|
||||||
return hash(
|
|
||||||
(
|
|
||||||
self.tag,
|
|
||||||
self.is_default,
|
|
||||||
self.alias,
|
|
||||||
self.install,
|
|
||||||
self.render,
|
|
||||||
self.transpile,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
|
ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
|
||||||
ImportDict = Dict[str, ImportTypes]
|
ImportDict = Dict[str, ImportTypes]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import functools
|
import functools
|
||||||
import glob
|
import glob
|
||||||
import importlib
|
import importlib
|
||||||
@ -15,7 +16,7 @@ import shutil
|
|||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import time
|
||||||
import zipfile
|
import zipfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fileinput import FileInput
|
from fileinput import FileInput
|
||||||
@ -32,17 +33,18 @@ from redis import exceptions
|
|||||||
from redis.asyncio import Redis
|
from redis.asyncio import Redis
|
||||||
|
|
||||||
from reflex import constants, model
|
from reflex import constants, model
|
||||||
from reflex.base import Base
|
|
||||||
from reflex.compiler import templates
|
from reflex.compiler import templates
|
||||||
from reflex.config import Config, get_config
|
from reflex.config import Config, get_config
|
||||||
from reflex.utils import console, net, path_ops, processes
|
from reflex.utils import console, net, path_ops, processes
|
||||||
|
from reflex.utils.exceptions import GeneratedCodeHasNoFunctionDefs
|
||||||
from reflex.utils.format import format_library_name
|
from reflex.utils.format import format_library_name
|
||||||
from reflex.utils.registry import _get_best_registry
|
from reflex.utils.registry import _get_best_registry
|
||||||
|
|
||||||
CURRENTLY_INSTALLING_NODE = False
|
CURRENTLY_INSTALLING_NODE = False
|
||||||
|
|
||||||
|
|
||||||
class Template(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class Template:
|
||||||
"""A template for a Reflex app."""
|
"""A template for a Reflex app."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
@ -51,7 +53,8 @@ class Template(Base):
|
|||||||
demo_url: str
|
demo_url: str
|
||||||
|
|
||||||
|
|
||||||
class CpuInfo(Base):
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
class CpuInfo:
|
||||||
"""Model to save cpu info."""
|
"""Model to save cpu info."""
|
||||||
|
|
||||||
manufacturer_id: Optional[str]
|
manufacturer_id: Optional[str]
|
||||||
@ -1278,7 +1281,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
tp["name"]: Template.parse_obj(tp)
|
tp["name"]: Template(**tp)
|
||||||
for tp in templates_data
|
for tp in templates_data
|
||||||
if not tp["hidden"] and tp["code_url"] is not None
|
if not tp["hidden"] and tp["code_url"] is not None
|
||||||
}
|
}
|
||||||
@ -1435,19 +1438,37 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash:
|
|||||||
Args:
|
Args:
|
||||||
app_name: The name of the app.
|
app_name: The name of the app.
|
||||||
generation_hash: The generation hash from reflex.build.
|
generation_hash: The generation hash from reflex.build.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GeneratedCodeHasNoFunctionDefs: If the fetched code has no function definitions
|
||||||
|
(the refactored reflex code is expected to have at least one root function defined).
|
||||||
"""
|
"""
|
||||||
# Download the reflex code for the generation.
|
# Download the reflex code for the generation.
|
||||||
resp = net.get(
|
url = constants.Templates.REFLEX_BUILD_CODE_URL.format(
|
||||||
constants.Templates.REFLEX_BUILD_CODE_URL.format(
|
generation_hash=generation_hash
|
||||||
generation_hash=generation_hash
|
)
|
||||||
|
resp = net.get(url)
|
||||||
|
while resp.status_code == httpx.codes.SERVICE_UNAVAILABLE:
|
||||||
|
console.debug("Waiting for the code to be generated...")
|
||||||
|
time.sleep(1)
|
||||||
|
resp = net.get(url)
|
||||||
|
resp.raise_for_status()
|
||||||
|
|
||||||
|
# Determine the name of the last function, which renders the generated code.
|
||||||
|
defined_funcs = re.findall(r"def ([a-zA-Z_]+)\(", resp.text)
|
||||||
|
if not defined_funcs:
|
||||||
|
raise GeneratedCodeHasNoFunctionDefs(
|
||||||
|
f"No function definitions found in generated code from {url!r}."
|
||||||
)
|
)
|
||||||
).raise_for_status()
|
render_func_name = defined_funcs[-1]
|
||||||
|
|
||||||
def replace_content(_match):
|
def replace_content(_match):
|
||||||
return "\n".join(
|
return "\n".join(
|
||||||
[
|
[
|
||||||
"def index() -> rx.Component:",
|
resp.text,
|
||||||
textwrap.indent("return " + resp.text, " "),
|
"",
|
||||||
|
"" "def index() -> rx.Component:",
|
||||||
|
f" return {render_func_name}()",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
],
|
],
|
||||||
|
@ -903,7 +903,13 @@ class PyiGenerator:
|
|||||||
# construct the import statement and handle special cases for aliases
|
# construct the import statement and handle special cases for aliases
|
||||||
sub_mod_attrs_imports = [
|
sub_mod_attrs_imports = [
|
||||||
f"from .{path} import {mod if not isinstance(mod, tuple) else mod[0]} as {mod if not isinstance(mod, tuple) else mod[1]}"
|
f"from .{path} import {mod if not isinstance(mod, tuple) else mod[0]} as {mod if not isinstance(mod, tuple) else mod[1]}"
|
||||||
+ (" # type: ignore" if mod in pyright_ignore_imports else "")
|
+ (
|
||||||
|
" # type: ignore"
|
||||||
|
if mod in pyright_ignore_imports
|
||||||
|
else " # noqa" # ignore ruff formatting here for cases like rx.list.
|
||||||
|
if isinstance(mod, tuple)
|
||||||
|
else ""
|
||||||
|
)
|
||||||
for mod, path in sub_mod_attrs.items()
|
for mod, path in sub_mod_attrs.items()
|
||||||
]
|
]
|
||||||
sub_mod_attrs_imports.append("")
|
sub_mod_attrs_imports.append("")
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import dataclasses
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import platform
|
import platform
|
||||||
import warnings
|
import warnings
|
||||||
@ -144,7 +145,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|||||||
"python_version": get_python_version(),
|
"python_version": get_python_version(),
|
||||||
"cpu_count": get_cpu_count(),
|
"cpu_count": get_cpu_count(),
|
||||||
"memory": get_memory(),
|
"memory": get_memory(),
|
||||||
"cpu_info": dict(cpuinfo) if cpuinfo else {},
|
"cpu_info": dataclasses.asdict(cpuinfo) if cpuinfo else {},
|
||||||
**additional_fields,
|
**additional_fields,
|
||||||
},
|
},
|
||||||
"timestamp": stamp,
|
"timestamp": stamp,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import dataclasses
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
@ -486,7 +487,11 @@ def is_valid_var_type(type_: Type) -> bool:
|
|||||||
|
|
||||||
if is_union(type_):
|
if is_union(type_):
|
||||||
return all((is_valid_var_type(arg) for arg in get_args(type_)))
|
return all((is_valid_var_type(arg) for arg in get_args(type_)))
|
||||||
return _issubclass(type_, StateVar) or serializers.has_serializer(type_)
|
return (
|
||||||
|
_issubclass(type_, StateVar)
|
||||||
|
or serializers.has_serializer(type_)
|
||||||
|
or dataclasses.is_dataclass(type_)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_backend_base_variable(name: str, cls: Type) -> bool:
|
def is_backend_base_variable(name: str, cls: Type) -> bool:
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
import sys
|
|
||||||
from typing import List, Tuple
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from reflex_chakra.components.datadisplay.table import Tbody, Tfoot, Thead
|
|
||||||
|
|
||||||
from reflex.state import BaseState
|
|
||||||
|
|
||||||
PYTHON_GT_V38 = sys.version_info.major >= 3 and sys.version_info.minor > 8
|
|
||||||
|
|
||||||
|
|
||||||
class TableState(BaseState):
|
|
||||||
"""Test State class."""
|
|
||||||
|
|
||||||
rows_List_List_str: List[List[str]] = [["random", "row"]]
|
|
||||||
rows_List_List: List[List] = [["random", "row"]]
|
|
||||||
rows_List_str: List[str] = ["random", "row"]
|
|
||||||
rows_Tuple_List_str: Tuple[List[str]] = (["random", "row"],)
|
|
||||||
rows_Tuple_List: Tuple[List] = ["random", "row"] # type: ignore
|
|
||||||
rows_Tuple_str_str: Tuple[str, str] = (
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
)
|
|
||||||
rows_Tuple_Tuple_str_str: Tuple[Tuple[str, str]] = (
|
|
||||||
(
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
rows_Tuple_Tuple: Tuple[Tuple] = (
|
|
||||||
(
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
rows_str: str = "random, row"
|
|
||||||
headers_List_str: List[str] = ["header1", "header2"]
|
|
||||||
headers_Tuple_str_str: Tuple[str, str] = (
|
|
||||||
"header1",
|
|
||||||
"header2",
|
|
||||||
)
|
|
||||||
headers_str: str = "headers1, headers2"
|
|
||||||
footers_List_str: List[str] = ["footer1", "footer2"]
|
|
||||||
footers_Tuple_str_str: Tuple[str, str] = (
|
|
||||||
"footer1",
|
|
||||||
"footer2",
|
|
||||||
)
|
|
||||||
footers_str: str = "footer1, footer2"
|
|
||||||
|
|
||||||
if sys.version_info.major >= 3 and sys.version_info.minor > 8:
|
|
||||||
rows_list_list_str: list[list[str]] = [["random", "row"]]
|
|
||||||
rows_list_list: list[list] = [["random", "row"]]
|
|
||||||
rows_list_str: list[str] = ["random", "row"]
|
|
||||||
rows_tuple_list_str: tuple[list[str]] = (["random", "row"],)
|
|
||||||
rows_tuple_list: tuple[list] = ["random", "row"] # type: ignore
|
|
||||||
rows_tuple_str_str: tuple[str, str] = (
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
)
|
|
||||||
rows_tuple_tuple_str_str: tuple[tuple[str, str]] = (
|
|
||||||
(
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
rows_tuple_tuple: tuple[tuple] = (
|
|
||||||
(
|
|
||||||
"random",
|
|
||||||
"row",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
valid_extras = (
|
|
||||||
[
|
|
||||||
TableState.rows_list_list_str,
|
|
||||||
TableState.rows_list_list,
|
|
||||||
TableState.rows_tuple_list_str,
|
|
||||||
TableState.rows_tuple_list,
|
|
||||||
TableState.rows_tuple_tuple_str_str,
|
|
||||||
TableState.rows_tuple_tuple,
|
|
||||||
]
|
|
||||||
if PYTHON_GT_V38
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
invalid_extras = (
|
|
||||||
[TableState.rows_list_str, TableState.rows_tuple_str_str] if PYTHON_GT_V38 else []
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"rows",
|
|
||||||
[
|
|
||||||
[["random", "row"]],
|
|
||||||
TableState.rows_List_List_str,
|
|
||||||
TableState.rows_List_List,
|
|
||||||
TableState.rows_Tuple_List_str,
|
|
||||||
TableState.rows_Tuple_List,
|
|
||||||
TableState.rows_Tuple_Tuple_str_str,
|
|
||||||
TableState.rows_Tuple_Tuple,
|
|
||||||
*valid_extras,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_body_with_valid_rows_prop(rows):
|
|
||||||
render_dict = Tbody.create(rows=rows).render()
|
|
||||||
assert render_dict["name"] == "Tbody"
|
|
||||||
assert len(render_dict["children"]) == 1
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"rows",
|
|
||||||
[
|
|
||||||
["random", "row"],
|
|
||||||
"random, rows",
|
|
||||||
TableState.rows_List_str,
|
|
||||||
TableState.rows_Tuple_str_str,
|
|
||||||
TableState.rows_str,
|
|
||||||
*invalid_extras,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_body_with_invalid_rows_prop(rows):
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
Tbody.create(rows=rows)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"headers",
|
|
||||||
[
|
|
||||||
["random", "header"],
|
|
||||||
TableState.headers_List_str,
|
|
||||||
TableState.headers_Tuple_str_str,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_head_with_valid_headers_prop(headers):
|
|
||||||
render_dict = Thead.create(headers=headers).render()
|
|
||||||
assert render_dict["name"] == "Thead"
|
|
||||||
assert len(render_dict["children"]) == 1
|
|
||||||
assert render_dict["children"][0]["name"] == "Tr"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"headers",
|
|
||||||
[
|
|
||||||
"random, header",
|
|
||||||
TableState.headers_str,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_head_with_invalid_headers_prop(headers):
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
Thead.create(headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"footers",
|
|
||||||
[
|
|
||||||
["random", "footers"],
|
|
||||||
TableState.footers_List_str,
|
|
||||||
TableState.footers_Tuple_str_str,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_footer_with_valid_footers_prop(footers):
|
|
||||||
render_dict = Tfoot.create(footers=footers).render()
|
|
||||||
assert render_dict["name"] == "Tfoot"
|
|
||||||
assert len(render_dict["children"]) == 1
|
|
||||||
assert render_dict["children"][0]["name"] == "Tr"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"footers",
|
|
||||||
[
|
|
||||||
"random, footers",
|
|
||||||
TableState.footers_str,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_create_table_footer_with_invalid_footers_prop(footers):
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
Tfoot.create(footers=footers)
|
|
@ -1,5 +1,4 @@
|
|||||||
from reflex_chakra.components.forms.form import Form
|
from reflex.components.radix.primitives.form import Form
|
||||||
|
|
||||||
from reflex.event import EventChain
|
from reflex.event import EventChain
|
||||||
from reflex.ivars.base import ImmutableVar
|
from reflex.ivars.base import ImmutableVar
|
||||||
|
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from reflex_chakra.components.media.icon import ICON_LIST, Icon
|
|
||||||
|
|
||||||
from reflex.utils import format
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_tag_errors():
|
|
||||||
"""Test that an icon without a tag raises an error."""
|
|
||||||
with pytest.raises(AttributeError):
|
|
||||||
Icon.create()
|
|
||||||
|
|
||||||
|
|
||||||
def test_children_errors():
|
|
||||||
"""Test that an icon with children raises an error."""
|
|
||||||
with pytest.raises(AttributeError):
|
|
||||||
Icon.create("child", tag="search")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"tag",
|
|
||||||
ICON_LIST,
|
|
||||||
)
|
|
||||||
def test_valid_icon(tag: str):
|
|
||||||
"""Test that a valid icon does not raise an error.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tag: The icon tag.
|
|
||||||
"""
|
|
||||||
icon = Icon.create(tag=tag)
|
|
||||||
assert icon.tag == format.to_title_case(tag) + "Icon"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("tag", ["", " ", "invalid", 123])
|
|
||||||
def test_invalid_icon(tag):
|
|
||||||
"""Test that an invalid icon raises an error.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tag: The icon tag.
|
|
||||||
"""
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
Icon.create(tag=tag)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"tag",
|
|
||||||
["Check", "Close", "eDit"],
|
|
||||||
)
|
|
||||||
def test_tag_with_capital(tag: str):
|
|
||||||
"""Test that an icon that tag with capital does not raise an error.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tag: The icon tag.
|
|
||||||
"""
|
|
||||||
icon = Icon.create(tag=tag)
|
|
||||||
assert icon.tag == format.to_title_case(tag) + "Icon"
|
|
@ -2,8 +2,6 @@ from contextlib import nullcontext
|
|||||||
from typing import Any, Dict, List, Optional, Type, Union
|
from typing import Any, Dict, List, Optional, Type, Union
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import reflex_chakra as rc
|
|
||||||
from reflex_chakra.components.layout.box import Box
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
@ -16,6 +14,7 @@ from reflex.components.component import (
|
|||||||
StatefulComponent,
|
StatefulComponent,
|
||||||
custom_component,
|
custom_component,
|
||||||
)
|
)
|
||||||
|
from reflex.components.radix.themes.layout.box import Box
|
||||||
from reflex.constants import EventTriggers
|
from reflex.constants import EventTriggers
|
||||||
from reflex.event import EventChain, EventHandler, parse_args_spec
|
from reflex.event import EventChain, EventHandler, parse_args_spec
|
||||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||||
@ -638,21 +637,21 @@ def test_component_create_unallowed_types(children, test_component):
|
|||||||
"props": [],
|
"props": [],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"args": None,
|
"args": None,
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "RadixThemesText",
|
"name": "RadixThemesText",
|
||||||
"props": ['as={"p"}'],
|
"props": ['as={"p"}'],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"args": None,
|
"args": None,
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [],
|
"props": [],
|
||||||
"contents": '{"first_text"}',
|
"contents": '{"first_text"}',
|
||||||
"args": None,
|
"args": None,
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
"children": [],
|
"children": [],
|
||||||
"autofocus": False,
|
"autofocus": False,
|
||||||
}
|
}
|
||||||
@ -680,13 +679,13 @@ def test_component_create_unallowed_types(children, test_component):
|
|||||||
"contents": '{"first_text"}',
|
"contents": '{"first_text"}',
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "RadixThemesText",
|
"name": "RadixThemesText",
|
||||||
"props": ['as={"p"}'],
|
"props": ['as={"p"}'],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"args": None,
|
"args": None,
|
||||||
@ -699,19 +698,19 @@ def test_component_create_unallowed_types(children, test_component):
|
|||||||
"contents": '{"second_text"}',
|
"contents": '{"second_text"}',
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "RadixThemesText",
|
"name": "RadixThemesText",
|
||||||
"props": ['as={"p"}'],
|
"props": ['as={"p"}'],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "Fragment",
|
"name": "Fragment",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -731,13 +730,13 @@ def test_component_create_unallowed_types(children, test_component):
|
|||||||
"contents": '{"first_text"}',
|
"contents": '{"first_text"}',
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "RadixThemesText",
|
"name": "RadixThemesText",
|
||||||
"props": ['as={"p"}'],
|
"props": ['as={"p"}'],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"args": None,
|
"args": None,
|
||||||
@ -758,31 +757,31 @@ def test_component_create_unallowed_types(children, test_component):
|
|||||||
"contents": '{"second_text"}',
|
"contents": '{"second_text"}',
|
||||||
"name": "",
|
"name": "",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "RadixThemesText",
|
"name": "RadixThemesText",
|
||||||
"props": ['as={"p"}'],
|
"props": ['as={"p"}'],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "Fragment",
|
"name": "Fragment",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "RadixThemesBox",
|
"name": "RadixThemesBox",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"contents": "",
|
"contents": "",
|
||||||
"name": "Fragment",
|
"name": "Fragment",
|
||||||
"props": [],
|
"props": [],
|
||||||
"special_props": set(),
|
"special_props": [],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1114,8 +1113,8 @@ def test_component_with_only_valid_children(fixture, request):
|
|||||||
[
|
[
|
||||||
(rx.text("hi"), '<RadixThemesText as={"p"}>\n {"hi"}\n</RadixThemesText>'),
|
(rx.text("hi"), '<RadixThemesText as={"p"}>\n {"hi"}\n</RadixThemesText>'),
|
||||||
(
|
(
|
||||||
rx.box(rc.heading("test", size="md")),
|
rx.box(rx.heading("test", size="3")),
|
||||||
'<RadixThemesBox>\n <Heading size={"md"}>\n {"test"}\n</Heading>\n</RadixThemesBox>',
|
'<RadixThemesBox>\n <RadixThemesHeading size={"3"}>\n {"test"}\n</RadixThemesHeading>\n</RadixThemesBox>',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -1290,12 +1289,12 @@ class EventState(rx.State):
|
|||||||
id="fstring-class_name",
|
id="fstring-class_name",
|
||||||
),
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
rx.fragment(special_props={TEST_VAR}),
|
rx.fragment(special_props=[TEST_VAR]),
|
||||||
[TEST_VAR],
|
[TEST_VAR],
|
||||||
id="direct-special_props",
|
id="direct-special_props",
|
||||||
),
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
rx.fragment(special_props={LiteralVar.create(f"foo{TEST_VAR}bar")}),
|
rx.fragment(special_props=[LiteralVar.create(f"foo{TEST_VAR}bar")]),
|
||||||
[FORMATTED_TEST_VAR],
|
[FORMATTED_TEST_VAR],
|
||||||
id="fstring-special_props",
|
id="fstring-special_props",
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import reflex_chakra as rc
|
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
from reflex.components.markdown import Markdown
|
from reflex.components.markdown import Markdown
|
||||||
@ -37,9 +36,7 @@ def test_get_component(tag, expected):
|
|||||||
def test_set_component_map():
|
def test_set_component_map():
|
||||||
"""Test setting the component map."""
|
"""Test setting the component map."""
|
||||||
component_map = {
|
component_map = {
|
||||||
"h1": lambda value: rx.box(
|
"h1": lambda value: rx.box(rx.heading(value, as_="h1"), padding="1em"),
|
||||||
rc.heading(value, as_="h1", size="2xl"), padding="1em"
|
|
||||||
),
|
|
||||||
"p": lambda value: rx.box(rx.text(value), padding="1em"),
|
"p": lambda value: rx.box(rx.text(value), padding="1em"),
|
||||||
}
|
}
|
||||||
md = Markdown.create("# Hello", component_map=component_map)
|
md = Markdown.create("# Hello", component_map=component_map)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import functools
|
import functools
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
@ -13,7 +14,6 @@ from typing import Generator, List, Tuple, Type
|
|||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import reflex_chakra as rc
|
|
||||||
import sqlmodel
|
import sqlmodel
|
||||||
from fastapi import FastAPI, UploadFile
|
from fastapi import FastAPI, UploadFile
|
||||||
from starlette_admin.auth import AuthProvider
|
from starlette_admin.auth import AuthProvider
|
||||||
@ -268,8 +268,6 @@ def test_add_page_set_route_dynamic(index_page, windows_platform: bool):
|
|||||||
app = App(state=EmptyState)
|
app = App(state=EmptyState)
|
||||||
assert app.state is not None
|
assert app.state is not None
|
||||||
route = "/test/[dynamic]"
|
route = "/test/[dynamic]"
|
||||||
if windows_platform:
|
|
||||||
route.lstrip("/").replace("/", "\\")
|
|
||||||
assert app.pages == {}
|
assert app.pages == {}
|
||||||
app.add_page(index_page, route=route)
|
app.add_page(index_page, route=route)
|
||||||
assert app.pages.keys() == {"test/[dynamic]"}
|
assert app.pages.keys() == {"test/[dynamic]"}
|
||||||
@ -937,8 +935,6 @@ def test_dynamic_arg_shadow(
|
|||||||
"""
|
"""
|
||||||
arg_name = "counter"
|
arg_name = "counter"
|
||||||
route = f"/test/[{arg_name}]"
|
route = f"/test/[{arg_name}]"
|
||||||
if windows_platform:
|
|
||||||
route.lstrip("/").replace("/", "\\")
|
|
||||||
app = app_module_mock.app = App(state=DynamicState)
|
app = app_module_mock.app = App(state=DynamicState)
|
||||||
assert app.state is not None
|
assert app.state is not None
|
||||||
with pytest.raises(NameError):
|
with pytest.raises(NameError):
|
||||||
@ -964,9 +960,6 @@ def test_multiple_dynamic_args(
|
|||||||
arg_name = "my_arg"
|
arg_name = "my_arg"
|
||||||
route = f"/test/[{arg_name}]"
|
route = f"/test/[{arg_name}]"
|
||||||
route2 = f"/test2/[{arg_name}]"
|
route2 = f"/test2/[{arg_name}]"
|
||||||
if windows_platform:
|
|
||||||
route = route.lstrip("/").replace("/", "\\")
|
|
||||||
route2 = route2.lstrip("/").replace("/", "\\")
|
|
||||||
app = app_module_mock.app = App(state=EmptyState)
|
app = app_module_mock.app = App(state=EmptyState)
|
||||||
app.add_page(index_page, route=route)
|
app.add_page(index_page, route=route)
|
||||||
app.add_page(index_page, route=route2)
|
app.add_page(index_page, route=route2)
|
||||||
@ -994,8 +987,6 @@ async def test_dynamic_route_var_route_change_completed_on_load(
|
|||||||
"""
|
"""
|
||||||
arg_name = "dynamic"
|
arg_name = "dynamic"
|
||||||
route = f"/test/[{arg_name}]"
|
route = f"/test/[{arg_name}]"
|
||||||
if windows_platform:
|
|
||||||
route.lstrip("/").replace("/", "\\")
|
|
||||||
app = app_module_mock.app = App(state=DynamicState)
|
app = app_module_mock.app = App(state=DynamicState)
|
||||||
assert app.state is not None
|
assert app.state is not None
|
||||||
assert arg_name not in app.state.vars
|
assert arg_name not in app.state.vars
|
||||||
@ -1062,7 +1053,7 @@ async def test_dynamic_route_var_route_change_completed_on_load(
|
|||||||
f"comp_{arg_name}": exp_val,
|
f"comp_{arg_name}": exp_val,
|
||||||
constants.CompileVars.IS_HYDRATED: False,
|
constants.CompileVars.IS_HYDRATED: False,
|
||||||
# "side_effect_counter": exp_index,
|
# "side_effect_counter": exp_index,
|
||||||
"router": exp_router,
|
"router": dataclasses.asdict(exp_router),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events=[
|
events=[
|
||||||
@ -1320,13 +1311,13 @@ def test_app_wrap_priority(compilable_app: tuple[App, Path]):
|
|||||||
tag = "Fragment1"
|
tag = "Fragment1"
|
||||||
|
|
||||||
def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
|
def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
|
||||||
return {(99, "Box"): rc.box()}
|
return {(99, "Box"): rx.box()}
|
||||||
|
|
||||||
class Fragment2(Component):
|
class Fragment2(Component):
|
||||||
tag = "Fragment2"
|
tag = "Fragment2"
|
||||||
|
|
||||||
def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
|
def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]:
|
||||||
return {(50, "Text"): rc.text()}
|
return {(50, "Text"): rx.text()}
|
||||||
|
|
||||||
class Fragment3(Component):
|
class Fragment3(Component):
|
||||||
tag = "Fragment3"
|
tag = "Fragment3"
|
||||||
@ -1346,19 +1337,17 @@ def test_app_wrap_priority(compilable_app: tuple[App, Path]):
|
|||||||
assert (
|
assert (
|
||||||
"function AppWrap({children}) {"
|
"function AppWrap({children}) {"
|
||||||
"return ("
|
"return ("
|
||||||
"<Box>"
|
"<RadixThemesBox>"
|
||||||
"<ChakraProvider theme={extendTheme(theme)}>"
|
'<RadixThemesText as={"p"}>'
|
||||||
"<ChakraColorModeProvider>"
|
"<RadixThemesColorModeProvider>"
|
||||||
"<Text>"
|
|
||||||
"<Fragment2>"
|
"<Fragment2>"
|
||||||
"<Fragment>"
|
"<Fragment>"
|
||||||
"{children}"
|
"{children}"
|
||||||
"</Fragment>"
|
"</Fragment>"
|
||||||
"</Fragment2>"
|
"</Fragment2>"
|
||||||
"</Text>"
|
"</RadixThemesColorModeProvider>"
|
||||||
"</ChakraColorModeProvider>"
|
"</RadixThemesText>"
|
||||||
"</ChakraProvider>"
|
"</RadixThemesBox>"
|
||||||
"</Box>"
|
|
||||||
")"
|
")"
|
||||||
"}"
|
"}"
|
||||||
) in "".join(app_js_lines)
|
) in "".join(app_js_lines)
|
||||||
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import copy
|
import copy
|
||||||
|
import dataclasses
|
||||||
import datetime
|
import datetime
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
@ -58,6 +59,7 @@ formatted_router = {
|
|||||||
"origin": "",
|
"origin": "",
|
||||||
"upgrade": "",
|
"upgrade": "",
|
||||||
"connection": "",
|
"connection": "",
|
||||||
|
"cookie": "",
|
||||||
"pragma": "",
|
"pragma": "",
|
||||||
"cache_control": "",
|
"cache_control": "",
|
||||||
"user_agent": "",
|
"user_agent": "",
|
||||||
@ -865,8 +867,10 @@ def test_get_headers(test_state, router_data, router_data_headers):
|
|||||||
router_data: The router data fixture.
|
router_data: The router data fixture.
|
||||||
router_data_headers: The expected headers.
|
router_data_headers: The expected headers.
|
||||||
"""
|
"""
|
||||||
|
print(router_data_headers)
|
||||||
test_state.router = RouterData(router_data)
|
test_state.router = RouterData(router_data)
|
||||||
assert test_state.router.headers.dict() == {
|
print(test_state.router.headers)
|
||||||
|
assert dataclasses.asdict(test_state.router.headers) == {
|
||||||
format.to_snake_case(k): v for k, v in router_data_headers.items()
|
format.to_snake_case(k): v for k, v in router_data_headers.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1908,19 +1912,21 @@ async def test_state_proxy(grandchild_state: GrandchildState, mock_app: rx.App):
|
|||||||
mock_app.event_namespace.emit.assert_called_once()
|
mock_app.event_namespace.emit.assert_called_once()
|
||||||
mcall = mock_app.event_namespace.emit.mock_calls[0]
|
mcall = mock_app.event_namespace.emit.mock_calls[0]
|
||||||
assert mcall.args[0] == str(SocketEvent.EVENT)
|
assert mcall.args[0] == str(SocketEvent.EVENT)
|
||||||
assert json.loads(mcall.args[1]) == StateUpdate(
|
assert json.loads(mcall.args[1]) == dataclasses.asdict(
|
||||||
delta={
|
StateUpdate(
|
||||||
parent_state.get_full_name(): {
|
delta={
|
||||||
"upper": "",
|
parent_state.get_full_name(): {
|
||||||
"sum": 3.14,
|
"upper": "",
|
||||||
},
|
"sum": 3.14,
|
||||||
grandchild_state.get_full_name(): {
|
},
|
||||||
"value2": "42",
|
grandchild_state.get_full_name(): {
|
||||||
},
|
"value2": "42",
|
||||||
GrandchildState3.get_full_name(): {
|
},
|
||||||
"computed": "",
|
GrandchildState3.get_full_name(): {
|
||||||
},
|
"computed": "",
|
||||||
}
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
assert mcall.kwargs["to"] == grandchild_state.router.session.session_id
|
assert mcall.kwargs["to"] == grandchild_state.router.session.session_id
|
||||||
|
|
||||||
|
@ -553,6 +553,7 @@ formatted_router = {
|
|||||||
"origin": "",
|
"origin": "",
|
||||||
"upgrade": "",
|
"upgrade": "",
|
||||||
"connection": "",
|
"connection": "",
|
||||||
|
"cookie": "",
|
||||||
"pragma": "",
|
"pragma": "",
|
||||||
"cache_control": "",
|
"cache_control": "",
|
||||||
"user_agent": "",
|
"user_agent": "",
|
||||||
|
@ -54,17 +54,21 @@ def test_import_var(import_var, expected_name):
|
|||||||
(
|
(
|
||||||
{"react": {"Component"}},
|
{"react": {"Component"}},
|
||||||
{"react": {"Component"}, "react-dom": {"render"}},
|
{"react": {"Component"}, "react-dom": {"render"}},
|
||||||
{"react": {"Component"}, "react-dom": {"render"}},
|
{"react": {ImportVar("Component")}, "react-dom": {ImportVar("render")}},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{"react": {"Component"}, "next/image": {"Image"}},
|
{"react": {"Component"}, "next/image": {"Image"}},
|
||||||
{"react": {"Component"}, "react-dom": {"render"}},
|
{"react": {"Component"}, "react-dom": {"render"}},
|
||||||
{"react": {"Component"}, "react-dom": {"render"}, "next/image": {"Image"}},
|
{
|
||||||
|
"react": {ImportVar("Component")},
|
||||||
|
"react-dom": {ImportVar("render")},
|
||||||
|
"next/image": {ImportVar("Image")},
|
||||||
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{"react": {"Component"}},
|
{"react": {"Component"}},
|
||||||
{"": {"some/custom.css"}},
|
{"": {"some/custom.css"}},
|
||||||
{"react": {"Component"}, "": {"some/custom.css"}},
|
{"react": {ImportVar("Component")}, "": {ImportVar("some/custom.css")}},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user