test_task.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. # Copyright 2021-2024 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. from unittest import mock
  12. import pytest
  13. from taipy.config.common.scope import Scope
  14. from taipy.config.config import Config
  15. from taipy.config.exceptions.exceptions import InvalidConfigurationId
  16. from taipy.core.config.data_node_config import DataNodeConfig
  17. from taipy.core.data._data_manager import _DataManager
  18. from taipy.core.data.csv import CSVDataNode
  19. from taipy.core.data.data_node import DataNode
  20. from taipy.core.data.in_memory import InMemoryDataNode
  21. from taipy.core.task._task_manager import _TaskManager
  22. from taipy.core.task.task import Task
  23. @pytest.fixture
  24. def output():
  25. return [DataNode("name_1"), DataNode("name_2"), DataNode("name_3")]
  26. @pytest.fixture
  27. def output_config():
  28. return [DataNodeConfig("name_1"), DataNodeConfig("name_2"), DataNodeConfig("name_3")]
  29. @pytest.fixture
  30. def input():
  31. return [DataNode("input_name_1"), DataNode("input_name_2"), DataNode("input_name_3")]
  32. @pytest.fixture
  33. def input_config():
  34. return [DataNodeConfig("input_name_1"), DataNodeConfig("input_name_2"), DataNodeConfig("input_name_3")]
  35. def test_create_task():
  36. name = "name_1"
  37. task = Task(name, {}, print, [], [])
  38. assert f"TASK_{name}_" in task.id
  39. assert task.config_id == "name_1"
  40. with pytest.raises(InvalidConfigurationId):
  41. Task("foo bar", {}, print, [], [])
  42. path = "my/csv/path"
  43. foo_dn = CSVDataNode("foo", Scope.SCENARIO, properties={"path": path, "has_header": True})
  44. task = Task("name_1", {}, print, [foo_dn], [])
  45. assert task.config_id == "name_1"
  46. assert task.id is not None
  47. assert task.owner_id is None
  48. assert task.parent_ids == set()
  49. assert task.foo == foo_dn
  50. assert task.foo.path == path
  51. with pytest.raises(AttributeError):
  52. _ = task.bar
  53. task = Task("name_1", {}, print, [foo_dn], [], parent_ids={"parent_id"})
  54. assert task.parent_ids == {"parent_id"}
  55. path = "my/csv/path"
  56. abc_dn = InMemoryDataNode("name_1ea", Scope.SCENARIO, properties={"path": path})
  57. task = Task("name_1ea", {}, print, [abc_dn], [], owner_id="owner_id", parent_ids={"parent_id_1", "parent_id_2"})
  58. assert task.config_id == "name_1ea"
  59. assert task.id is not None
  60. assert task.owner_id == "owner_id"
  61. assert task.parent_ids == {"parent_id_1", "parent_id_2"}
  62. assert task.name_1ea == abc_dn
  63. assert task.name_1ea.path == path
  64. with pytest.raises(AttributeError):
  65. _ = task.bar
  66. with mock.patch("taipy.core.get") as get_mck:
  67. class MockOwner:
  68. label = "owner_label"
  69. def get_label(self):
  70. return self.label
  71. get_mck.return_value = MockOwner()
  72. assert task.get_label() == "owner_label > " + task.config_id
  73. assert task.get_simple_label() == task.config_id
  74. def test_can_not_change_task_output(output):
  75. task = Task("name_1", {}, print, output=output)
  76. with pytest.raises(AttributeError):
  77. task.output = {}
  78. assert list(task.output.values()) == output
  79. output.append(output[0])
  80. assert list(task.output.values()) != output
  81. def test_can_not_change_task_input(input):
  82. task = Task("name_1", {}, print, input=input)
  83. with pytest.raises(AttributeError):
  84. task.input = {}
  85. assert list(task.input.values()) == input
  86. input.append(input[0])
  87. assert list(task.input.values()) != input
  88. def test_can_not_change_task_config_output(output_config):
  89. task_config = Config.configure_task("name_1", print, [], output=output_config)
  90. assert task_config.output_configs == output_config
  91. with pytest.raises(AttributeError):
  92. task_config.output_configs = []
  93. output_config.append(output_config[0])
  94. assert task_config._output != output_config
  95. def test_can_not_update_task_output_values(output_config):
  96. data_node_cfg = Config.configure_data_node("data_node_cfg")
  97. task_config = Config.configure_task("name_1", print, [], output=output_config)
  98. task_config.output_configs.append(data_node_cfg)
  99. assert task_config.output_configs == output_config
  100. task_config.output_configs[0] = data_node_cfg
  101. assert task_config.output_configs[0] != data_node_cfg
  102. def test_can_not_update_task_input_values(input_config):
  103. data_node_config = DataNodeConfig("data_node")
  104. task_config = Config.configure_task("name_1", print, input=input_config, output=[])
  105. task_config.input_configs.append(data_node_config)
  106. assert task_config.input_configs == input_config
  107. task_config.input_configs[0] = data_node_config
  108. assert task_config.input_configs[0] != data_node_config
  109. def mock_func():
  110. pass
  111. def test_auto_set_and_reload(data_node):
  112. task_1 = Task(
  113. config_id="foo", properties={}, function=print, input=None, output=None, owner_id=None, skippable=False
  114. )
  115. _DataManager._set(data_node)
  116. _TaskManager._set(task_1)
  117. task_2 = _TaskManager._get(task_1)
  118. # auto set & reload on function attribute
  119. assert task_1.function == print
  120. assert task_2.function == print
  121. task_1.function = sum
  122. assert task_1.function == sum
  123. assert task_2.function == sum
  124. task_2.function = mock_func
  125. assert task_1.function == mock_func
  126. assert task_2.function == mock_func
  127. # auto set & reload on skippable attribute
  128. assert not task_1.skippable
  129. assert not task_2.skippable
  130. task_1.skippable = True
  131. assert task_1.skippable
  132. assert task_2.skippable
  133. task_2.skippable = False
  134. assert not task_1.skippable
  135. assert not task_2.skippable
  136. # auto set & reload on parent_ids attribute (set() object does not have auto set yet)
  137. assert task_1.parent_ids == set()
  138. assert task_2.parent_ids == set()
  139. task_1._parent_ids.update(["sc2"])
  140. _TaskManager._set(task_1)
  141. assert task_1.parent_ids == {"sc2"}
  142. assert task_2.parent_ids == {"sc2"}
  143. task_2._parent_ids.clear()
  144. task_2._parent_ids.update(["sc1"])
  145. _TaskManager._set(task_2)
  146. assert task_1.parent_ids == {"sc1"}
  147. assert task_2.parent_ids == {"sc1"}
  148. with task_1 as task:
  149. assert task.config_id == "foo"
  150. assert task.owner_id is None
  151. assert task.function == mock_func
  152. assert not task.skippable
  153. assert task._is_in_context
  154. task.function = print
  155. task.skippable = True
  156. assert task.config_id == "foo"
  157. assert task.owner_id is None
  158. assert task.function == mock_func
  159. assert not task.skippable
  160. assert task._is_in_context
  161. assert task_1.config_id == "foo"
  162. assert task_1.owner_id is None
  163. assert task_1.function == print
  164. assert task.skippable
  165. assert not task_1._is_in_context
  166. def test_auto_set_and_reload_properties():
  167. task_1 = Task(
  168. config_id="foo", properties={}, function=print, input=None, output=None, owner_id=None, skippable=False
  169. )
  170. _TaskManager._set(task_1)
  171. task_2 = _TaskManager._get(task_1)
  172. # auto set & reload on properties attribute
  173. assert task_1.properties == {}
  174. assert task_2.properties == {}
  175. task_1._properties["qux"] = 4
  176. assert task_1.properties["qux"] == 4
  177. assert task_2.properties["qux"] == 4
  178. assert task_1.properties == {"qux": 4}
  179. assert task_2.properties == {"qux": 4}
  180. task_2._properties["qux"] = 5
  181. assert task_1.properties["qux"] == 5
  182. assert task_2.properties["qux"] == 5
  183. task_1.properties["temp_key_1"] = "temp_value_1"
  184. task_1.properties["temp_key_2"] = "temp_value_2"
  185. assert task_1.properties == {
  186. "qux": 5,
  187. "temp_key_1": "temp_value_1",
  188. "temp_key_2": "temp_value_2",
  189. }
  190. assert task_2.properties == {
  191. "qux": 5,
  192. "temp_key_1": "temp_value_1",
  193. "temp_key_2": "temp_value_2",
  194. }
  195. task_1.properties.pop("temp_key_1")
  196. assert "temp_key_1" not in task_1.properties.keys()
  197. assert "temp_key_1" not in task_1.properties.keys()
  198. assert task_1.properties == {
  199. "qux": 5,
  200. "temp_key_2": "temp_value_2",
  201. }
  202. assert task_2.properties == {
  203. "qux": 5,
  204. "temp_key_2": "temp_value_2",
  205. }
  206. task_2.properties.pop("temp_key_2")
  207. assert task_1.properties == {"qux": 5}
  208. assert task_2.properties == {"qux": 5}
  209. assert "temp_key_2" not in task_1.properties.keys()
  210. assert "temp_key_2" not in task_2.properties.keys()
  211. task_1.properties["temp_key_3"] = 0
  212. assert task_1.properties == {"qux": 5, "temp_key_3": 0}
  213. assert task_2.properties == {"qux": 5, "temp_key_3": 0}
  214. task_1.properties.update({"temp_key_3": 1})
  215. assert task_1.properties == {"qux": 5, "temp_key_3": 1}
  216. assert task_2.properties == {"qux": 5, "temp_key_3": 1}
  217. task_1.properties.update(dict())
  218. assert task_1.properties == {"qux": 5, "temp_key_3": 1}
  219. assert task_2.properties == {"qux": 5, "temp_key_3": 1}
  220. task_1.properties["temp_key_4"] = 0
  221. task_1.properties["temp_key_5"] = 0
  222. with task_1 as task:
  223. assert task._is_in_context
  224. assert task.properties["qux"] == 5
  225. assert task.properties["temp_key_3"] == 1
  226. assert task.properties["temp_key_4"] == 0
  227. assert task.properties["temp_key_5"] == 0
  228. task.properties["qux"] = 9
  229. task.properties.pop("temp_key_3")
  230. task.properties.pop("temp_key_4")
  231. task.properties.update({"temp_key_4": 1})
  232. task.properties.update({"temp_key_5": 2})
  233. task.properties.pop("temp_key_5")
  234. task.properties.update(dict())
  235. assert task._is_in_context
  236. assert task.properties["qux"] == 5
  237. assert task.properties["temp_key_3"] == 1
  238. assert task.properties["temp_key_4"] == 0
  239. assert task.properties["temp_key_5"] == 0
  240. assert not task_1._is_in_context
  241. assert task_1.properties["qux"] == 9
  242. assert "temp_key_3" not in task_1.properties.keys()
  243. assert task_1.properties["temp_key_4"] == 1
  244. assert "temp_key_5" not in task_1.properties.keys()
  245. def test_get_parents(task):
  246. with mock.patch("taipy.core.get_parents") as mck:
  247. task.get_parents()
  248. mck.assert_called_once_with(task)
  249. def test_submit_task(task: Task):
  250. with mock.patch("taipy.core.task._task_manager._TaskManager._submit") as mock_submit:
  251. task.submit([], True)
  252. mock_submit.assert_called_once_with(task, [], True, False, None)