瀏覽代碼

Merge pull request #1836 from Avaiga/feature/#1805-protect-reason-apis

feature/#1805 added checking if entity exists
Toan Quach 7 月之前
父節點
當前提交
b9f75ef4a8

+ 8 - 2
taipy/core/_manager/_manager.py

@@ -161,8 +161,14 @@ class _Manager(Generic[EntityType]):
 
     @classmethod
     def _is_editable(cls, entity: Union[EntityType, str]) -> ReasonCollection:
-        return ReasonCollection()
+        reason_collection = ReasonCollection()
+        if cls._get(entity) is None:
+            reason_collection._add_reason(str(entity), EntityDoesNotExist(str(entity)))
+        return reason_collection
 
     @classmethod
     def _is_readable(cls, entity: Union[EntityType, str]) -> ReasonCollection:
-        return ReasonCollection()
+        reason_collection = ReasonCollection()
+        if cls._get(entity) is None:
+            reason_collection._add_reason(str(entity), EntityDoesNotExist(str(entity)))
+        return reason_collection

+ 11 - 6
taipy/core/_orchestrator/_orchestrator_factory.py

@@ -9,11 +9,11 @@
 # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
 import typing
-from importlib import util
 from typing import Optional, Type
 
 from taipy.config.config import Config
 
+from ..common._check_dependencies import _TAIPY_ENTERPRISE_MODULE, _using_enterprise
 from ..common._utils import _load_fct
 from ..exceptions.exceptions import ModeNotAvailable, OrchestratorNotBuilt
 from ._abstract_orchestrator import _AbstractOrchestrator
@@ -22,7 +22,6 @@ from ._orchestrator import _Orchestrator
 
 
 class _OrchestratorFactory:
-    _TAIPY_ENTERPRISE_MODULE = "taipy.enterprise"
     _TAIPY_ENTERPRISE_CORE_ORCHESTRATOR_MODULE = _TAIPY_ENTERPRISE_MODULE + ".core._orchestrator._orchestrator"
     _TAIPY_ENTERPRISE_CORE_DISPATCHER_MODULE = _TAIPY_ENTERPRISE_MODULE + ".core._orchestrator._dispatcher"
     __TAIPY_ENTERPRISE_BUILD_DISPATCHER_METHOD = "_build_dispatcher"
@@ -34,7 +33,7 @@ class _OrchestratorFactory:
     def _build_orchestrator(cls) -> Type[_AbstractOrchestrator]:
         if cls._orchestrator:
             return cls._orchestrator  # type: ignore
