test_taipy.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  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. import datetime
  12. from unittest import mock
  13. import pytest
  14. import taipy.core.taipy as tp
  15. from taipy.common.config import Config
  16. from taipy.common.config.common.frequency import Frequency
  17. from taipy.common.config.common.scope import Scope
  18. from taipy.common.config.exceptions.exceptions import ConfigurationUpdateBlocked
  19. from taipy.core import (
  20. Cycle,
  21. CycleId,
  22. DataNodeId,
  23. JobId,
  24. Orchestrator,
  25. Scenario,
  26. ScenarioId,
  27. Sequence,
  28. SequenceId,
  29. Submission,
  30. SubmissionId,
  31. Task,
  32. TaskId,
  33. )
  34. from taipy.core._orchestrator._orchestrator_factory import _OrchestratorFactory
  35. from taipy.core._version._version_manager import _VersionManager
  36. from taipy.core.config.data_node_config import DataNodeConfig
  37. from taipy.core.config.scenario_config import ScenarioConfig
  38. from taipy.core.cycle._cycle_manager import _CycleManager
  39. from taipy.core.data._data_manager import _DataManager
  40. from taipy.core.data.pickle import PickleDataNode
  41. from taipy.core.exceptions.exceptions import DataNodeConfigIsNotGlobal
  42. from taipy.core.job._job_manager import _JobManager
  43. from taipy.core.job.job import Job
  44. from taipy.core.scenario._scenario_manager import _ScenarioManager
  45. from taipy.core.submission._submission_manager import _SubmissionManager
  46. from taipy.core.task._task_manager import _TaskManager
  47. def cb(s, j):
  48. print() # noqa: T201
  49. class TestTaipy:
  50. def test_set(self, scenario, cycle, sequence, data_node, task, submission):
  51. with mock.patch("taipy.core.data._data_manager._DataManager._set") as mck:
  52. tp.set(data_node)
  53. mck.assert_called_once_with(data_node)
  54. with mock.patch("taipy.core.task._task_manager._TaskManager._set") as mck:
  55. tp.set(task)
  56. mck.assert_called_once_with(task)
  57. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._set") as mck:
  58. tp.set(sequence)
  59. mck.assert_called_once_with(sequence)
  60. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._set") as mck:
  61. tp.set(scenario)
  62. mck.assert_called_once_with(scenario)
  63. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._set") as mck:
  64. tp.set(cycle)
  65. mck.assert_called_once_with(cycle)
  66. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._set") as mck:
  67. tp.set(submission)
  68. mck.assert_called_once_with(submission)
  69. def test_is_editable_is_called(self, cycle, job, data_node):
  70. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._is_editable") as mck:
  71. cycle_id = CycleId("CYCLE_id")
  72. tp.is_editable(cycle_id)
  73. mck.assert_called_once_with(cycle_id)
  74. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._is_editable") as mck:
  75. tp.is_editable(cycle)
  76. mck.assert_called_once_with(cycle)
  77. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_editable") as mck:
  78. scenario_id = ScenarioId("SCENARIO_id")
  79. tp.is_editable(scenario_id)
  80. mck.assert_called_once_with(scenario_id)
  81. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_editable") as mck:
  82. scenario = Scenario("scenario_config_id", set(), {})
  83. tp.is_editable(scenario)
  84. mck.assert_called_once_with(scenario)
  85. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_editable") as mck:
  86. sequence_id = SequenceId("SEQUENCE_id")
  87. tp.is_editable(sequence_id)
  88. mck.assert_called_once_with(sequence_id)
  89. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_editable") as mck:
  90. sequence = Sequence({}, [], SequenceId("sequence_id"))
  91. tp.is_editable(sequence)
  92. mck.assert_called_once_with(sequence)
  93. with mock.patch("taipy.core.task._task_manager._TaskManager._is_editable") as mck:
  94. task_id = TaskId("TASK_id")
  95. tp.is_editable(task_id)
  96. mck.assert_called_once_with(task_id)
  97. with mock.patch("taipy.core.task._task_manager._TaskManager._is_editable") as mck:
  98. task = Task("task_config_id", {}, print)
  99. tp.is_editable(task)
  100. mck.assert_called_once_with(task)
  101. with mock.patch("taipy.core.job._job_manager._JobManager._is_editable") as mck:
  102. job_id = JobId("JOB_id")
  103. tp.is_editable(job_id)
  104. mck.assert_called_once_with(job_id)
  105. with mock.patch("taipy.core.job._job_manager._JobManager._is_editable") as mck:
  106. tp.is_editable(job)
  107. mck.assert_called_once_with(job)
  108. with mock.patch("taipy.core.data._data_manager._DataManager._is_editable") as mck:
  109. dn_id = DataNodeId("DATANODE_id")
  110. tp.is_editable(dn_id)
  111. mck.assert_called_once_with(dn_id)
  112. with mock.patch("taipy.core.data._data_manager._DataManager._is_editable") as mck:
  113. tp.is_editable(data_node)
  114. mck.assert_called_once_with(data_node)
  115. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_editable") as mck:
  116. submission = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id, "submission_id")
  117. tp.is_editable(submission)
  118. mck.assert_called_once_with(submission)
  119. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_editable") as mck:
  120. submission_id = SubmissionId("SUBMISSION_id")
  121. tp.is_editable(submission_id)
  122. mck.assert_called_once_with(submission_id)
  123. def test_is_editable(self):
  124. a_date = datetime.datetime.now()
  125. cycle = Cycle(Frequency.DAILY, {}, a_date, a_date, a_date)
  126. scenario = Scenario("scenario_config_id", set(), {}, sequences={"sequence": {}})
  127. task = Task("task_config_id", {}, print)
  128. job = Job(JobId("job_id"), task, "submit_id", scenario.id)
  129. dn = PickleDataNode(config_id="data_node_config_id", scope=Scope.SCENARIO)
  130. submission = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id, "submission_id")
  131. _CycleManager._set(cycle)
  132. _ScenarioManager._set(scenario)
  133. _TaskManager._set(task)
  134. _JobManager._set(job)
  135. _DataManager._set(dn)
  136. _SubmissionManager._set(submission)
  137. sequence = scenario.sequences["sequence"]
  138. assert tp.is_editable(scenario)
  139. assert tp.is_editable(sequence)
  140. assert tp.is_editable(task)
  141. assert tp.is_editable(cycle)
  142. assert tp.is_editable(job)
  143. assert tp.is_editable(submission)
  144. assert tp.is_editable(dn)
  145. def test_is_readable_is_called(self, cycle, job, data_node):
  146. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._is_readable") as mck:
  147. cycle_id = CycleId("CYCLE_id")
  148. tp.is_readable(cycle_id)
  149. mck.assert_called_once_with(cycle_id)
  150. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._is_readable") as mck:
  151. tp.is_readable(cycle)
  152. mck.assert_called_once_with(cycle)
  153. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_readable") as mck:
  154. scenario_id = ScenarioId("SCENARIO_id")
  155. tp.is_readable(scenario_id)
  156. mck.assert_called_once_with(scenario_id)
  157. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_readable") as mck:
  158. scenario = Scenario("scenario_config_id", set(), {})
  159. tp.is_readable(scenario)
  160. mck.assert_called_once_with(scenario)
  161. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_readable") as mck:
  162. sequence_id = SequenceId("SEQUENCE_id")
  163. tp.is_readable(sequence_id)
  164. mck.assert_called_once_with(sequence_id)
  165. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_readable") as mck:
  166. sequence = Sequence({}, [], SequenceId("sequence_id"))
  167. tp.is_readable(sequence)
  168. mck.assert_called_once_with(sequence)
  169. with mock.patch("taipy.core.task._task_manager._TaskManager._is_readable") as mck:
  170. task_id = TaskId("TASK_id")
  171. tp.is_readable(task_id)
  172. mck.assert_called_once_with(task_id)
  173. with mock.patch("taipy.core.task._task_manager._TaskManager._is_readable") as mck:
  174. task = Task("task_config_id", {}, print)
  175. tp.is_readable(task)
  176. mck.assert_called_once_with(task)
  177. with mock.patch("taipy.core.job._job_manager._JobManager._is_readable") as mck:
  178. job_id = JobId("JOB_id")
  179. tp.is_readable(job_id)
  180. mck.assert_called_once_with(job_id)
  181. with mock.patch("taipy.core.job._job_manager._JobManager._is_readable") as mck:
  182. tp.is_readable(job)
  183. mck.assert_called_once_with(job)
  184. with mock.patch("taipy.core.data._data_manager._DataManager._is_readable") as mck:
  185. dn_id = DataNodeId("DATANODE_id")
  186. tp.is_readable(dn_id)
  187. mck.assert_called_once_with(dn_id)
  188. with mock.patch("taipy.core.data._data_manager._DataManager._is_readable") as mck:
  189. tp.is_readable(data_node)
  190. mck.assert_called_once_with(data_node)
  191. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_readable") as mck:
  192. submission = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id, "submission_id")
  193. tp.is_readable(submission)
  194. mck.assert_called_once_with(submission)
  195. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_readable") as mck:
  196. submission_id = SubmissionId("SUBMISSION_id")
  197. tp.is_readable(submission_id)
  198. mck.assert_called_once_with(submission_id)
  199. def test_is_readable(self):
  200. a_date = datetime.datetime.now()
  201. cycle = Cycle(Frequency.DAILY, {}, a_date, a_date, a_date)
  202. scenario = Scenario("scenario_config_id", set(), {}, sequences={"sequence": {}})
  203. task = Task("task_config_id", {}, print)
  204. job = Job(JobId("a_job_id"), task, "submit_id", scenario.id)
  205. dn = PickleDataNode(config_id="a_data_node_config_id", scope=Scope.SCENARIO)
  206. submission = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id, "submission_id")
  207. _CycleManager._set(cycle)
  208. _ScenarioManager._set(scenario)
  209. _TaskManager._set(task)
  210. _JobManager._set(job)
  211. _DataManager._set(dn)
  212. _SubmissionManager._set(submission)
  213. sequence = scenario.sequences["sequence"]
  214. assert tp.is_readable(scenario)
  215. assert tp.is_readable(sequence)
  216. assert tp.is_readable(task)
  217. assert tp.is_readable(cycle)
  218. assert tp.is_readable(job)
  219. assert tp.is_readable(dn)
  220. assert tp.is_readable(submission)
  221. def test_is_submittable_is_called(self):
  222. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_submittable") as mck:
  223. scenario_id = ScenarioId("SCENARIO_id")
  224. tp.is_submittable(scenario_id)
  225. mck.assert_called_once_with(scenario_id)
  226. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_submittable") as mck:
  227. scenario = Scenario("scenario_config_id", set(), {})
  228. tp.is_submittable(scenario)
  229. mck.assert_called_once_with(scenario)
  230. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_submittable") as mck:
  231. sequence_id = SequenceId("SEQUENCE_id")
  232. tp.is_submittable(sequence_id)
  233. mck.assert_called_once_with(sequence_id)
  234. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._is_submittable") as mck:
  235. sequence = Sequence({}, [], SequenceId("sequence_id"))
  236. tp.is_submittable(sequence)
  237. mck.assert_called_once_with(sequence)
  238. with mock.patch("taipy.core.task._task_manager._TaskManager._is_submittable") as mck:
  239. task_id = TaskId("TASK_id")
  240. tp.is_submittable(task_id)
  241. mck.assert_called_once_with(task_id)
  242. with mock.patch("taipy.core.task._task_manager._TaskManager._is_submittable") as mck:
  243. task = Task("task_config_id", {}, print)
  244. tp.is_submittable(task)
  245. mck.assert_called_once_with(task)
  246. def test_is_submittable(self):
  247. current_date = datetime.datetime.now()
  248. cycle = Cycle(Frequency.DAILY, {}, current_date, current_date, current_date)
  249. scenario = Scenario("scenario_config_id", set(), {}, sequences={"sequence": {}})
  250. task = Task("task_config_id", {}, print)
  251. job = Job(JobId("job_id"), task, "submit_id", ScenarioId(scenario.id))
  252. dn = PickleDataNode("data_node_config_id", Scope.SCENARIO)
  253. _CycleManager._set(cycle)
  254. _ScenarioManager._set(scenario)
  255. _TaskManager._set(task)
  256. _JobManager._set(job)
  257. _DataManager._set(dn)
  258. sequence = scenario.sequences["sequence"]
  259. assert tp.is_submittable(scenario)
  260. assert tp.is_submittable(sequence)
  261. assert tp.is_submittable(task)
  262. assert not tp.is_submittable(cycle)
  263. assert not tp.is_submittable(job)
  264. assert not tp.is_submittable(dn)
  265. def test_submit(self, scenario, sequence, task):
  266. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._submit") as mck:
  267. tp.submit(scenario)
  268. mck.assert_called_once_with(scenario, force=False, wait=False, timeout=None)
  269. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._submit") as mck:
  270. tp.submit(sequence)
  271. mck.assert_called_once_with(sequence, force=False, wait=False, timeout=None)
  272. with mock.patch("taipy.core.task._task_manager._TaskManager._submit") as mck:
  273. tp.submit(task)
  274. mck.assert_called_once_with(task, force=False, wait=False, timeout=None)
  275. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._submit") as mck:
  276. tp.submit(scenario, False, False, None)
  277. mck.assert_called_once_with(scenario, force=False, wait=False, timeout=None)
  278. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._submit") as mck:
  279. tp.submit(sequence, False, False, None)
  280. mck.assert_called_once_with(sequence, force=False, wait=False, timeout=None)
  281. with mock.patch("taipy.core.task._task_manager._TaskManager._submit") as mck:
  282. tp.submit(task, False, False, None)
  283. mck.assert_called_once_with(task, force=False, wait=False, timeout=None)
  284. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._submit") as mck:
  285. tp.submit(scenario, True, True, 60)
  286. mck.assert_called_once_with(scenario, force=True, wait=True, timeout=60)
  287. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._submit") as mck:
  288. tp.submit(sequence, True, True, 60)
  289. mck.assert_called_once_with(sequence, force=True, wait=True, timeout=60)
  290. with mock.patch("taipy.core.task._task_manager._TaskManager._submit") as mck:
  291. tp.submit(task, True, True, 60)
  292. mck.assert_called_once_with(task, force=True, wait=True, timeout=60)
  293. def test_warning_no_core_service_running(self, scenario):
  294. _OrchestratorFactory._remove_dispatcher()
  295. with pytest.warns(ResourceWarning) as warning:
  296. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._submit"):
  297. tp.submit(scenario)
  298. assert len(warning) == 1
  299. assert "The Orchestrator service is NOT running" in warning[0].message.args[0]
  300. def test_get_tasks(self):
  301. with mock.patch("taipy.core.task._task_manager._TaskManager._get_all") as mck:
  302. tp.get_tasks()
  303. mck.assert_called_once_with()
  304. def test_get_task(self, task):
  305. with mock.patch("taipy.core.task._task_manager._TaskManager._get") as mck:
  306. task_id = TaskId("TASK_id")
  307. tp.get(task_id)
  308. mck.assert_called_once_with(task_id)
  309. def test_task_exists(self):
  310. with mock.patch("taipy.core.task._task_manager._TaskManager._exists") as mck:
  311. task_id = TaskId("TASK_id")
  312. tp.exists(task_id)
  313. mck.assert_called_once_with(task_id)
  314. def test_is_deletable(self, task):
  315. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_deletable") as mck:
  316. scenario_id = ScenarioId("SCENARIO_id")
  317. tp.is_deletable(scenario_id)
  318. mck.assert_called_once_with(scenario_id)
  319. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_deletable") as mck:
  320. scenario = Scenario("config_id", set(), {})
  321. tp.is_deletable(scenario)
  322. mck.assert_called_once_with(scenario)
  323. with mock.patch("taipy.core.job._job_manager._JobManager._is_deletable") as mck:
  324. job_id = JobId("JOB_job_id")
  325. tp.is_deletable(job_id)
  326. mck.assert_called_once_with(job_id)
  327. with mock.patch("taipy.core.job._job_manager._JobManager._is_deletable") as mck:
  328. job = Job(JobId("job_id"), task, "submit_id", task.id)
  329. tp.is_deletable(job)
  330. mck.assert_called_once_with(job)
  331. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_deletable") as mck:
  332. submission = Submission(scenario.id, scenario._ID_PREFIX, scenario.config_id, "submission_id")
  333. tp.is_deletable(submission)
  334. mck.assert_called_once_with(submission)
  335. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._is_deletable") as mck:
  336. submission_id = SubmissionId("SUBMISSION_id")
  337. tp.is_deletable(submission_id)
  338. mck.assert_called_once_with(submission_id)
  339. def test_is_promotable(self):
  340. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_promotable_to_primary") as mck:
  341. scenario_id = ScenarioId("SCENARIO_id")
  342. tp.is_promotable(scenario_id)
  343. mck.assert_called_once_with(scenario_id)
  344. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._is_promotable_to_primary") as mck:
  345. scenario = Scenario("config_id", set(), {})
  346. tp.is_promotable(scenario)
  347. mck.assert_called_once_with(scenario)
  348. def test_delete_scenario(self):
  349. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._hard_delete") as mck:
  350. scenario_id = ScenarioId("SCENARIO_id")
  351. tp.delete(scenario_id)
  352. mck.assert_called_once_with(scenario_id)
  353. def test_delete(self):
  354. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._hard_delete") as mck:
  355. cycle_id = CycleId("CYCLE_id")
  356. tp.delete(cycle_id)
  357. mck.assert_called_once_with(cycle_id)
  358. def test_get_scenarios(self, cycle):
  359. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get_all") as mck:
  360. tp.get_scenarios()
  361. mck.assert_called_once_with()
  362. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get_all_by_cycle") as mck:
  363. tp.get_scenarios(cycle)
  364. mck.assert_called_once_with(cycle)
  365. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get_all_by_tag") as mck:
  366. tp.get_scenarios(tag="tag")
  367. mck.assert_called_once_with("tag")
  368. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._filter_by_creation_time") as mck:
  369. tp.get_scenarios(created_start_time=datetime.datetime(2021, 1, 1))
  370. mck.assert_called_once_with([], datetime.datetime(2021, 1, 1), None)
  371. def test_get_scenarios_sorted(self):
  372. scenario_1_cfg = Config.configure_scenario(id="scenario_1")
  373. scenario_2_cfg = Config.configure_scenario(id="scenario_2")
  374. now = datetime.datetime.now() + datetime.timedelta(seconds=1)
  375. scenario_1 = _ScenarioManager._create(scenario_1_cfg, now, "B_scenario")
  376. scenario_2 = _ScenarioManager._create(scenario_2_cfg, now + datetime.timedelta(seconds=1), "C_scenario")
  377. scenario_3 = _ScenarioManager._create(scenario_2_cfg, now + datetime.timedelta(seconds=2), "A_scenario")
  378. scenario_4 = _ScenarioManager._create(scenario_2_cfg, now + datetime.timedelta(seconds=3), "D_scenario")
  379. _ScenarioManager._tag(scenario_1, "banana")
  380. _ScenarioManager._tag(scenario_1, "kiwi") # scenario_1 now has tags {"banana", "kiwi"}
  381. _ScenarioManager._tag(scenario_2, "apple")
  382. _ScenarioManager._tag(scenario_2, "banana") # scenario_2 now has tags {"banana", "apple"}
  383. _ScenarioManager._tag(scenario_3, "apple")
  384. _ScenarioManager._tag(scenario_3, "kiwi") # scenario_3 now has tags {"kiwi", "apple"}
  385. scenarios_sorted_by_name = [scenario_3, scenario_1, scenario_2, scenario_4]
  386. assert scenarios_sorted_by_name == tp.get_scenarios(is_sorted=True, sort_key="name")
  387. assert scenarios_sorted_by_name == tp.get_scenarios(is_sorted=True, sort_key="wrong_sort_key")
  388. scenarios_with_same_config_id = [scenario_2, scenario_3, scenario_4]
  389. scenarios_with_same_config_id.sort(key=lambda x: x.id)
  390. scenarios_sorted_by_config_id = [
  391. scenario_1,
  392. scenarios_with_same_config_id[0],
  393. scenarios_with_same_config_id[1],
  394. scenarios_with_same_config_id[2],
  395. ]
  396. assert scenarios_sorted_by_config_id == tp.get_scenarios(is_sorted=True, sort_key="config_id")
  397. scenarios_sorted_by_id = [scenario_1, scenario_2, scenario_3, scenario_4]
  398. scenarios_sorted_by_id.sort(key=lambda x: x.id)
  399. assert scenarios_sorted_by_id == tp.get_scenarios(is_sorted=True, sort_key="id")
  400. scenarios_sorted_by_creation_date = [scenario_1, scenario_2, scenario_3, scenario_4]
  401. assert scenarios_sorted_by_creation_date == tp.get_scenarios(is_sorted=True, sort_key="creation_date")
  402. # Note: the scenario without any tags comes first.
  403. scenarios_sorted_by_tag = [scenario_4, scenario_2, scenario_3, scenario_1]
  404. assert scenarios_sorted_by_tag == tp.get_scenarios(is_sorted=True, sort_key="tags")
  405. scenarios_sorted_by_name_descending_order = [scenario_4, scenario_2, scenario_1, scenario_3]
  406. assert scenarios_sorted_by_name_descending_order == tp.get_scenarios(
  407. is_sorted=True, descending=True, sort_key="name"
  408. )
  409. def test_get_scenario(self, scenario):
  410. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get") as mck:
  411. scenario_id = ScenarioId("SCENARIO_id")
  412. tp.get(scenario_id)
  413. mck.assert_called_once_with(scenario_id)
  414. def test_scenario_exists(self):
  415. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._exists") as mck:
  416. scenario_id = ScenarioId("SCENARIO_id")
  417. tp.exists(scenario_id)
  418. mck.assert_called_once_with(scenario_id)
  419. def test_get_primary(self, cycle):
  420. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get_primary") as mck:
  421. tp.get_primary(cycle)
  422. mck.assert_called_once_with(cycle)
  423. def test_get_primary_scenarios(self):
  424. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._get_primary_scenarios") as mck:
  425. tp.get_primary_scenarios()
  426. mck.assert_called_once_with()
  427. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._filter_by_creation_time") as mck:
  428. tp.get_scenarios(created_end_time=datetime.datetime(2021, 1, 1))
  429. mck.assert_called_once_with([], None, datetime.datetime(2021, 1, 1))
  430. def test_set_primary(self, scenario):
  431. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._set_primary") as mck:
  432. tp.set_primary(scenario)
  433. mck.assert_called_once_with(scenario)
  434. def test_tag_and_untag(self, scenario):
  435. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._tag") as mck:
  436. tp.tag(scenario, "tag")
  437. mck.assert_called_once_with(scenario, "tag")
  438. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._untag") as mck:
  439. tp.untag(scenario, "tag")
  440. mck.assert_called_once_with(scenario, "tag")
  441. def test_compare_scenarios(self, scenario):
  442. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._compare") as mck:
  443. tp.compare_scenarios(scenario, scenario, data_node_config_id="dn")
  444. mck.assert_called_once_with(scenario, scenario, data_node_config_id="dn")
  445. def test_subscribe_scenario(self, scenario):
  446. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._subscribe") as mck:
  447. tp.subscribe_scenario(cb)
  448. mck.assert_called_once_with(cb, [], None)
  449. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._subscribe") as mck:
  450. tp.subscribe_scenario(cb, scenario=scenario)
  451. mck.assert_called_once_with(cb, [], scenario)
  452. def test_unsubscribe_scenario(self, scenario):
  453. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._unsubscribe") as mck:
  454. tp.unsubscribe_scenario(cb)
  455. mck.assert_called_once_with(cb, None, None)
  456. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._unsubscribe") as mck:
  457. tp.unsubscribe_scenario(cb, scenario=scenario)
  458. mck.assert_called_once_with(cb, None, scenario)
  459. def test_subscribe_sequence(self, sequence):
  460. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._subscribe") as mck:
  461. tp.subscribe_sequence(cb)
  462. mck.assert_called_once_with(cb, None, None)
  463. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._subscribe") as mck:
  464. tp.subscribe_sequence(cb, sequence=sequence)
  465. mck.assert_called_once_with(cb, None, sequence)
  466. def test_unsubscribe_sequence(self, sequence):
  467. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._unsubscribe") as mck:
  468. tp.unsubscribe_sequence(callback=cb)
  469. mck.assert_called_once_with(cb, None, None)
  470. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._unsubscribe") as mck:
  471. tp.unsubscribe_sequence(callback=cb, sequence=sequence)
  472. mck.assert_called_once_with(cb, None, sequence)
  473. def test_delete_sequence(self):
  474. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._hard_delete") as mck:
  475. sequence_id = SequenceId("SEQUENCE_id")
  476. tp.delete(sequence_id)
  477. mck.assert_called_once_with(sequence_id)
  478. def test_get_sequence(self, sequence):
  479. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._get") as mck:
  480. sequence_id = SequenceId("SEQUENCE_id")
  481. tp.get(sequence_id)
  482. mck.assert_called_once_with(sequence_id)
  483. def test_get_sequences(self):
  484. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._get_all") as mck:
  485. tp.get_sequences()
  486. mck.assert_called_once_with()
  487. def test_sequence_exists(self):
  488. with mock.patch("taipy.core.sequence._sequence_manager._SequenceManager._exists") as mck:
  489. sequence_id = SequenceId("SEQUENCE_id")
  490. tp.exists(sequence_id)
  491. mck.assert_called_once_with(sequence_id)
  492. def test_get_job(self):
  493. with mock.patch("taipy.core.job._job_manager._JobManager._get") as mck:
  494. job_id = JobId("JOB_id")
  495. tp.get(job_id)
  496. mck.assert_called_once_with(job_id)
  497. def test_get_jobs(self):
  498. with mock.patch("taipy.core.job._job_manager._JobManager._get_all") as mck:
  499. tp.get_jobs()
  500. mck.assert_called_once_with()
  501. def test_job_exists(self):
  502. with mock.patch("taipy.core.job._job_manager._JobManager._exists") as mck:
  503. job_id = JobId("JOB_id")
  504. tp.exists(job_id)
  505. mck.assert_called_once_with(job_id)
  506. def test_delete_job(self, task):
  507. with mock.patch("taipy.core.job._job_manager._JobManager._delete") as mck:
  508. job = Job(JobId("job_id"), task, "submit_id", "scenario_id")
  509. tp.delete_job(job)
  510. mck.assert_called_once_with(job, False)
  511. with mock.patch("taipy.core.job._job_manager._JobManager._delete") as mck:
  512. job = Job(JobId("job_id"), task, "submit_id", "scenario_id")
  513. tp.delete_job(job, False)
  514. mck.assert_called_once_with(job, False)
  515. with mock.patch("taipy.core.job._job_manager._JobManager._delete") as mck:
  516. job = Job(JobId("job_id"), task, "submit_id", "scenario_id")
  517. tp.delete_job(job, True)
  518. mck.assert_called_once_with(job, True)
  519. def test_delete_jobs(self):
  520. with mock.patch("taipy.core.job._job_manager._JobManager._delete_all") as mck:
  521. tp.delete_jobs()
  522. mck.assert_called_once_with()
  523. def test_get_latest_job(self, task):
  524. with mock.patch("taipy.core.job._job_manager._JobManager._get_latest") as mck:
  525. tp.get_latest_job(task)
  526. mck.assert_called_once_with(task)
  527. def test_cancel_job(self):
  528. with mock.patch("taipy.core.job._job_manager._JobManager._cancel") as mck:
  529. tp.cancel_job("job_id")
  530. mck.assert_called_once_with("job_id")
  531. def test_get_submissions(self):
  532. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._get_all") as mck:
  533. tp.get_submissions()
  534. mck.assert_called_once_with()
  535. def test_get_submission(self, task):
  536. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._get") as mck:
  537. submission_id = SubmissionId("SUBMISSION_id")
  538. tp.get(submission_id)
  539. mck.assert_called_once_with(submission_id)
  540. def test_get_latest_submission(self, task):
  541. with mock.patch("taipy.core.submission._submission_manager._SubmissionManager._get_latest") as mck:
  542. tp.get_latest_submission(task)
  543. mck.assert_called_once_with(task)
  544. def test_block_config_when_orchestrator_is_running(self):
  545. input_cfg_1 = Config.configure_data_node(id="i1", storage_type="pickle", scope=Scope.SCENARIO, default_data=1)
  546. output_cfg_1 = Config.configure_data_node(id="o1", storage_type="pickle", scope=Scope.SCENARIO)
  547. task_cfg_1 = Config.configure_task("t1", print, input_cfg_1, output_cfg_1)
  548. Config.configure_scenario("s1", [task_cfg_1], [], Frequency.DAILY)
  549. with mock.patch("sys.argv", ["prog"]):
  550. orchestrator = Orchestrator()
  551. orchestrator.run()
  552. with pytest.raises(ConfigurationUpdateBlocked):
  553. Config.configure_scenario("block_scenario", [task_cfg_1])
  554. orchestrator.stop()
  555. def test_get_data_node(self, data_node):
  556. with mock.patch("taipy.core.data._data_manager._DataManager._get") as mck:
  557. tp.get(data_node.id)
  558. mck.assert_called_once_with(data_node.id)
  559. def test_get_data_nodes(self):
  560. with mock.patch("taipy.core.data._data_manager._DataManager._get_all") as mck:
  561. tp.get_data_nodes()
  562. mck.assert_called_once_with()
  563. def test_data_node_exists(self):
  564. with mock.patch("taipy.core.data._data_manager._DataManager._exists") as mck:
  565. data_node_id = DataNodeId("DATANODE_id")
  566. tp.exists(data_node_id)
  567. mck.assert_called_once_with(data_node_id)
  568. def test_get_cycles(self):
  569. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._get_all") as mck:
  570. tp.get_cycles()
  571. mck.assert_called_once_with()
  572. def test_cycle_exists(self):
  573. with mock.patch("taipy.core.cycle._cycle_manager._CycleManager._exists") as mck:
  574. cycle_id = CycleId("CYCLE_id")
  575. tp.exists(cycle_id)
  576. mck.assert_called_once_with(cycle_id)
  577. def test_can_create(self):
  578. global_dn_config = Config.configure_in_memory_data_node("global_dn", 10, scope=Scope.GLOBAL)
  579. dn_config = Config.configure_in_memory_data_node("dn", 10)
  580. task_config = Config.configure_task("task", print, [dn_config])
  581. scenario_config = Config.configure_scenario("sc", {task_config}, [], Frequency.DAILY)
  582. assert tp.can_create()
  583. assert tp.can_create(scenario_config)
  584. assert tp.can_create(global_dn_config)
  585. assert not tp.can_create(dn_config)
  586. assert not tp.can_create("1")
  587. def test_create_global_data_node(self):
  588. dn_cfg_global = DataNodeConfig("id", "pickle", Scope.GLOBAL)
  589. dn_cfg_scenario = DataNodeConfig("id", "pickle", Scope.SCENARIO)
  590. with mock.patch("taipy.core.data._data_manager._DataManager._create_and_set") as dn_create_mock:
  591. with mock.patch("taipy.core.orchestrator.Orchestrator._manage_version_and_block_config") as mv_mock:
  592. dn = tp.create_global_data_node(dn_cfg_global)
  593. dn_create_mock.assert_called_once_with(dn_cfg_global, None, None)
  594. mv_mock.assert_called_once()
  595. dn = tp.create_global_data_node(dn_cfg_global)
  596. assert dn.scope == Scope.GLOBAL
  597. assert dn.config_id == dn_cfg_global.id
  598. assert _VersionManager._get(dn.version) is not None
  599. # Create a global data node from the same configuration should return the same data node
  600. dn_2 = tp.create_global_data_node(dn_cfg_global)
  601. assert dn_2.id == dn.id
  602. with pytest.raises(DataNodeConfigIsNotGlobal):
  603. tp.create_global_data_node(dn_cfg_scenario)
  604. def test_create_scenario(self):
  605. scenario_config = ScenarioConfig("scenario_config")
  606. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._create") as mck:
  607. with mock.patch("taipy.core.orchestrator.Orchestrator._manage_version_and_block_config") as mv_mock:
  608. tp.create_scenario(scenario_config)
  609. mck.assert_called_once_with(scenario_config, None, None)
  610. mv_mock.assert_called_once()
  611. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._create") as mck:
  612. tp.create_scenario(scenario_config, datetime.datetime(2022, 2, 5))
  613. mck.assert_called_once_with(scenario_config, datetime.datetime(2022, 2, 5), None)
  614. with mock.patch("taipy.core.scenario._scenario_manager._ScenarioManager._create") as mck:
  615. tp.create_scenario(scenario_config, datetime.datetime(2022, 2, 5), "displayable_name")
  616. mck.assert_called_once_with(scenario_config, datetime.datetime(2022, 2, 5), "displayable_name")
  617. def test_get_parents(self):
  618. def assert_result_parents_and_expected_parents(parents, expected_parents):
  619. for key, items in expected_parents.items():
  620. assert len(parents[key]) == len(expected_parents[key])
  621. parent_ids = [parent.id for parent in parents[key]]
  622. assert all(item.id in parent_ids for item in items)
  623. dn_config_1 = Config.configure_data_node(id="d1", storage_type="in_memory", scope=Scope.SCENARIO)
  624. dn_config_2 = Config.configure_data_node(id="d2", storage_type="in_memory", scope=Scope.SCENARIO)
  625. dn_config_3 = Config.configure_data_node(id="d3", storage_type="in_memory", scope=Scope.SCENARIO)
  626. dn_config_4 = Config.configure_data_node(id="d4", storage_type="in_memory", scope=Scope.SCENARIO)
  627. t_config_1 = Config.configure_task("t1", print, dn_config_1, dn_config_2)
  628. t_config_2 = Config.configure_task("t2", print, dn_config_2, dn_config_3)
  629. scenario_cfg_1 = Config.configure_scenario("s1", [t_config_1, t_config_2], [dn_config_4], Frequency.DAILY)
  630. scenario = tp.create_scenario(scenario_cfg_1)
  631. tasks = scenario.tasks
  632. expected_parents = {
  633. "scenario": {scenario},
  634. "task": {tasks["t1"]},
  635. }
  636. parents = tp.get_parents(scenario.tasks["t1"].data_nodes["d1"])
  637. assert_result_parents_and_expected_parents(parents, expected_parents)
  638. expected_parents = {
  639. "scenario": {scenario},
  640. "task": {tasks["t1"], tasks["t2"]},
  641. }
  642. parents = tp.get_parents(scenario.tasks["t1"].data_nodes["d2"])
  643. assert_result_parents_and_expected_parents(parents, expected_parents)
  644. expected_parents = {"scenario": {scenario}, "task": {tasks["t2"]}}
  645. parents = tp.get_parents(scenario.tasks["t2"].data_nodes["d3"])
  646. assert_result_parents_and_expected_parents(parents, expected_parents)
  647. expected_parents = {"scenario": {scenario}}
  648. parents = tp.get_parents(scenario.tasks["t1"])
  649. assert_result_parents_and_expected_parents(parents, expected_parents)
  650. expected_parents = {"scenario": {scenario}}
  651. parents = tp.get_parents(scenario.tasks["t2"])
  652. assert_result_parents_and_expected_parents(parents, expected_parents)
  653. expected_parents = {"scenario": {scenario}}
  654. parents = tp.get_parents(scenario.additional_data_nodes["d4"])
  655. assert_result_parents_and_expected_parents(parents, expected_parents)
  656. expected_parents = {}
  657. parents = tp.get_parents(scenario)
  658. assert_result_parents_and_expected_parents(parents, expected_parents)
  659. expected_parents = {}
  660. parents = tp.get_parents(scenario.cycle)
  661. assert_result_parents_and_expected_parents(parents, expected_parents)
  662. def test_get_cycles_scenarios(self):
  663. scenario_cfg_1 = Config.configure_scenario("s1", [], [], Frequency.DAILY)
  664. scenario_cfg_2 = Config.configure_scenario("s2", [], [], Frequency.WEEKLY)
  665. scenario_cfg_3 = Config.configure_scenario("s3", [], [], Frequency.MONTHLY)
  666. scenario_cfg_4 = Config.configure_scenario("s4", [], [], Frequency.YEARLY)
  667. scenario_cfg_5 = Config.configure_scenario("s5", [], [], None)
  668. now = datetime.datetime.now()
  669. scenario_1_1 = tp.create_scenario(scenario_cfg_1, now)
  670. scenario_1_2 = tp.create_scenario(scenario_cfg_1, datetime.datetime.now())
  671. scenario_1_3 = tp.create_scenario(scenario_cfg_1, now + datetime.timedelta(days=1))
  672. scenario_1_4 = tp.create_scenario(scenario_cfg_1, now + datetime.timedelta(days=8))
  673. scenario_1_5 = tp.create_scenario(scenario_cfg_1, now + datetime.timedelta(days=25))
  674. scenario_2 = tp.create_scenario(scenario_cfg_2)
  675. scenario_3 = tp.create_scenario(scenario_cfg_3)
  676. scenario_4 = tp.create_scenario(scenario_cfg_4)
  677. scenario_5_1 = tp.create_scenario(scenario_cfg_5)
  678. scenario_5_2 = tp.create_scenario(scenario_cfg_5)
  679. scenario_5_3 = tp.create_scenario(scenario_cfg_5)
  680. expected_cycles_scenarios = {
  681. scenario_1_1.cycle: [scenario_1_1.id, scenario_1_2.id],
  682. scenario_1_3.cycle: [scenario_1_3.id],
  683. scenario_1_4.cycle: [scenario_1_4.id],
  684. scenario_1_5.cycle: [scenario_1_5.id],
  685. scenario_2.cycle: [scenario_2.id],
  686. scenario_3.cycle: [scenario_3.id],
  687. scenario_4.cycle: [scenario_4.id],
  688. None: [scenario_5_1.id, scenario_5_2.id, scenario_5_3.id],
  689. }
  690. cycles_scenarios = tp.get_cycles_scenarios()
  691. assert expected_cycles_scenarios.keys() == cycles_scenarios.keys()
  692. for cycle, scenarios in cycles_scenarios.items():
  693. expected_scenarios = expected_cycles_scenarios[cycle]
  694. assert sorted([scenario.id for scenario in scenarios]) == sorted(expected_scenarios)
  695. def test_get_entities_by_config_id(self):
  696. scenario_config_1 = Config.configure_scenario("s1", sequence_configs=[])
  697. scenario_config_2 = Config.configure_scenario("s2", sequence_configs=[])
  698. s_1_1 = tp.create_scenario(scenario_config_1)
  699. s_1_2 = tp.create_scenario(scenario_config_1)
  700. s_1_3 = tp.create_scenario(scenario_config_1)
  701. assert len(tp.get_scenarios()) == 3
  702. s_2_1 = tp.create_scenario(scenario_config_2)
  703. s_2_2 = tp.create_scenario(scenario_config_2)
  704. assert len(tp.get_scenarios()) == 5
  705. s1_scenarios = tp.get_entities_by_config_id(scenario_config_1.id)
  706. assert len(s1_scenarios) == 3
  707. assert sorted([s_1_1.id, s_1_2.id, s_1_3.id]) == sorted([scenario.id for scenario in s1_scenarios])
  708. s2_scenarios = tp.get_entities_by_config_id(scenario_config_2.id)
  709. assert len(s2_scenarios) == 2
  710. assert sorted([s_2_1.id, s_2_2.id]) == sorted([scenario.id for scenario in s2_scenarios])
  711. def test_get_entities_by_config_id_in_multiple_versions_environment(self):
  712. scenario_config_1 = Config.configure_scenario("s1", sequence_configs=[])
  713. scenario_config_2 = Config.configure_scenario("s2", sequence_configs=[])
  714. _VersionManager._set_experiment_version("1.0")
  715. tp.create_scenario(scenario_config_1)
  716. tp.create_scenario(scenario_config_1)
  717. tp.create_scenario(scenario_config_1)
  718. tp.create_scenario(scenario_config_2)
  719. tp.create_scenario(scenario_config_2)
  720. assert len(tp.get_scenarios()) == 5
  721. assert len(tp.get_entities_by_config_id(scenario_config_1.id)) == 3
  722. assert len(tp.get_entities_by_config_id(scenario_config_2.id)) == 2
  723. _VersionManager._set_experiment_version("2.0")
  724. tp.create_scenario(scenario_config_1)
  725. tp.create_scenario(scenario_config_1)
  726. tp.create_scenario(scenario_config_1)
  727. tp.create_scenario(scenario_config_2)
  728. tp.create_scenario(scenario_config_2)
  729. assert len(tp.get_scenarios()) == 5
  730. assert len(tp.get_entities_by_config_id(scenario_config_1.id)) == 3
  731. assert len(tp.get_entities_by_config_id(scenario_config_2.id)) == 2