Skip to content

Commit 64e139c

Browse files
committed
Merge remote-tracking branch 'origin/main' into release/reflex-0.8.27
2 parents 00af449 + 88155a7 commit 64e139c

File tree

19 files changed

+576
-393
lines changed

19 files changed

+576
-393
lines changed

pyi_hashes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"reflex/components/core/window_events.pyi": "af33ccec866b9540ee7fbec6dbfbd151",
2424
"reflex/components/datadisplay/__init__.pyi": "52755871369acbfd3a96b46b9a11d32e",
2525
"reflex/components/datadisplay/code.pyi": "b86769987ef4d1cbdddb461be88539fd",
26-
"reflex/components/datadisplay/dataeditor.pyi": "fb26f3e702fcb885539d1cf82a854be3",
26+
"reflex/components/datadisplay/dataeditor.pyi": "f8c1e816c9f22f4a7429f812214407f2",
2727
"reflex/components/datadisplay/shiki_code_block.pyi": "1d53e75b6be0d3385a342e7b3011babd",
2828
"reflex/components/el/__init__.pyi": "0adfd001a926a2a40aee94f6fa725ecc",
2929
"reflex/components/el/element.pyi": "c5974a92fbc310e42d0f6cfdd13472f4",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies = [
2424
"click >=8.2",
2525
"granian[reload] >=2.5.5",
2626
"httpx >=0.23.3,<1.0",
27-
"packaging >=24.2,<26",
27+
"packaging >=24.2,<27",
2828
"platformdirs >=4.3.7,<5.0",
2929
"psutil >=7.0.0,<8.0; sys_platform == 'win32'",
3030
"pydantic >=1.10.21,<3.0",

reflex/.templates/web/utils/state.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,16 @@ export const applyRestEvent = async (event, socket, navigate, params) => {
446446
return eventSent;
447447
};
448448

449+
/**
450+
* Resolve a socket reference to the actual socket object.
451+
* Handles both ref objects ({ current: Socket }) and raw sockets.
452+
* @param socket Either a ref object or raw socket.
453+
* @returns The actual socket object.
454+
*/
455+
const resolveSocket = (socket) => {
456+
return socket?.current ?? socket;
457+
};
458+
449459
/**
450460
* Queue events to be processed and trigger processing of queue.
451461
* @param events Array of events to queue.
@@ -471,7 +481,7 @@ export const queueEvents = async (
471481
];
472482
}
473483
event_queue.push(...events.filter((e) => e !== undefined && e !== null));
474-
await processEvent(socket.current, navigate, params);
484+
await processEvent(resolveSocket(socket), navigate, params);
475485
};
476486

477487
/**

reflex/app.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@
7777
from reflex.event import (
7878
_EVENT_FIELDS,
7979
Event,
80-
EventHandler,
8180
EventSpec,
8281
EventType,
8382
IndividualEventType,
8483
get_hydrate_event,
8584
noop,
8685
)
86+
from reflex.istate.proxy import StateProxy
8787
from reflex.page import DECORATED_PAGES
8888
from reflex.route import (
8989
get_route_args,
@@ -1619,6 +1619,8 @@ def _process_background(
16191619
if not handler.is_background:
16201620
return None
16211621

1622+
substate = StateProxy(substate)
1623+
16221624
async def _coro():
16231625
"""Coroutine to process the event and emit updates inside an asyncio.Task.
16241626
@@ -1934,21 +1936,14 @@ async def upload_file(request: Request):
19341936
substate_token = _substate_key(token, handler.rpartition(".")[0])
19351937
state = await app.state_manager.get_state(substate_token)
19361938

1937-
# get the current session ID
1938-
# get the current state(parent state/substate)
1939-
path = handler.split(".")[:-1]
1940-
current_state = state.get_substate(path)
19411939
handler_upload_param = ()
19421940

1943-
# get handler function
1944-
func = getattr(type(current_state), handler.split(".")[-1])
1941+
_current_state, event_handler = state._get_event_handler(handler)
19451942

1946-
# check if there exists any handler args with annotation, list[UploadFile]
1947-
if isinstance(func, EventHandler):
1948-
if func.is_background:
1949-
msg = f"@rx.event(background=True) is not supported for upload handler `{handler}`."
1950-
raise UploadTypeError(msg)
1951-
func = func.fn
1943+
if event_handler.is_background:
1944+
msg = f"@rx.event(background=True) is not supported for upload handler `{handler}`."
1945+
raise UploadTypeError(msg)
1946+
func = event_handler.fn
19521947
if isinstance(func, functools.partial):
19531948
func = func.func
19541949
for k, v in get_type_hints(func).items():

reflex/components/core/debounce.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def create(cls, *children: Component, **props: Any) -> Component:
111111
child_ref = child.get_ref()
112112
if props.get("input_ref") is None and child_ref:
113113
props["input_ref"] = Var(_js_expr=child_ref, _var_type=str)
114+
if child.id is not None:
114115
props["id"] = child.id
115116

116117
# Set the child element to wrap, including any imports/hooks from the child.

reflex/components/datadisplay/dataeditor.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ class DataEditor(NoSSRComponent):
240240
# Determines the height of each row.
241241
row_height: Var[int]
242242

243-
# Kind of row markers.
243+
# Kind of row markers. Options are: "none", "number", "checkbox", "both", "checkbox-visible", "clickable-number".
244244
row_markers: Var[LiteralRowMarker]
245245

246246
# Changes the starting index for row markers.
@@ -291,6 +291,9 @@ class DataEditor(NoSSRComponent):
291291
# Controls which types of row selections can exist at the same time. ("exclusive", "mixed").
292292
row_selection_blending: Var[Literal["exclusive", "mixed"]]
293293

294+
# Controls row marker selection behavior. "auto" adapts to touch/mouse, "multi" acts as if Ctrl is pressed. ("auto", "multi").
295+
row_selection_mode: Var[Literal["auto", "multi"]]
296+
294297
# Controls how spans are handled in selections. ("default", "allowPartial").
295298
span_range_behavior: Var[Literal["default", "allowPartial"]]
296299

@@ -357,6 +360,12 @@ class DataEditor(NoSSRComponent):
357360
# Fired when a column is resized.
358361
on_column_resize: EventHandler[passthrough_event_spec(GridColumn, int)]
359362

363+
# Shows search bar.
364+
show_search: Var[bool]
365+
366+
# Fired when the search close button is clicked.
367+
on_search_close: EventHandler[no_args_event_spec]
368+
360369
def add_imports(self) -> ImportDict:
361370
"""Add imports for the component.
362371

reflex/components/field.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ class FieldBasedMeta(type):
6767
PropsBaseMeta and BaseComponentMeta.
6868
"""
6969

70-
def __new__(cls, name: str, bases: tuple[type], namespace: dict[str, Any]) -> type:
70+
def __new__(
71+
cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]
72+
) -> type:
7173
"""Create a new field-based class.
7274
7375
Args:
@@ -100,7 +102,7 @@ def __new__(cls, name: str, bases: tuple[type], namespace: dict[str, Any]) -> ty
100102
return super().__new__(cls, name, bases, namespace)
101103

102104
@classmethod
103-
def _collect_inherited_fields(cls, bases: tuple[type]) -> dict[str, Any]:
105+
def _collect_inherited_fields(cls, bases: tuple[type, ...]) -> dict[str, Any]:
104106
inherited_fields: dict[str, Any] = {}
105107

106108
# Collect inherited fields from base classes

reflex/components/literals.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@
2929
]
3030

3131

32-
LiteralRowMarker = Literal["none", "number", "checkbox", "both", "clickable-number"]
32+
LiteralRowMarker = Literal[
33+
"none", "number", "checkbox", "both", "checkbox-visible", "clickable-number"
34+
]

reflex/event.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def substate_token(self) -> str:
8989
_EVENT_FIELDS: set[str] = {f.name for f in dataclasses.fields(Event)}
9090

9191
BACKGROUND_TASK_MARKER = "_reflex_background_task"
92+
EVENT_ACTIONS_MARKER = "_rx_event_actions"
9293

9394

9495
@dataclasses.dataclass(
@@ -2311,6 +2312,7 @@ class EventNamespace:
23112312

23122313
# Constants
23132314
BACKGROUND_TASK_MARKER = BACKGROUND_TASK_MARKER
2315+
EVENT_ACTIONS_MARKER = EVENT_ACTIONS_MARKER
23142316
_EVENT_FIELDS = _EVENT_FIELDS
23152317
FORM_DATA = FORM_DATA
23162318
upload_files = upload_files
@@ -2461,7 +2463,7 @@ def wrapper(
24612463
# Store decorator event actions on the function for later processing
24622464
event_actions = _build_event_actions()
24632465
if event_actions:
2464-
func._rx_event_actions = event_actions # pyright: ignore [reportFunctionMemberAccess]
2466+
setattr(func, EVENT_ACTIONS_MARKER, event_actions)
24652467
return func # pyright: ignore [reportReturnType]
24662468

24672469
if func is not None:

reflex/istate/proxy.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from reflex.state import BaseState, StateUpdate
2727

2828
T_STATE = TypeVar("T_STATE", bound="BaseState")
29+
T = TypeVar("T")
2930

3031

3132
class StateProxy(wrapt.ObjectProxy):
@@ -671,19 +672,23 @@ def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Any:
671672
return copy.deepcopy(self.__wrapped__, memo=memo)
672673

673674
def __reduce_ex__(self, protocol_version: SupportsIndex):
674-
"""Get the state for redis serialization.
675+
"""Serialize the wrapped object for pickle, stripping off the proxy.
675676
676-
This method is called by cloudpickle to serialize the object.
677-
678-
It explicitly serializes the wrapped object, stripping off the mutable proxy.
677+
Returns a function that reconstructs to the wrapped object directly,
678+
ensuring pickle's memo system correctly tracks object identity.
679679
680680
Args:
681681
protocol_version: The protocol version.
682682
683683
Returns:
684-
Tuple of (wrapped class, empty args, class __getstate__)
684+
Tuple that reconstructs to the wrapped object.
685685
"""
686-
return self.__wrapped__.__reduce_ex__(protocol_version)
686+
return (_unwrap_for_pickle, (self.__wrapped__,))
687+
688+
689+
def _unwrap_for_pickle(obj: T) -> T:
690+
"""Return the object unchanged. Used by MutableProxy.__reduce_ex__."""
691+
return obj
687692

688693

689694
@serializer

0 commit comments

Comments
 (0)