fix isssues in dataeditor

This commit is contained in:
Khaleel Al-Adhami 2024-10-21 18:06:20 -07:00
parent ae0c5a035a
commit 8f91ba8500
3 changed files with 143 additions and 15 deletions

View File

@ -335,7 +335,7 @@ class DataEditor(NoSSRComponent):
on_delete: EventHandler[identity_event(GridSelection)] on_delete: EventHandler[identity_event(GridSelection)]
# Fired when editing is finished. # Fired when editing is finished.
on_finished_editing: EventHandler[identity_event(Optional[GridCell], list[int])] on_finished_editing: EventHandler[identity_event(Union[GridCell, None], list[int])]
# Fired when a row is appended. # Fired when a row is appended.
on_row_appended: EventHandler[empty_event] on_row_appended: EventHandler[empty_event]

View File

@ -6,6 +6,8 @@
from enum import Enum from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Union, overload from typing import Any, Dict, List, Literal, Optional, Union, overload
from typing_extensions import TypedDict
from reflex.base import Base from reflex.base import Base
from reflex.components.component import NoSSRComponent from reflex.components.component import NoSSRComponent
from reflex.event import EventType from reflex.event import EventType
@ -78,6 +80,54 @@ class DataEditorTheme(Base):
def on_edit_spec(pos, data: dict[str, Any]): ... def on_edit_spec(pos, data: dict[str, Any]): ...
class Bounds(TypedDict):
x: int
y: int
width: int
height: int
class CompatSelection(TypedDict):
items: list
class Rectangle(TypedDict):
x: int
y: int
width: int
height: int
class GridSelectionCurrent(TypedDict):
cell: list[int]
range: Rectangle
rangeStack: list[Rectangle]
class GridSelection(TypedDict):
current: Optional[GridSelectionCurrent]
columns: CompatSelection
rows: CompatSelection
class GroupHeaderClickedEventArgs(TypedDict):
kind: str
group: str
location: list[int]
bounds: Bounds
isEdge: bool
shiftKey: bool
ctrlKey: bool
metaKey: bool
isTouch: bool
localEventX: int
localEventY: int
button: int
buttons: int
scrollEdge: list[int]
class GridCell(TypedDict):
span: Optional[List[int]]
class GridColumn(TypedDict):
title: str
group: Optional[str]
class DataEditor(NoSSRComponent): class DataEditor(NoSSRComponent):
def add_imports(self) -> ImportDict: ... def add_imports(self) -> ImportDict: ...
def add_hooks(self) -> list[str]: ... def add_hooks(self) -> list[str]: ...
@ -136,24 +186,28 @@ class DataEditor(NoSSRComponent):
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None, on_blur: Optional[EventType[[]]] = None,
on_cell_activated: Optional[EventType] = None, on_cell_activated: Optional[EventType[tuple[int, int]]] = None,
on_cell_clicked: Optional[EventType] = None, on_cell_clicked: Optional[EventType[tuple[int, int]]] = None,
on_cell_context_menu: Optional[EventType] = None, on_cell_context_menu: Optional[EventType[tuple[int, int]]] = None,
on_cell_edited: Optional[EventType] = None, on_cell_edited: Optional[EventType] = None,
on_click: Optional[EventType[[]]] = None, on_click: Optional[EventType[[]]] = None,
on_column_resize: Optional[EventType] = None, on_column_resize: Optional[EventType[GridColumn, int, int]] = None,
on_context_menu: Optional[EventType[[]]] = None, on_context_menu: Optional[EventType[[]]] = None,
on_delete: Optional[EventType] = None, on_delete: Optional[EventType[GridSelection]] = None,
on_double_click: Optional[EventType[[]]] = None, on_double_click: Optional[EventType[[]]] = None,
on_finished_editing: Optional[EventType] = None, on_finished_editing: Optional[
EventType[Union[GridCell, None], list[int]]
] = None,
on_focus: Optional[EventType[[]]] = None, on_focus: Optional[EventType[[]]] = None,
on_group_header_clicked: Optional[EventType] = None, on_group_header_clicked: Optional[EventType] = None,
on_group_header_context_menu: Optional[EventType] = None, on_group_header_context_menu: Optional[
on_group_header_renamed: Optional[EventType] = None, EventType[int, GroupHeaderClickedEventArgs]
on_header_clicked: Optional[EventType] = None, ] = None,
on_header_context_menu: Optional[EventType] = None, on_group_header_renamed: Optional[EventType[str, str]] = None,
on_header_menu_click: Optional[EventType] = None, on_header_clicked: Optional[EventType[tuple[int, int]]] = None,
on_item_hovered: Optional[EventType] = None, on_header_context_menu: Optional[EventType[tuple[int, int]]] = None,
on_header_menu_click: Optional[EventType[int, Rectangle]] = None,
on_item_hovered: Optional[EventType[tuple[int, int]]] = None,
on_mount: Optional[EventType[[]]] = None, on_mount: Optional[EventType[[]]] = None,
on_mouse_down: Optional[EventType[[]]] = None, on_mouse_down: Optional[EventType[[]]] = None,
on_mouse_enter: Optional[EventType[[]]] = None, on_mouse_enter: Optional[EventType[[]]] = None,

