test_pandas_data_accessor.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. # Copyright 2023 Avaiga Private Limited
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. # the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. # specific language governing permissions and limitations under the License.
  11. import inspect
  12. from datetime import datetime
  13. from importlib import util
  14. import pandas # type: ignore
  15. from flask import g
  16. from taipy.gui import Gui
  17. from taipy.gui.data.data_format import _DataFormat
  18. from taipy.gui.data.decimator import ScatterDecimator
  19. from taipy.gui.data.pandas_data_accessor import _PandasDataAccessor
  20. def test_simple_data(gui: Gui, helpers, small_dataframe):
  21. accessor = _PandasDataAccessor()
  22. pd = pandas.DataFrame(data=small_dataframe)
  23. ret_data = accessor.get_data(gui, "x", pd, {"start": 0, "end": -1}, _DataFormat.JSON)
  24. assert ret_data
  25. value = ret_data["value"]
  26. assert value
  27. assert value["rowcount"] == 3
  28. data = value["data"]
  29. assert len(data) == 3
  30. def test_simple_data_with_arrow(gui: Gui, helpers, small_dataframe):
  31. if util.find_spec("pyarrow"):
  32. accessor = _PandasDataAccessor()
  33. pd = pandas.DataFrame(data=small_dataframe)
  34. ret_data = accessor.get_data(gui, "x", pd, {"start": 0, "end": -1}, _DataFormat.APACHE_ARROW)
  35. assert ret_data
  36. value = ret_data["value"]
  37. assert value
  38. assert value["rowcount"] == 3
  39. data = value["data"]
  40. assert isinstance(data, bytes)
  41. def test_get_all_simple_data(gui: Gui, helpers, small_dataframe):
  42. accessor = _PandasDataAccessor()
  43. pd = pandas.DataFrame(data=small_dataframe)
  44. ret_data = accessor.get_data(gui, "x", pd, {"alldata": True}, _DataFormat.JSON)
  45. assert ret_data
  46. assert ret_data["alldata"] is True
  47. value = ret_data["value"]
  48. assert value
  49. data = value["data"]
  50. assert data == small_dataframe
  51. def test_slice(gui: Gui, helpers, small_dataframe):
  52. accessor = _PandasDataAccessor()
  53. pd = pandas.DataFrame(data=small_dataframe)
  54. value = accessor.get_data(gui, "x", pd, {"start": 0, "end": 1}, _DataFormat.JSON)["value"]
  55. assert value["rowcount"] == 3
  56. data = value["data"]
  57. assert len(data) == 2
  58. value = accessor.get_data(gui, "x", pd, {"start": "0", "end": "1"}, _DataFormat.JSON)["value"]
  59. data = value["data"]
  60. assert len(data) == 2
  61. def test_sort(gui: Gui, helpers, small_dataframe):
  62. accessor = _PandasDataAccessor()
  63. pd = pandas.DataFrame(data=small_dataframe)
  64. query = {"columns": ["name", "value"], "start": 0, "end": -1, "orderby": "name", "sort": "desc"}
  65. data = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)["value"]["data"]
  66. assert data[0]["name"] == "C"
  67. def test_aggregate(gui: Gui, helpers, small_dataframe):
  68. accessor = _PandasDataAccessor()
  69. pd = pandas.DataFrame(data=small_dataframe)
  70. pd = pandas.concat(
  71. [pd, pandas.DataFrame(data={"name": ["A"], "value": [4]})], axis=0, join="outer", ignore_index=True
  72. )
  73. query = {"columns": ["name", "value"], "start": 0, "end": -1, "aggregates": ["name"], "applies": {"value": "sum"}}
  74. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)["value"]
  75. assert value["rowcount"] == 3
  76. data = value["data"]
  77. assert next(v.get("value") for v in data if v.get("name") == "A") == 5
  78. def test_filters(gui: Gui, helpers, small_dataframe):
  79. accessor = _PandasDataAccessor()
  80. pd = pandas.DataFrame(data=small_dataframe)
  81. pd = pandas.concat(
  82. [pd, pandas.DataFrame(data={"name": ["A"], "value": [4]})], axis=0, join="outer", ignore_index=True
  83. )
  84. query = {
  85. "columns": ["name", "value"],
  86. "start": 0,
  87. "end": -1,
  88. "filters": [{"col": "name", "action": "!=", "value": ""}],
  89. }
  90. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  91. assert len(value["value"]["data"]) == 4
  92. query = {
  93. "columns": ["name", "value"],
  94. "start": 0,
  95. "end": -1,
  96. "filters": [{"col": "name", "action": "==", "value": ""}],
  97. }
  98. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  99. assert len(value["value"]["data"]) == 0
  100. query = {
  101. "columns": ["name", "value"],
  102. "start": 0,
  103. "end": -1,
  104. "filters": [{"col": "name", "action": "==", "value": "A"}],
  105. }
  106. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  107. assert len(value["value"]["data"]) == 2
  108. query = {
  109. "columns": ["name", "value"],
  110. "start": 0,
  111. "end": -1,
  112. "filters": [{"col": "name", "action": "==", "value": "A"}, {"col": "value", "action": "==", "value": 2}],
  113. }
  114. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  115. assert len(value["value"]["data"]) == 0
  116. query = {
  117. "columns": ["name", "value"],
  118. "start": 0,
  119. "end": -1,
  120. "filters": [{"col": "name", "action": "!=", "value": "A"}, {"col": "value", "action": "==", "value": 2}],
  121. }
  122. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  123. assert len(value["value"]["data"]) == 1
  124. assert value["value"]["data"][0]["_tp_index"] == 1
  125. def test_filter_by_date(gui: Gui, helpers, small_dataframe):
  126. accessor = _PandasDataAccessor()
  127. pd = pandas.DataFrame(data=small_dataframe)
  128. pd["a date"] = [
  129. datetime.fromisocalendar(2022, 28, 1),
  130. datetime.fromisocalendar(2022, 28, 2),
  131. datetime.fromisocalendar(2022, 28, 3),
  132. ]
  133. query = {
  134. "columns": ["name", "value"],
  135. "start": 0,
  136. "end": -1,
  137. "filters": [{"col": "a date", "action": ">", "value": datetime.fromisocalendar(2022, 28, 3).isoformat() + "Z"}],
  138. }
  139. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  140. assert len(value["value"]["data"]) == 0
  141. query = {
  142. "columns": ["name", "value"],
  143. "start": 0,
  144. "end": -1,
  145. "filters": [{"col": "a date", "action": ">", "value": datetime.fromisocalendar(2022, 28, 2).isoformat() + "Z"}],
  146. }
  147. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  148. assert len(value["value"]["data"]) == 1
  149. query = {
  150. "columns": ["name", "value"],
  151. "start": 0,
  152. "end": -1,
  153. "filters": [{"col": "a date", "action": "<", "value": datetime.fromisocalendar(2022, 28, 3).isoformat() + "Z"}],
  154. }
  155. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  156. assert len(value["value"]["data"]) == 2
  157. query = {
  158. "columns": ["name", "value"],
  159. "start": 0,
  160. "end": -1,
  161. "filters": [
  162. {"col": "a date", "action": "<", "value": datetime.fromisocalendar(2022, 28, 2).isoformat() + "Z"},
  163. {"col": "a date", "action": ">", "value": datetime.fromisocalendar(2022, 28, 2).isoformat() + "Z"},
  164. ],
  165. }
  166. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  167. assert len(value["value"]["data"]) == 0
  168. query = {
  169. "columns": ["name", "value"],
  170. "start": 0,
  171. "end": -1,
  172. "filters": [
  173. {"col": "a date", "action": "<", "value": datetime.fromisocalendar(2022, 28, 3).isoformat() + "Z"},
  174. {"col": "a date", "action": ">", "value": datetime.fromisocalendar(2022, 28, 1).isoformat() + "Z"},
  175. ],
  176. }
  177. value = accessor.get_data(gui, "x", pd, query, _DataFormat.JSON)
  178. assert len(value["value"]["data"]) == 1
  179. def test_decimator(gui: Gui, helpers, small_dataframe):
  180. a_decimator = ScatterDecimator()
  181. accessor = _PandasDataAccessor()
  182. pd = pandas.DataFrame(data=small_dataframe)
  183. # set gui frame
  184. gui._set_frame(inspect.currentframe())
  185. gui.add_page("test", "<|Hello {a_decimator}|button|id={btn_id}|>")
  186. gui.run(run_server=False)
  187. flask_client = gui._server.test_client()
  188. cid = helpers.create_scope_and_get_sid(gui)
  189. # Get the jsx once so that the page will be evaluated -> variable will be registered
  190. flask_client.get(f"/taipy-jsx/test?client_id={cid}")
  191. with gui.get_flask_app().test_request_context(f"/taipy-jsx/test/?client_id={cid}", data={"client_id": cid}):
  192. g.client_id = cid
  193. ret_data = accessor.get_data(
  194. gui,
  195. "x",
  196. pd,
  197. {
  198. "start": 0,
  199. "end": -1,
  200. "alldata": True,
  201. "decimatorPayload": {
  202. "decimators": [{"decimator": "a_decimator", "chartMode": "markers"}],
  203. "width": 100,
  204. },
  205. },
  206. _DataFormat.JSON,
  207. )
  208. assert ret_data
  209. value = ret_data["value"]
  210. assert value
  211. data = value["data"]
  212. assert len(data) == 2