mitosheet 0.2.53__py2.py3-none-any.whl → 0.2.55__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mitosheet/dataframe_display_formatters.py +33 -66
- mitosheet/formatter/__init__.py +10 -0
- mitosheet/formatter/viewer.py +148 -0
- mitosheet/labextension/package.json +23 -7
- mitosheet/labextension/static/339.967abbd46339aee7868c.js +1 -0
- mitosheet/labextension/static/418.0ec6f919714352f77210.js +1 -0
- mitosheet/labextension/static/remoteEntry.b3dffe9fd1efc1d162d4.js +1 -0
- mitosheet/saved_analyses/save_utils.py +1 -1
- mitosheet/tests/test_formatter.py +240 -0
- {mitosheet-0.2.53.data → mitosheet-0.2.55.data}/data/share/jupyter/labextensions/mitosheet/package.json +23 -7
- mitosheet-0.2.55.data/data/share/jupyter/labextensions/mitosheet/static/339.967abbd46339aee7868c.js +1 -0
- mitosheet-0.2.55.data/data/share/jupyter/labextensions/mitosheet/static/418.0ec6f919714352f77210.js +1 -0
- mitosheet-0.2.55.data/data/share/jupyter/labextensions/mitosheet/static/remoteEntry.b3dffe9fd1efc1d162d4.js +1 -0
- {mitosheet-0.2.53.dist-info → mitosheet-0.2.55.dist-info}/METADATA +5 -2
- {mitosheet-0.2.53.dist-info → mitosheet-0.2.55.dist-info}/RECORD +22 -17
- mitosheet/labextension/static/339.5f826c48e1170f2309de.js +0 -1
- mitosheet/labextension/static/remoteEntry.905183b0f55e620383e3.js +0 -1
- mitosheet-0.2.53.data/data/share/jupyter/labextensions/mitosheet/static/339.5f826c48e1170f2309de.js +0 -1
- mitosheet-0.2.53.data/data/share/jupyter/labextensions/mitosheet/static/remoteEntry.905183b0f55e620383e3.js +0 -1
- {mitosheet-0.2.53.data → mitosheet-0.2.55.data}/data/share/jupyter/labextensions/mitosheet/static/405.4dea6fd8e64e4dc9015a.js +0 -0
- {mitosheet-0.2.53.data → mitosheet-0.2.55.data}/data/share/jupyter/labextensions/mitosheet/static/509.9cd86a57778b85719494.js +0 -0
- {mitosheet-0.2.53.data → mitosheet-0.2.55.data}/data/share/jupyter/labextensions/mitosheet/static/style.js +0 -0
- {mitosheet-0.2.53.data → mitosheet-0.2.55.data}/data/share/jupyter/labextensions/mitosheet/static/third-party-licenses.json +0 -0
- {mitosheet-0.2.53.dist-info → mitosheet-0.2.55.dist-info}/LICENSE.txt +0 -0
- {mitosheet-0.2.53.dist-info → mitosheet-0.2.55.dist-info}/WHEEL +0 -0
- {mitosheet-0.2.53.dist-info → mitosheet-0.2.55.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
# Copyright (c) Saga Inc.
|
|
4
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Tests for the formatter module, specifically the format_dataframe_mimetype function.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
import pandas as pd
|
|
13
|
+
|
|
14
|
+
from mitosheet.formatter.viewer import format_dataframe_mimetype
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_format_dataframe_mimetype_basic():
|
|
18
|
+
"""Test basic DataFrame formatting."""
|
|
19
|
+
df = pd.DataFrame({"A": [1, 2, 3], "B": ["foo", "bar", "baz"]})
|
|
20
|
+
|
|
21
|
+
result = format_dataframe_mimetype(df)
|
|
22
|
+
|
|
23
|
+
assert result is not None
|
|
24
|
+
assert "columns" in result
|
|
25
|
+
assert "data" in result
|
|
26
|
+
assert "totalRows" in result
|
|
27
|
+
assert "indexLevels" in result
|
|
28
|
+
assert "columnLevels" in result
|
|
29
|
+
|
|
30
|
+
assert result["totalRows"] == 3
|
|
31
|
+
assert result["indexLevels"] == 1
|
|
32
|
+
assert result["columnLevels"] == 1
|
|
33
|
+
|
|
34
|
+
# Check column metadata
|
|
35
|
+
columns = result["columns"]
|
|
36
|
+
assert len(columns) == 3 # index + 2 data columns
|
|
37
|
+
assert columns[0]["name"] == ["index"]
|
|
38
|
+
assert columns[1]["name"] == ["A"]
|
|
39
|
+
assert columns[2]["name"] == ["B"]
|
|
40
|
+
|
|
41
|
+
# Check data
|
|
42
|
+
data = json.loads(result["data"])
|
|
43
|
+
assert len(data) == 3
|
|
44
|
+
assert data[0] == [0, 1, "foo"]
|
|
45
|
+
assert data[1] == [1, 2, "bar"]
|
|
46
|
+
assert data[2] == [2, 3, "baz"]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_format_dataframe_mimetype_with_named_index():
|
|
50
|
+
"""Test DataFrame with named index."""
|
|
51
|
+
df = pd.DataFrame({"A": [1, 2, 3], "B": ["foo", "bar", "baz"]})
|
|
52
|
+
df.index.name = "my_index"
|
|
53
|
+
|
|
54
|
+
result = format_dataframe_mimetype(df)
|
|
55
|
+
|
|
56
|
+
assert result is not None
|
|
57
|
+
assert result["columns"][0]["name"] == ["my_index"]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_format_dataframe_mimetype_with_datetime_index():
|
|
61
|
+
"""Test DataFrame with datetime index."""
|
|
62
|
+
dates = pd.date_range("2023-01-01", periods=3, freq="D")
|
|
63
|
+
df = pd.DataFrame({"A": [1, 2, 3], "B": ["foo", "bar", "baz"]}, index=dates)
|
|
64
|
+
|
|
65
|
+
result = format_dataframe_mimetype(df)
|
|
66
|
+
|
|
67
|
+
assert result is not None
|
|
68
|
+
data = json.loads(result["data"])
|
|
69
|
+
assert len(data) == 3
|
|
70
|
+
# Check that datetime is formatted correctly
|
|
71
|
+
assert data[0][0] == "2023-01-01T00:00:00.000"
|
|
72
|
+
assert data[1][0] == "2023-01-02T00:00:00.000"
|
|
73
|
+
assert data[2][0] == "2023-01-03T00:00:00.000"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_format_dataframe_mimetype_with_multiindex():
|
|
77
|
+
"""Test DataFrame with MultiIndex."""
|
|
78
|
+
index = pd.MultiIndex.from_tuples(
|
|
79
|
+
[("A", 1), ("A", 2), ("B", 1)], names=["letter", "number"]
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
df = pd.DataFrame({"X": [10, 20, 30], "Y": [40, 50, 60]}, index=index)
|
|
83
|
+
|
|
84
|
+
result = format_dataframe_mimetype(df)
|
|
85
|
+
|
|
86
|
+
assert result is not None
|
|
87
|
+
assert result["indexLevels"] == 2
|
|
88
|
+
|
|
89
|
+
# Check column metadata includes both index levels
|
|
90
|
+
columns = result["columns"]
|
|
91
|
+
assert len(columns) == 4 # 2 index levels + 2 data columns
|
|
92
|
+
assert columns[0]["name"] == ["letter"]
|
|
93
|
+
assert columns[1]["name"] == ["number"]
|
|
94
|
+
assert columns[2]["name"] == ["X"]
|
|
95
|
+
assert columns[3]["name"] == ["Y"]
|
|
96
|
+
|
|
97
|
+
# Check data
|
|
98
|
+
data = json.loads(result["data"])
|
|
99
|
+
assert len(data) == 3
|
|
100
|
+
assert data[0] == ["A", 1, 10, 40]
|
|
101
|
+
assert data[1] == ["A", 2, 20, 50]
|
|
102
|
+
assert data[2] == ["B", 1, 30, 60]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_format_dataframe_mimetype_with_nan_values():
|
|
106
|
+
"""Test DataFrame with NaN values."""
|
|
107
|
+
df = pd.DataFrame(
|
|
108
|
+
{"A": [1, None, 3], "B": ["foo", None, "baz"], "C": [1.5, float("nan"), 3.5]}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
result = format_dataframe_mimetype(df)
|
|
112
|
+
|
|
113
|
+
assert result is not None
|
|
114
|
+
data = json.loads(result["data"])
|
|
115
|
+
assert len(data) == 3
|
|
116
|
+
# NaN values should be converted to empty strings
|
|
117
|
+
assert data[0] == [0, 1.0, "foo", 1.5]
|
|
118
|
+
assert data[1] == [1, None, None, None]
|
|
119
|
+
assert data[2] == [2, 3.0, "baz", 3.5]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_format_dataframe_mimetype_truncation():
|
|
123
|
+
"""Test DataFrame truncation when exceeding display.max_rows."""
|
|
124
|
+
# Create a DataFrame with more rows than the default display.max_rows
|
|
125
|
+
df = pd.DataFrame({"A": range(100), "B": [f"val_{i}" for i in range(100)]})
|
|
126
|
+
|
|
127
|
+
# Temporarily set display.max_rows to a small value
|
|
128
|
+
original_max_rows = pd.get_option("display.max_rows")
|
|
129
|
+
pd.set_option("display.max_rows", 10)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
result = format_dataframe_mimetype(df)
|
|
133
|
+
|
|
134
|
+
assert result is not None
|
|
135
|
+
assert result["totalRows"] == 100
|
|
136
|
+
assert len(json.loads(result["data"])) < result["totalRows"]
|
|
137
|
+
|
|
138
|
+
finally:
|
|
139
|
+
# Restore original setting
|
|
140
|
+
pd.set_option("display.max_rows", original_max_rows)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_format_dataframe_mimetype_describe_output():
|
|
144
|
+
"""Test that describe() output returns None."""
|
|
145
|
+
df = pd.DataFrame({"A": [1, 2, 3, 4, 5], "B": [10, 20, 30, 40, 50]})
|
|
146
|
+
describe_df = df.describe()
|
|
147
|
+
|
|
148
|
+
result = format_dataframe_mimetype(describe_df)
|
|
149
|
+
|
|
150
|
+
# Should return None for describe() output
|
|
151
|
+
assert result is None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_format_dataframe_mimetype_empty_dataframe():
|
|
155
|
+
"""Test empty DataFrame."""
|
|
156
|
+
df = pd.DataFrame()
|
|
157
|
+
|
|
158
|
+
result = format_dataframe_mimetype(df)
|
|
159
|
+
|
|
160
|
+
assert result is not None
|
|
161
|
+
assert result["totalRows"] == 0
|
|
162
|
+
assert len(json.loads(result["data"])) == 0
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_format_dataframe_mimetype_single_column():
|
|
166
|
+
"""Test DataFrame with single column."""
|
|
167
|
+
df = pd.DataFrame({"A": [1, 2, 3]})
|
|
168
|
+
|
|
169
|
+
result = format_dataframe_mimetype(df)
|
|
170
|
+
|
|
171
|
+
assert result is not None
|
|
172
|
+
columns = result["columns"]
|
|
173
|
+
assert len(columns) == 2 # index + 1 data column
|
|
174
|
+
assert columns[0]["name"] == ["index"]
|
|
175
|
+
assert columns[1]["name"] == ["A"]
|
|
176
|
+
|
|
177
|
+
data = json.loads(result["data"])
|
|
178
|
+
assert len(data) == 3
|
|
179
|
+
assert data[0] == [0, 1]
|
|
180
|
+
assert data[1] == [1, 2]
|
|
181
|
+
assert data[2] == [2, 3]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_format_dataframe_mimetype_with_different_dtypes():
|
|
185
|
+
"""Test DataFrame with different column dtypes."""
|
|
186
|
+
df = pd.DataFrame(
|
|
187
|
+
{
|
|
188
|
+
"int_col": [1, 2, 3],
|
|
189
|
+
"float_col": [1.1, 2.2, 3.3],
|
|
190
|
+
"str_col": ["a", "b", "c"],
|
|
191
|
+
"bool_col": [True, False, True],
|
|
192
|
+
"datetime_col": pd.date_range("2023-01-01", periods=3),
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
result = format_dataframe_mimetype(df)
|
|
197
|
+
|
|
198
|
+
assert result is not None
|
|
199
|
+
columns = result["columns"]
|
|
200
|
+
|
|
201
|
+
# Check that dtypes are preserved in metadata
|
|
202
|
+
dtype_names = [col["dtype"] for col in columns]
|
|
203
|
+
assert "int64" in dtype_names or "int32" in dtype_names
|
|
204
|
+
assert "float64" in dtype_names or "float32" in dtype_names
|
|
205
|
+
assert "object" in dtype_names # strings
|
|
206
|
+
assert "bool" in dtype_names
|
|
207
|
+
assert any("datetime64" in dtype for dtype in dtype_names)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_format_dataframe_mimetype_with_multiindex_columns():
|
|
211
|
+
"""Test DataFrame with MultiIndex columns."""
|
|
212
|
+
# Create a DataFrame with MultiIndex columns
|
|
213
|
+
columns = pd.MultiIndex.from_tuples(
|
|
214
|
+
[("A", "one"), ("A", "two"), ("B", "one"), ("B", "two")],
|
|
215
|
+
names=["level_0", "level_1"],
|
|
216
|
+
)
|
|
217
|
+
df = pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], columns=columns)
|
|
218
|
+
|
|
219
|
+
result = format_dataframe_mimetype(df)
|
|
220
|
+
|
|
221
|
+
assert result is not None
|
|
222
|
+
assert result["columnLevels"] == 2
|
|
223
|
+
|
|
224
|
+
# Check column metadata
|
|
225
|
+
columns_result = result["columns"]
|
|
226
|
+
assert len(columns_result) == 5 # index + 4 data columns
|
|
227
|
+
|
|
228
|
+
# Check that column names are lists representing the multi-index structure
|
|
229
|
+
assert columns_result[0]["name"] == ["index"] # index column
|
|
230
|
+
assert columns_result[1]["name"] == ["A", "one"] # first multi-index column
|
|
231
|
+
assert columns_result[2]["name"] == ["A", "two"]
|
|
232
|
+
assert columns_result[3]["name"] == ["B", "one"]
|
|
233
|
+
assert columns_result[4]["name"] == ["B", "two"]
|
|
234
|
+
|
|
235
|
+
# Check data
|
|
236
|
+
data = json.loads(result["data"])
|
|
237
|
+
assert len(data) == 3
|
|
238
|
+
assert data[0] == [0, 1, 2, 3, 4]
|
|
239
|
+
assert data[1] == [1, 5, 6, 7, 8]
|
|
240
|
+
assert data[2] == [2, 9, 10, 11, 12]
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"jupyterlab": {
|
|
10
10
|
"outputDir": "mitosheet/labextension",
|
|
11
11
|
"extension": "lib/plugin",
|
|
12
|
+
"mimeExtension": "lib/viewer/renderer",
|
|
12
13
|
"_build": {
|
|
13
|
-
"load": "static/remoteEntry.
|
|
14
|
-
"extension": "./extension"
|
|
14
|
+
"load": "static/remoteEntry.b3dffe9fd1efc1d162d4.js",
|
|
15
|
+
"extension": "./extension",
|
|
16
|
+
"mimeExtension": "./mimeExtension"
|
|
15
17
|
}
|
|
16
18
|
},
|
|
17
19
|
"name": "mitosheet",
|
|
@@ -21,16 +23,18 @@
|
|
|
21
23
|
"email": "aaron@sagacollab.com"
|
|
22
24
|
},
|
|
23
25
|
"bugs": {
|
|
24
|
-
"url": "https://github.com/mito-ds/
|
|
26
|
+
"url": "https://github.com/mito-ds/mito/issues"
|
|
25
27
|
},
|
|
26
28
|
"repository": {
|
|
27
|
-
"url": "https://github.com/mito-ds/
|
|
29
|
+
"url": "https://github.com/mito-ds/mito",
|
|
28
30
|
"type": "git"
|
|
29
31
|
},
|
|
30
|
-
"version": "0.2.
|
|
32
|
+
"version": "0.2.55",
|
|
31
33
|
"dependencies": {
|
|
32
34
|
"@jupyterlab/application": "^4.0.0",
|
|
33
35
|
"@jupyterlab/notebook": "^4.2.4",
|
|
36
|
+
"@jupyterlab/rendermime-interfaces": "^3.0.0",
|
|
37
|
+
"@jupyterlab/ui-components": "^4.0.0",
|
|
34
38
|
"@types/fscreen": "^1.0.1",
|
|
35
39
|
"@types/react-dom": "^18.3.0",
|
|
36
40
|
"fscreen": "^1.1.0",
|
|
@@ -70,7 +74,10 @@
|
|
|
70
74
|
"lint": "eslint src/ --ext .ts,.tsx --fix",
|
|
71
75
|
"prepack": "jlpm run build:all",
|
|
72
76
|
"build:docs:update_frontend": "python docs/make_function_docs.py update_frontend",
|
|
73
|
-
"build:docs:generate_markdown": "python docs/make_function_docs.py generate_markdown"
|
|
77
|
+
"build:docs:generate_markdown": "python docs/make_function_docs.py generate_markdown",
|
|
78
|
+
"test": "jest",
|
|
79
|
+
"test:watch": "jest --watch",
|
|
80
|
+
"test:coverage": "jest --coverage"
|
|
74
81
|
},
|
|
75
82
|
"keywords": [
|
|
76
83
|
"jupyter",
|
|
@@ -82,7 +89,12 @@
|
|
|
82
89
|
],
|
|
83
90
|
"devDependencies": {
|
|
84
91
|
"@jupyterlab/builder": "^4.0.0",
|
|
92
|
+
"@testing-library/dom": "^10.4.1",
|
|
93
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
94
|
+
"@testing-library/react": "^16.3.0",
|
|
95
|
+
"@testing-library/user-event": "^14.6.1",
|
|
85
96
|
"@types/expect.js": "^0.3.29",
|
|
97
|
+
"@types/jest": "^30.0.0",
|
|
86
98
|
"@types/node": "^18.19.43",
|
|
87
99
|
"@types/react": "^18.3.3",
|
|
88
100
|
"@typescript-eslint/eslint-plugin": "^4.8.1",
|
|
@@ -96,15 +108,19 @@
|
|
|
96
108
|
"expect.js": "^0.3.1",
|
|
97
109
|
"file-loader": "^6.2.0",
|
|
98
110
|
"fs-extra": "^10.0.0",
|
|
111
|
+
"identity-obj-proxy": "^3.0.0",
|
|
112
|
+
"jest": "^30.2.0",
|
|
113
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
99
114
|
"mkdirp": "^1.0.4",
|
|
100
115
|
"mocha": "^9.1.2",
|
|
101
116
|
"npm-run-all": "^4.1.5",
|
|
102
117
|
"prettier": "^2.1.1",
|
|
103
118
|
"rimraf": "^3.0.2",
|
|
119
|
+
"ts-jest": "^29.4.6",
|
|
104
120
|
"typescript": "^5.5.4"
|
|
105
121
|
},
|
|
106
122
|
"main": "lib/index.js",
|
|
107
|
-
"homepage": "https://
|
|
123
|
+
"homepage": "https://github.com/mito-ds/mito",
|
|
108
124
|
"types": "./lib/index.d.ts",
|
|
109
125
|
"description": "The Mito Spreadsheet",
|
|
110
126
|
"resolutions": {
|