View File

@ -16,7 +16,7 @@ from itertools import chain
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
from pathlib import Path from pathlib import Path
from types import ModuleType, SimpleNamespace from types import ModuleType, SimpleNamespace
from typing import Any, Callable, Iterable, Type, get_args from typing import Any, Callable, Iterable, Type, get_args, get_origin
from reflex.components.component import Component from reflex.components.component import Component
from reflex.utils import types as rx_types from reflex.utils import types as rx_types
@ -372,6 +372,53 @@ def _extract_class_props_as_ast_nodes(
return kwargs return kwargs
def type_to_ast(typ) -> ast.AST:
"""Converts any type annotation into its AST representation.
Handles nested generic types, unions, etc.
Args:
typ: The type annotation to convert.
Returns:
The AST representation of the type annotation.
"""
if typ is type(None):
return ast.Name(id="None")
origin = get_origin(typ)
# Handle plain types (int, str, custom classes, etc.)
if origin is None:
if hasattr(typ, "__name__"):
return ast.Name(id=typ.__name__)
elif hasattr(typ, "_name"):
return ast.Name(id=typ._name)
return ast.Name(id=str(typ))
# Get the base type name (List, Dict, Optional, etc.)
base_name = origin._name if hasattr(origin, "_name") else origin.__name__
# Get type arguments
args = get_args(typ)
# Handle empty type arguments
if not args:
return ast.Name(id=base_name)
# Convert all type arguments recursively
arg_nodes = [type_to_ast(arg) for arg in args]
# Special case for single-argument types (like List[T] or Optional[T])
if len(arg_nodes) == 1:
slice_value = arg_nodes[0]
else:
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
return ast.Subscript(
value=ast.Name(id=base_name), slice=ast.Index(value=slice_value), ctx=ast.Load()
)
def _get_parent_imports(func): def _get_parent_imports(func):
_imports = {"reflex.vars": ["Var"]} _imports = {"reflex.vars": ["Var"]}
for type_hint in inspect.get_annotations(func).values(): for type_hint in inspect.get_annotations(func).values():
@ -430,13 +477,40 @@ def _generate_component_create_functiondef(
def figure_out_return_type(annotation: Any): def figure_out_return_type(annotation: Any):
if inspect.isclass(annotation) and issubclass(annotation, inspect._empty): if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
return ast.Name(id="Optional[EventType]") return ast.Name(id="Optional[EventType]")
if not isinstance(annotation, str) and get_origin(annotation) is tuple:
arguments = get_args(annotation)
arguments_without_var = [
get_args(argument)[0] if get_origin(argument) == Var else argument
for argument in arguments
]
# Convert each argument type to its AST representation
type_args = [type_to_ast(arg) for arg in arguments_without_var]
# Join the type arguments with commas for EventType
args_str = ", ".join(ast.unparse(arg) for arg in type_args)
# Create EventType using the joined string
event_type = ast.Name(id=f"EventType[{args_str}]")
# Wrap in Optional
optional_type = ast.Subscript(
value=ast.Name(id="Optional"),
slice=ast.Index(value=event_type),
ctx=ast.Load(),
)
return ast.Name(id=ast.unparse(optional_type))
if isinstance(annotation, str) and annotation.startswith("Tuple["): if isinstance(annotation, str) and annotation.startswith("Tuple["):
inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]") inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
if inside_of_tuple == "()": if inside_of_tuple == "()":
return ast.Name(id="Optional[EventType[[]]]") return ast.Name(id="Optional[EventType[[]]]")
arguments: list[str] = [""] arguments = [""]
bracket_count = 0 bracket_count = 0