11from __future__ import annotations
22
3+ import json
34from abc import abstractmethod
45from typing import TYPE_CHECKING , Any , ClassVar , Self , TypeAlias , overload
56
@@ -25,6 +26,47 @@ class _Adaptor:
2526 def __init__ (self , data : Any ) -> None :
2627 self ._d = data
2728
29+ @overload
30+ def write_json (self , file : str ) -> None : ...
31+ @overload
32+ def write_json (self , file : None ) -> str : ...
33+ def write_json (self , file = None ):
34+ if file is None :
35+ msg = (
36+ f"Writing to JSON string rather than file is not supported for "
37+ f"{ type (self ._d )} "
38+ )
39+ raise NotImplementedError (msg )
40+
41+ import json
42+
43+ json .dump (self ._d , open (file , mode = "w" ))
44+
45+ def write_joblib (self , file : str ) -> None :
46+ import joblib
47+
48+ joblib .dump (self ._d , file )
49+
50+ def write_csv (self , file : str ) -> None :
51+ msg = f"Writing to CSV is not supported for { type (self ._d )} "
52+ raise NotImplementedError (msg )
53+
54+ def write_parquet (self , file : str ) -> None :
55+ msg = f"Writing to Parquet is not supported for { type (self ._d )} "
56+ raise NotImplementedError (msg )
57+
58+ def write_feather (self , file : str ) -> None :
59+ msg = f"Writing to Feather is not supported for { type (self ._d )} "
60+ raise NotImplementedError (msg )
61+
62+ @property
63+ def data_preview (self ) -> str :
64+ # note that the R library uses jsonlite::toJSON
65+ import json
66+
67+ # TODO(compat): set display none in index.html
68+ return json .dumps ({})
69+
2870
2971class _DFAdaptor (_Adaptor ):
3072 _d : ClassVar [_DataFrame ]
@@ -39,12 +81,20 @@ def columns(self) -> list[Any]: ...
3981 @abstractmethod
4082 def head (self , n : int ) -> Self : ...
4183
42- @abstractmethod
43- def write_json (self ) -> str :
44- """Write the dataframe to a JSON string.
84+ @property
85+ def data_preview (self ) -> str :
86+ # TODO(compat) is 100 hard-coded?
87+ # Note that we go df -> json -> dict, to take advantage of type conversions in the dataframe library
88+ data : list [dict [Any , Any ]] = json .loads (self .head (100 ).write_json ())
89+ columns = [
90+ {"name" : [col ], "label" : [col ], "align" : ["left" ], "type" : ["" ]}
91+ for col in self .columns
92+ ]
4593
46- In the format: list like [{column -> value}, ... , {column -> value}]
47- """
94+ # this reproduces R pins behavior, by omitting entries that would be null
95+ data_no_nulls = [{k : v for k , v in row .items () if v is not None } for row in data ]
96+
97+ return json .dumps ({"data" : data_no_nulls , "columns" : columns })
4898
4999
50100class _PandasAdaptor (_DFAdaptor ):
@@ -53,22 +103,43 @@ def __init__(self, data: _AbstractPandasFrame) -> None:
53103
54104 @property
55105 def columns (self ) -> list [Any ]:
56- return self ._d .columns
106+ return self ._d .columns . tolist ()
57107
58108 def head (self , n : int ) -> Self :
59109 return _PandasAdaptor (self ._d .head (n ))
60110
61- def write_json (self ) -> str :
111+ @overload
112+ def write_json (self , file : str ) -> None : ...
113+ @overload
114+ def write_json (self , file : None ) -> str : ...
115+ def write_json (self , file = None ):
116+ if file is not None :
117+ msg = (
118+ f"Writing to file rather than JSON string is not supported for "
119+ f"{ type (self ._d )} "
120+ )
121+ raise NotImplementedError (msg )
122+
62123 return self ._d .to_json (orient = "records" )
63124
125+ def write_csv (self , file : str ) -> None :
126+ self ._d .to_csv (file , index = False )
127+
128+ def write_parquet (self , file : str ) -> None :
129+ self ._d .to_parquet (file )
130+
131+ def write_feather (self , file : str ) -> None :
132+ self ._d .to_feather (file )
133+
64134
65135@overload
66- def _create_df_adaptor ( df : _DataFrame ) -> _DFAdaptor : ...
136+ def _create_adaptor ( obj : Any ) -> _Adaptor : ...
67137@overload
68- def _create_df_adaptor (df : _PandasDataFrame ) -> _PandasAdaptor : ...
69- def _create_df_adaptor (df ):
70- if isinstance (df , _AbstractPandasFrame ):
71- return _PandasAdaptor (df )
72-
73- msg = f"Could not determine dataframe adaptor for { df } "
74- raise NotImplementedError (msg )
138+ def _create_adaptor (obj : _DataFrame ) -> _DFAdaptor : ...
139+ @overload
140+ def _create_adaptor (obj : _PandasDataFrame ) -> _PandasAdaptor : ...
141+ def _create_adaptor (obj ):
142+ if isinstance (obj , _AbstractPandasFrame ):
143+ return _PandasAdaptor (obj )
144+ else :
145+ return _Adaptor (obj )
0 commit comments