2
2
3
3
import warnings
4
4
5
- # TODO-barret; Make DataFrameLikeT generic bound to DataFrameLike. Add this generic type to the DataGrid and DataTable
6
- # TODO-barret; Should `.input_cell_selection()` ever return None? Is that value even helpful? Empty lists would be much more user friendly.
7
- # * For next release: Agreed to remove `None` type.
8
- # * For this release: Immediately make PR to remove `.input_` from `.input_cell_selection()`
9
5
# TODO-barret-render.data_frame; Docs
10
6
# TODO-barret-render.data_frame; Add examples!
11
- from typing import TYPE_CHECKING , Any , Awaitable , Callable , Dict , Literal , Union , cast
7
+ from typing import TYPE_CHECKING , Any , Awaitable , Callable , Literal , Union , cast
12
8
13
9
from htmltools import Tag
14
10
36
32
)
37
33
from ._data_frame_utils ._styles import as_browser_style_infos
38
34
from ._data_frame_utils ._tbl_data import (
39
- apply_frame_patches ,
40
- as_data_frame_like ,
35
+ apply_frame_patches__typed ,
41
36
frame_columns ,
42
37
frame_shape ,
43
38
serialize_dtype ,
44
- subset_frame ,
39
+ subset_frame__typed ,
45
40
)
46
41
from ._data_frame_utils ._types import (
47
42
CellPatchProcessed ,
48
43
ColumnFilter ,
49
44
ColumnSort ,
50
- DataFrameLike ,
45
+ DataFrameLikeT ,
46
+ FrameDtype ,
51
47
FrameRender ,
52
48
cell_patch_processed_to_jsonifiable ,
53
49
frame_render_to_jsonifiable ,
59
55
if TYPE_CHECKING :
60
56
from ..session import Session
61
57
62
- from ._data_frame_utils ._datagridtable import DataFrameResult
58
+ DataFrameResult = Union [
59
+ None ,
60
+ DataFrameLikeT ,
61
+ "DataGrid[DataFrameLikeT]" ,
62
+ "DataTable[DataFrameLikeT]" ,
63
+ ]
64
+ DataFrameValue = Union [None , DataGrid [DataFrameLikeT ], DataTable [DataFrameLikeT ]]
65
+
63
66
64
67
# # TODO-future; Use `dataframe-api-compat>=0.2.6` to injest dataframes and return standardized dataframe structures
65
68
# # TODO-future: Find this type definition: https://github.com/data-apis/dataframe-api-compat/blob/273c0be45962573985b3a420869d0505a3f9f55d/dataframe_api_compat/polars_standard/dataframe_object.py#L22
92
95
93
96
94
97
@add_example ()
95
- class data_frame (Renderer [DataFrameResult ]):
98
+ class data_frame (Renderer [DataFrameResult [ DataFrameLikeT ] ]):
96
99
"""
97
100
Decorator for a function that returns a pandas `DataFrame` object (or similar) to
98
101
render as an interactive table or grid. Features fast virtualized scrolling, sorting,
@@ -164,11 +167,11 @@ class data_frame(Renderer[DataFrameResult]):
164
167
objects you can return from the rendering function to specify options.
165
168
"""
166
169
167
- _value : reactive .Value [DataFrameResult | None ]
170
+ _value : reactive .Value [DataFrameValue [ DataFrameLikeT ] | None ]
168
171
"""
169
172
Reactive value of the data frame's rendered object.
170
173
"""
171
- _type_hints : reactive .Value [dict [ str , str ] | None ]
174
+ _type_hints : reactive .Value [list [ FrameDtype ] | None ]
172
175
"""
173
176
Reactive value of the data frame's type hints for each column.
174
177
@@ -206,7 +209,7 @@ class data_frame(Renderer[DataFrameResult]):
206
209
Reactive value of the data frame's edits provided by the user.
207
210
"""
208
211
209
- data : reactive .Calc_ [DataFrameLike ]
212
+ data : reactive .Calc_ [DataFrameLikeT ]
210
213
"""
211
214
Reactive value of the data frame's output data.
212
215
@@ -217,17 +220,17 @@ class data_frame(Renderer[DataFrameResult]):
217
220
Even if the rendered data value was not of type `pd.DataFrame` or `pl.DataFrame`, this method currently
218
221
converts it to a `pd.DataFrame`.
219
222
"""
220
- _data_view_all : reactive .Calc_ [DataFrameLike ]
223
+ _data_view_all : reactive .Calc_ [DataFrameLikeT ]
221
224
"""
222
225
Reactive value of the full (sorted and filtered) data.
223
226
"""
224
- _data_view_selected : reactive .Calc_ [DataFrameLike ]
227
+ _data_view_selected : reactive .Calc_ [DataFrameLikeT ]
225
228
"""
226
229
Reactive value of the selected rows of the (sorted and filtered) data.
227
230
"""
228
231
229
232
@add_example (ex_dir = "../api-examples/data_frame_data_view" )
230
- def data_view (self , * , selected : bool = False ) -> DataFrameLike :
233
+ def data_view (self , * , selected : bool = False ) -> DataFrameLikeT :
231
234
"""
232
235
Reactive function that retrieves the data how it is viewed within the browser.
233
236
@@ -299,7 +302,7 @@ def data_view(self, *, selected: bool = False) -> DataFrameLike:
299
302
The row numbers of the data frame that are currently being viewed in the browser
300
303
after sorting and filtering has been applied.
301
304
"""
302
- _data_patched : reactive .Calc_ [DataFrameLike ]
305
+ _data_patched : reactive .Calc_ [DataFrameLikeT ]
303
306
"""
304
307
Reactive value of the data frame's patched data.
305
308
@@ -339,8 +342,10 @@ def _init_reactives(self) -> None:
339
342
from .. import req
340
343
341
344
# Init
342
- self ._value : reactive .Value [DataFrameResult | None ] = reactive .Value (None )
343
- self ._type_hints : reactive .Value [dict [str , str ] | None ] = reactive .Value (None )
345
+ self ._value : reactive .Value [DataFrameValue [DataFrameLikeT ] | None ] = (
346
+ reactive .Value (None )
347
+ )
348
+ self ._type_hints : reactive .Value [list [FrameDtype ] | None ] = reactive .Value (None )
344
349
self ._cell_patch_map = reactive .Value ({})
345
350
346
351
@reactive .calc
@@ -350,7 +355,7 @@ def self_cell_patches() -> list[CellPatchProcessed]:
350
355
self .cell_patches = self_cell_patches
351
356
352
357
@reactive .calc
353
- def self_data () -> DataFrameLike :
358
+ def self_data () -> DataFrameLikeT :
354
359
value = self ._value ()
355
360
req (value )
356
361
@@ -423,14 +428,14 @@ def self_data_view_rows() -> tuple[int, ...]:
423
428
self .data_view_rows = self_data_view_rows
424
429
425
430
@reactive .calc
426
- def self__data_patched () -> DataFrameLike :
427
- return apply_frame_patches (self .data (), self .cell_patches ())
431
+ def self__data_patched () -> DataFrameLikeT :
432
+ return apply_frame_patches__typed (self .data (), self .cell_patches ())
428
433
429
434
self ._data_patched = self__data_patched
430
435
431
436
# Apply filtering and sorting
432
437
# https://github.com/posit-dev/py-shiny/issues/1240
433
- def _subset_data_view (selected : bool ) -> DataFrameLike :
438
+ def _subset_data_view (selected : bool ) -> DataFrameLikeT :
434
439
"""
435
440
Helper method to subset data according to what is viewed in the browser;
436
441
@@ -454,15 +459,15 @@ def _subset_data_view(selected: bool) -> DataFrameLike:
454
459
else :
455
460
rows = self .data_view_rows ()
456
461
457
- return subset_frame (self ._data_patched (), rows = rows )
462
+ return subset_frame__typed (self ._data_patched (), rows = rows )
458
463
459
464
# Helper reactives so that internal calculations can be cached for use in other calculations
460
465
@reactive .calc
461
- def self__data_view () -> DataFrameLike :
466
+ def self__data_view () -> DataFrameLikeT :
462
467
return _subset_data_view (selected = False )
463
468
464
469
@reactive .calc
465
- def self__data_view_selected () -> DataFrameLike :
470
+ def self__data_view_selected () -> DataFrameLikeT :
466
471
return _subset_data_view (selected = True )
467
472
468
473
self ._data_view_all = self__data_view
@@ -721,7 +726,7 @@ async def _attempt_update_cell_style(self) -> None:
721
726
def auto_output_ui (self ) -> Tag :
722
727
return ui .output_data_frame (id = self .output_id )
723
728
724
- def __init__ (self , fn : ValueFn [DataFrameResult ]):
729
+ def __init__ (self , fn : ValueFn [DataFrameResult [ DataFrameLikeT ] ]):
725
730
super ().__init__ (fn )
726
731
727
732
# Set reactives from calculated properties
@@ -758,26 +763,22 @@ async def render(self) -> JsonifiableDict | None:
758
763
return None
759
764
760
765
if not isinstance (value , AbstractTabularData ):
761
- value = DataGrid (
762
- as_data_frame_like (
763
- value ,
764
- "@render.data_frame doesn't know how to render objects of type" ,
765
- )
766
- )
766
+ try :
767
+ value = DataGrid (value )
768
+ except TypeError as e :
769
+ raise TypeError (
770
+ "@render.data_frame doesn't know how to render objects of type " ,
771
+ type (value ),
772
+ ) from e
767
773
768
774
# Set patches url handler for client
769
775
patch_key = self ._set_patches_handler ()
770
- self ._value .set (value )
776
+ self ._value .set (value ) # pyright: ignore[reportArgumentType]
771
777
772
778
# Use session context so `to_payload()` gets the correct session
773
779
with session_context (self ._get_session ()):
774
780
payload = value .to_payload ()
775
-
776
- type_hints = cast (
777
- Union [Dict [str , str ], None ],
778
- payload .get ("typeHints" , None ),
779
- )
780
- self ._type_hints .set (type_hints )
781
+ self ._type_hints .set (payload ["typeHints" ])
781
782
782
783
ret : FrameRender = {
783
784
"payload" : payload ,
0 commit comments