-        if util.find_spec(cls._TAIPY_ENTERPRISE_MODULE) is not None:
+        if _using_enterprise():
             cls._orchestrator = _load_fct(
                 cls._TAIPY_ENTERPRISE_CORE_ORCHESTRATOR_MODULE,
                 "Orchestrator",
@@ -51,7 +50,7 @@ class _OrchestratorFactory:
         if not cls._orchestrator:
             raise OrchestratorNotBuilt
 
-        if util.find_spec(cls._TAIPY_ENTERPRISE_MODULE):
+        if _using_enterprise():
             cls.__build_enterprise_job_dispatcher(force_restart=force_restart)
         elif Config.job_config.is_standalone:
             cls.__build_standalone_job_dispatcher(force_restart=force_restart)
@@ -77,7 +76,7 @@ class _OrchestratorFactory:
             else:
                 return
 
-        if util.find_spec(cls._TAIPY_ENTERPRISE_MODULE) is not None:
+        if _using_enterprise():
             cls._dispatcher = _load_fct(
                 cls._TAIPY_ENTERPRISE_CORE_DISPATCHER_MODULE, cls.__TAIPY_ENTERPRISE_BUILD_DISPATCHER_METHOD
             )(cls._orchestrator)
@@ -89,7 +88,13 @@ class _OrchestratorFactory:
     def __build_development_job_dispatcher(cls):
         if isinstance(cls._dispatcher, _StandaloneJobDispatcher):
             cls._dispatcher.stop()
-        cls._dispatcher = _DevelopmentJobDispatcher(typing.cast(_AbstractOrchestrator, cls._orchestrator))
+
+        if _using_enterprise():
+            cls._dispatcher = _load_fct(
+                cls._TAIPY_ENTERPRISE_CORE_DISPATCHER_MODULE, cls.__TAIPY_ENTERPRISE_BUILD_DISPATCHER_METHOD
+            )(cls._orchestrator)
+        else:
+            cls._dispatcher = _DevelopmentJobDispatcher(typing.cast(_AbstractOrchestrator, cls._orchestrator))
 
     @classmethod
     def __build_enterprise_job_dispatcher(cls, force_restart=False):

+ 7 - 3
taipy/core/job/_job_manager.py

@@ -18,7 +18,7 @@ from .._version._version_manager_factory import _VersionManagerFactory
 from .._version._version_mixin import _VersionMixin
 from ..exceptions.exceptions import JobNotDeletedException
 from ..notification import EventEntityType, EventOperation, Notifier, _make_event
-from ..reason import JobIsNotFinished, ReasonCollection
+from ..reason import EntityDoesNotExist, JobIsNotFinished, ReasonCollection
 from ..task.task import Task
 from .job import Job
 from .job_id import JobId
@@ -92,9 +92,13 @@ class _JobManager(_Manager[Job], _VersionMixin):
         reason_collector = ReasonCollection()
 
         if isinstance(job, str):
-            job = cls._get(job)
+            job_id = job
+            job = cls._get(job, None)
+            if job is None:
+                reason_collector._add_reason(job_id, EntityDoesNotExist(job_id))
+                return reason_collector
 
-        if job and not job.is_finished():
+        if not job.is_finished():
             reason_collector._add_reason(job.id, JobIsNotFinished(job.id))
 
         return reason_collector

+ 1 - 0
taipy/core/reason/__init__.py

@@ -26,6 +26,7 @@ from .reason import (
     DataNodeEditInProgress,
     DataNodeIsNotWritten,
     EntityDoesNotExist,
+    EntityIsNotAScenario,
     EntityIsNotSubmittableEntity,
     InvalidUploadFile,
     JobIsNotFinished,

+ 24 - 10
taipy/core/reason/reason.py

@@ -151,8 +151,9 @@ class NoFileToDownload(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, file_path: str, datanode_id: str):
-        Reason.__init__(self, f"Path '{file_path}' from data node '{datanode_id}'"
-                              f" does not exist and cannot be downloaded.")
+        Reason.__init__(
+            self, f"Path '{file_path}' from data node '{datanode_id}'" f" does not exist and cannot be downloaded"
+        )
         _DataNodeReasonMixin.__init__(self, datanode_id)
 
 
@@ -165,8 +166,9 @@ class NotAFile(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, file_path: str, datanode_id: str):
-        Reason.__init__(self, f"Path '{file_path}' from data node '{datanode_id}'"
-                              f" is not a file and can t be downloaded.")
+        Reason.__init__(
+            self, f"Path '{file_path}' from data node '{datanode_id}'" f" is not a file and can t be downloaded"
+        )
         _DataNodeReasonMixin.__init__(self, datanode_id)
 
 
@@ -193,7 +195,7 @@ class EntityDoesNotExist(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, entity_id: str):
-        Reason.__init__(self, f"Entity {entity_id} does not exist in the repository.")
+        Reason.__init__(self, f"Entity {entity_id} does not exist in the repository")
 
 
 class JobIsNotFinished(Reason, _DataNodeReasonMixin):
@@ -205,7 +207,19 @@ class JobIsNotFinished(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, job_id: str):
-        Reason.__init__(self, f"The job {job_id} is not finished yet.")
+        Reason.__init__(self, f"The job {job_id} is not finished yet")
+
+
+class EntityIsNotAScenario(Reason, _DataNodeReasonMixin):
+    """
+    The entity is not a scenario, which prevents specific actions from being performed.
+
+    Attributes:
+        entity_id (str): The entity identifier.
+    """
+
+    def __init__(self, entity_id: str):
+        Reason.__init__(self, f"The entity {entity_id} is not a scenario")
 
 
 class ScenarioIsThePrimaryScenario(Reason, _DataNodeReasonMixin):
@@ -218,7 +232,7 @@ class ScenarioIsThePrimaryScenario(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, scenario_id: str, cycle: str):
-        Reason.__init__(self, f"The scenario {scenario_id} is the primary scenario of cycle {cycle}.")
+        Reason.__init__(self, f"The scenario {scenario_id} is the primary scenario of cycle {cycle}")
 
 
 class ScenarioDoesNotBelongToACycle(Reason, _DataNodeReasonMixin):
@@ -230,7 +244,7 @@ class ScenarioDoesNotBelongToACycle(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, scenario_id: str):
-        Reason.__init__(self, f"The scenario {scenario_id} does not belong to any cycle.")
+        Reason.__init__(self, f"The scenario {scenario_id} does not belong to any cycle")
 
 
 class SubmissionIsNotFinished(Reason, _DataNodeReasonMixin):
@@ -242,7 +256,7 @@ class SubmissionIsNotFinished(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, submission_id: str):
-        Reason.__init__(self, f"The submission {submission_id} is not finished yet.")
+        Reason.__init__(self, f"The submission {submission_id} is not finished yet")
 
 
 class SubmissionStatusIsUndefined(Reason, _DataNodeReasonMixin):
@@ -254,4 +268,4 @@ class SubmissionStatusIsUndefined(Reason, _DataNodeReasonMixin):
     """
 
     def __init__(self, submission_id: str):
-        Reason.__init__(self, f"The status of submission {submission_id} is undefined.")
+        Reason.__init__(self, f"The status of submission {submission_id} is undefined")

+ 20 - 6
taipy/core/scenario/_scenario_manager.py

@@ -41,6 +41,7 @@ from ..job.job import Job
 from ..notification import EventEntityType, EventOperation, Notifier, _make_event
 from ..reason import (
     EntityDoesNotExist,
+    EntityIsNotAScenario,
     EntityIsNotSubmittableEntity,
     ReasonCollection,
     ScenarioDoesNotBelongToACycle,
@@ -208,16 +209,21 @@ class _ScenarioManager(_Manager[Scenario], _VersionMixin):
 
     @classmethod
     def _is_submittable(cls, scenario: Union[Scenario, ScenarioId]) -> ReasonCollection:
+        reason_collector = ReasonCollection()
+
         if isinstance(scenario, str):
+            scenario_id = scenario
             scenario = cls._get(scenario)
+            if scenario is None:
+                reason_collector._add_reason(scenario_id, EntityDoesNotExist(scenario_id))
+                return reason_collector
 
         if not isinstance(scenario, Scenario):
-            scenario = str(scenario)
-            reason_collector = ReasonCollection()
-            reason_collector._add_reason(scenario, EntityIsNotSubmittableEntity(scenario))
-            return reason_collector
+            reason_collector._add_reason(str(scenario), EntityIsNotSubmittableEntity(str(scenario)))
+        else:
+            return scenario.is_ready_to_run()
 
-        return scenario.is_ready_to_run()
+        return reason_collector
 
     @classmethod
     def _submit(
@@ -425,10 +431,18 @@ class _ScenarioManager(_Manager[Scenario], _VersionMixin):
         reason_collection = ReasonCollection()
 
         if isinstance(scenario, str):
+            scenario_id = scenario
             scenario = cls._get(scenario)
-        if scenario.is_primary:
+            if scenario is None:
+                reason_collection._add_reason(scenario_id, EntityDoesNotExist(scenario_id))
+                return reason_collection
+
+        if not isinstance(scenario, Scenario):
+            reason_collection._add_reason(str(scenario), EntityIsNotAScenario(str(scenario)))
+        elif scenario.is_primary:
             if len(cls._get_all_by_cycle(scenario.cycle)) > 1:
                 reason_collection._add_reason(scenario.id, ScenarioIsThePrimaryScenario(scenario.id, scenario.cycle.id))
+
         return reason_collection
 
     @classmethod

+ 10 - 5
taipy/core/sequence/_sequence_manager.py

@@ -342,16 +342,21 @@ class _SequenceManager(_Manager[Sequence], _VersionMixin):
 
     @classmethod
     def _is_submittable(cls, sequence: Union[Sequence, SequenceId]) -> ReasonCollection:
+        reason_collector = ReasonCollection()
+
         if isinstance(sequence, str):
+            sequence_id = sequence
             sequence = cls._get(sequence)
+            if sequence is None:
+                reason_collector._add_reason(sequence_id, EntityDoesNotExist(sequence_id))
+                return reason_collector
 
         if not isinstance(sequence, Sequence):
-            sequence = str(sequence)
-            reason_collector = ReasonCollection()
-            reason_collector._add_reason(sequence, EntityIsNotSubmittableEntity(sequence))
-            return reason_collector
+            reason_collector._add_reason(str(sequence), EntityIsNotSubmittableEntity(str(sequence)))
+        else:
+            return sequence.is_ready_to_run()
 
-        return sequence.is_ready_to_run()
+        return reason_collector
 
     @classmethod
     def _submit(

+ 5 - 1
taipy/core/submission/_submission_manager.py

@@ -21,7 +21,7 @@ from .._version._version_mixin import _VersionMixin
 from ..exceptions.exceptions import SubmissionNotDeletedException
 from ..job.job import Job, Status
 from ..notification import EventEntityType, EventOperation, Notifier, _make_event
-from ..reason import ReasonCollection, SubmissionIsNotFinished
+from ..reason import EntityDoesNotExist, ReasonCollection, SubmissionIsNotFinished
 from ..scenario.scenario import Scenario
 from ..sequence.sequence import Sequence
 from ..submission.submission import Submission, SubmissionId, SubmissionStatus
@@ -178,7 +178,11 @@ class _SubmissionManager(_Manager[Submission], _VersionMixin):
         reason_collector = ReasonCollection()
 
         if isinstance(submission, str):
+            submission_id = submission
             submission = cls._get(submission)
+            if submission is None:
+                reason_collector._add_reason(submission_id, EntityDoesNotExist(submission_id))
+                return reason_collector
 
         if not submission.is_finished() and submission.submission_status != SubmissionStatus.UNDEFINED:
             reason_collector._add_reason(submission.id, SubmissionIsNotFinished(submission.id))

+ 13 - 4
taipy/core/task/_task_manager.py

@@ -26,7 +26,13 @@ from ..cycle.cycle_id import CycleId
 from ..data._data_manager_factory import _DataManagerFactory
 from ..exceptions.exceptions import NonExistingTask
 from ..notification import EventEntityType, EventOperation, Notifier, _make_event
-from ..reason import DataNodeEditInProgress, DataNodeIsNotWritten, EntityIsNotSubmittableEntity, ReasonCollection
+from ..reason import (
+    DataNodeEditInProgress,
+    DataNodeIsNotWritten,
+    EntityDoesNotExist,
+    EntityIsNotSubmittableEntity,
+    ReasonCollection,
+)
 from ..scenario.scenario_id import ScenarioId
 from ..sequence.sequence_id import SequenceId
 from ..submission.submission import Submission
@@ -165,13 +171,16 @@ class _TaskManager(_Manager[Task], _VersionMixin):
 
     @classmethod
     def _is_submittable(cls, task: Union[Task, TaskId]) -> ReasonCollection:
+        reason_collection = ReasonCollection()
+
         if isinstance(task, str):
+            task_id = task
             task = cls._get(task)
+            if task is None:
+                reason_collection._add_reason(task_id, EntityDoesNotExist(task_id))
 
-        reason_collection = ReasonCollection()
         if not isinstance(task, Task):
-            task = str(task)
-            reason_collection._add_reason(task, EntityIsNotSubmittableEntity(task))
+            reason_collection._add_reason(str(task), EntityIsNotSubmittableEntity(str(task)))
         else:
             data_manager = _DataManagerFactory._build_manager()
             for node in task.input.values():

+ 8 - 0
tests/core/_manager/test_manager.py

@@ -166,7 +166,15 @@ class TestManager:
         MockManager._set(m)
         assert MockManager._is_editable(m)
 
+        rc = MockManager._is_editable("some_entity")
+        assert not rc
+        assert "Entity some_entity does not exist in the repository." in rc.reasons
+
     def test_is_readable(self):
         m = MockEntity("uuid", "Foo")
         MockManager._set(m)
         assert MockManager._is_readable(m)
+
+        rc = MockManager._is_editable("some_entity")
+        assert not rc
+        assert "Entity some_entity does not exist in the repository." in rc.reasons

+ 4 - 0
tests/core/job/test_job_manager.py

@@ -412,6 +412,10 @@ def test_is_deletable():
     task = _create_task(print, 0, "task")
     job = _OrchestratorFactory._orchestrator.submit_task(task).jobs[0]
 
+    rc = _JobManager._is_deletable("some_job")
+    assert not rc
+    assert "Entity some_job does not exist in the repository." in rc.reasons
+
     assert job.is_completed()
     assert _JobManager._is_deletable(job)
     assert _JobManager._is_deletable(job.id)

+ 10 - 4
tests/core/scenario/test_scenario_manager.py

@@ -404,6 +404,10 @@ def test_is_deletable():
     scenario_1_primary = _ScenarioManager._create(scenario_config, creation_date=creation_date, name="1")
     scenario_2 = _ScenarioManager._create(scenario_config, creation_date=creation_date, name="2")
 
+    rc = _ScenarioManager._is_deletable("some_scenario")
+    assert not rc
+    assert "Entity some_scenario does not exist in the repository." in rc.reasons
+
     assert len(_ScenarioManager._get_all()) == 2
     assert scenario_1_primary.is_primary
     assert not _ScenarioManager._is_deletable(scenario_1_primary)
@@ -681,12 +685,10 @@ def notify_multi_param(param, *args):
     assert len(param) == 3
 
 
-def notify1(*args, **kwargs):
-    ...
+def notify1(*args, **kwargs): ...
 
 
-def notify2(*args, **kwargs):
-    ...
+def notify2(*args, **kwargs): ...
 
 
 def test_notification_unsubscribe(mocker):
@@ -1045,6 +1047,10 @@ def test_is_submittable():
     scenario_config = Config.configure_scenario("sc", {task_config}, set(), Frequency.DAILY)
     scenario = _ScenarioManager._create(scenario_config)
 
+    rc = _ScenarioManager._is_submittable("some_scenario")
+    assert not rc
+    assert "Entity some_scenario does not exist in the repository." in rc.reasons
+
     assert len(_ScenarioManager._get_all()) == 1
     assert _ScenarioManager._is_submittable(scenario)
     assert _ScenarioManager._is_submittable(scenario.id)

+ 7 - 6
tests/core/sequence/test_sequence_manager.py

@@ -206,6 +206,10 @@ def test_is_submittable():
     scenario = Scenario("scenario", {task}, {}, set())
     _ScenarioManager._set(scenario)
 
+    rc = _SequenceManager._is_submittable("some_sequence")
+    assert not rc
+    assert "Entity some_sequence does not exist in the repository." in rc.reasons
+
     scenario.add_sequences({"sequence": [task]})
     sequence = scenario.sequences["sequence"]
 
@@ -445,16 +449,13 @@ def test_get_or_create_data():
         sequence.WRONG.write(7)
 
 
-def notify1(*args, **kwargs):
-    ...
+def notify1(*args, **kwargs): ...
 
 
-def notify2(*args, **kwargs):
-    ...
+def notify2(*args, **kwargs): ...
 
 
-def notify_multi_param(*args, **kwargs):
-    ...
+def notify_multi_param(*args, **kwargs): ...
 
 
 def test_sequence_notification_subscribe(mocker):

+ 4 - 0
tests/core/submission/test_submission_manager.py

@@ -151,6 +151,10 @@ def test_is_deletable():
 
     assert len(submission_manager._get_all()) == 1
 
+    rc = submission_manager._is_deletable("some_submission")
+    assert not rc
+    assert "Entity some_submission does not exist in the repository." in rc.reasons
+
     assert submission._submission_status == SubmissionStatus.SUBMITTED
     assert not submission.is_deletable()
     assert not submission_manager._is_deletable(submission)

+ 4 - 0
tests/core/task/test_task_manager.py

@@ -308,6 +308,10 @@ def test_is_submittable():
     task_config = Config.configure_task("task", print, [dn_config])
     task = _TaskManager._bulk_get_or_create([task_config])[0]
 
+    rc = _TaskManager._is_submittable("some_task")
+    assert not rc
+    assert "Entity some_task does not exist in the repository" in rc.reasons
+
     assert len(_TaskManager._get_all()) == 1
     assert _TaskManager._is_submittable(task)
     assert _TaskManager._is_submittable(task.id)

+ 16 - 2
tests/gui_core/test_context_is_editable.py

@@ -11,9 +11,15 @@
 
 from unittest.mock import Mock, patch
 
+import pytest
+
 from taipy.config.common.scope import Scope
 from taipy.core import Job, JobId, Scenario, Task
+from taipy.core.data._data_manager_factory import _DataManagerFactory
 from taipy.core.data.pickle import PickleDataNode
+from taipy.core.job._job_manager_factory import _JobManagerFactory
+from taipy.core.scenario._scenario_manager_factory import _ScenarioManagerFactory
+from taipy.core.task._task_manager_factory import _TaskManagerFactory
 from taipy.gui import Gui
 from taipy.gui_core._context import _GuiCoreContext
 
@@ -48,6 +54,13 @@ class MockState:
 
 
 class TestGuiCoreContext_is_editable:
+    @pytest.fixture(scope="class", autouse=True)
+    def set_entity(self):
+        _ScenarioManagerFactory._build_manager()._set(a_scenario)
+        _TaskManagerFactory._build_manager()._set(a_task)
+        _JobManagerFactory._build_manager()._set(a_job)
+        _DataManagerFactory._build_manager()._set(a_datanode)
+
     def test_crud_scenario(self):
         with patch("taipy.gui_core._context.core_get", side_effect=mock_core_get):
             gui_core_context = _GuiCoreContext(Mock())
@@ -125,8 +138,9 @@ class TestGuiCoreContext_is_editable:
                 assert "is not editable" in str(assign.call_args.args[1])
 
     def test_act_on_jobs(self):
-        with patch("taipy.gui_core._context.core_get", side_effect=mock_core_get), patch(
-            "taipy.gui_core._context.is_deletable", side_effect=mock_is_true
+        with (
+            patch("taipy.gui_core._context.core_get", side_effect=mock_core_get),
+            patch("taipy.gui_core._context.is_deletable", side_effect=mock_is_true),
         ):
             gui_core_context = _GuiCoreContext(Mock())
             assign = Mock()

+ 16 - 2
tests/gui_core/test_context_is_promotable.py

@@ -11,9 +11,15 @@
 
 from unittest.mock import Mock, patch
 
+import pytest
+
 from taipy.config.common.scope import Scope
 from taipy.core import Job, JobId, Scenario, Task
+from taipy.core.data._data_manager_factory import _DataManagerFactory
 from taipy.core.data.pickle import PickleDataNode
+from taipy.core.job._job_manager_factory import _JobManagerFactory
+from taipy.core.scenario._scenario_manager_factory import _ScenarioManagerFactory
+from taipy.core.task._task_manager_factory import _TaskManagerFactory
 from taipy.gui_core._context import _GuiCoreContext
 
 a_scenario = Scenario("scenario_config_id", None, {}, sequences={"sequence": {}})
@@ -47,9 +53,17 @@ class MockState:
 
 
 class TestGuiCoreContext_is_promotable:
+    @pytest.fixture(scope="class", autouse=True)
+    def set_entity(self):
+        _ScenarioManagerFactory._build_manager()._set(a_scenario)
+        _TaskManagerFactory._build_manager()._set(a_task)
+        _JobManagerFactory._build_manager()._set(a_job)
+        _DataManagerFactory._build_manager()._set(a_datanode)
+
     def test_edit_entity(self):
-        with patch("taipy.gui_core._context.core_get", side_effect=mock_core_get), patch(
-            "taipy.gui_core._context.is_promotable", side_effect=mock_is_true
+        with (
+            patch("taipy.gui_core._context.core_get", side_effect=mock_core_get),
+            patch("taipy.gui_core._context.is_promotable", side_effect=mock_is_true),
         ):
             gui_core_context = _GuiCoreContext(Mock())
             assign = Mock()

+ 20 - 2
tests/gui_core/test_context_is_readable.py

@@ -14,11 +14,19 @@ import typing as t
 from datetime import datetime
 from unittest.mock import Mock, patch
 
+import pytest
+
 from taipy.config.common.frequency import Frequency
 from taipy.config.common.scope import Scope
 from taipy.core import Cycle, CycleId, Job, JobId, Scenario, Task
+from taipy.core.cycle._cycle_manager_factory import _CycleManagerFactory
+from taipy.core.data._data_manager_factory import _DataManagerFactory
 from taipy.core.data.pickle import PickleDataNode
+from taipy.core.job._job_manager_factory import _JobManagerFactory
+from taipy.core.scenario._scenario_manager_factory import _ScenarioManagerFactory
+from taipy.core.submission._submission_manager_factory import _SubmissionManagerFactory
 from taipy.core.submission.submission import Submission, SubmissionStatus
+from taipy.core.task._task_manager_factory import _TaskManagerFactory
 from taipy.gui import Gui
 from taipy.gui_core._context import _GuiCoreContext
 
@@ -64,6 +72,15 @@ class MockState:
 
 
 class TestGuiCoreContext_is_readable:
+    @pytest.fixture(scope="class", autouse=True)
+    def set_entity(self):
+        _CycleManagerFactory._build_manager()._set(a_cycle)
+        _ScenarioManagerFactory._build_manager()._set(a_scenario)
+        _TaskManagerFactory._build_manager()._set(a_task)
+        _JobManagerFactory._build_manager()._set(a_job)
+        _DataManagerFactory._build_manager()._set(a_datanode)
+        _SubmissionManagerFactory._build_manager()._set(a_submission)
+
     def test_scenario_adapter(self):
         with patch("taipy.gui_core._context.core_get", side_effect=mock_core_get):
             gui_core_context = _GuiCoreContext(Mock())
@@ -222,8 +239,9 @@ class TestGuiCoreContext_is_readable:
                 assert outcome is None
 
     def test_act_on_jobs(self):
-        with patch("taipy.gui_core._context.core_get", side_effect=mock_core_get), patch(
-            "taipy.gui_core._context.is_deletable", side_effect=mock_is_true
+        with (
+            patch("taipy.gui_core._context.core_get", side_effect=mock_core_get),
+            patch("taipy.gui_core._context.is_deletable", side_effect=mock_is_true),
         ):
             gui_core_context = _GuiCoreContext(Mock())
             assign = Mock()