diff --git a/taipy/core/_entity/_entity.py b/taipy/core/_entity/_entity.py index 7b5e3ed1be..f48d1a5a29 100644 --- a/taipy/core/_entity/_entity.py +++ b/taipy/core/_entity/_entity.py @@ -11,7 +11,7 @@ from typing import List -from .._entity._reload import _get_manager +from .._entity._reload import _Reloader from ..notification import Notifier @@ -33,8 +33,8 @@ def __exit__(self, exc_type, exc_value, exc_traceback): for to_delete_key in self._properties._pending_deletions: self._properties.data.pop(to_delete_key, None) self._properties.data.update(self._properties._pending_changes) - _get_manager(self._MANAGER_NAME)._set(self) + _Reloader._get_manager(self._MANAGER_NAME)._set(self) for event in self._in_context_attributes_changed_collector: Notifier.publish(event) - _get_manager(self._MANAGER_NAME)._set(self) + _Reloader._get_manager(self._MANAGER_NAME)._set(self) diff --git a/taipy/core/_entity/_reload.py b/taipy/core/_entity/_reload.py index ed32f3fc58..225ecfff02 100644 --- a/taipy/core/_entity/_reload.py +++ b/taipy/core/_entity/_reload.py @@ -10,8 +10,11 @@ # specific language governing permissions and limitations under the License. import functools +from typing import Dict, Type from .._manager._manager import _Manager +from ..common._check_dependencies import EnterpriseEditionUtils +from ..common._utils import _load_fct from ..notification import EventOperation, Notifier, _make_event @@ -19,19 +22,21 @@ class _Reloader: """The _Reloader singleton class""" _instance = None - _no_reload_context = False + _managers: Dict[str, Type[_Manager]] = {} + def __new__(cls, *args, **kwargs): if not isinstance(cls._instance, cls): cls._instance = object.__new__(cls, *args, **kwargs) + cls._managers = cls._build_managers() return cls._instance def _reload(self, manager: str, obj): if self._no_reload_context: return obj - entity = _get_manager(manager)._get(obj, obj) + entity = self._get_manager(manager)._get(obj, obj) if obj._is_in_context and hasattr(entity, "_properties"): if obj._properties._pending_changes: entity._properties._pending_changes = obj._properties._pending_changes @@ -47,6 +52,40 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, exc_traceback): self._no_reload_context = False + @classmethod + @functools.lru_cache + def _build_managers(cls) -> Dict[str, Type[_Manager]]: + from ..cycle._cycle_manager_factory import _CycleManagerFactory + from ..data._data_manager_factory import _DataManagerFactory + from ..job._job_manager_factory import _JobManagerFactory + from ..scenario._scenario_manager_factory import _ScenarioManagerFactory + from ..sequence._sequence_manager_factory import _SequenceManagerFactory + from ..submission._submission_manager_factory import _SubmissionManagerFactory + from ..task._task_manager_factory import _TaskManagerFactory + + managers: Dict[str, Type[_Manager]] = { + "scenario": _ScenarioManagerFactory._build_manager(), + "sequence": _SequenceManagerFactory._build_manager(), + "data": _DataManagerFactory._build_manager(), + "cycle": _CycleManagerFactory._build_manager(), + "job": _JobManagerFactory._build_manager(), + "task": _TaskManagerFactory._build_manager(), + "submission": _SubmissionManagerFactory._build_manager(), + } + + if EnterpriseEditionUtils._using_enterprise(): + _build_enterprise_managers = _load_fct( + EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + "._entity.utils", "_build_enterprise_managers" + ) + managers.update(_build_enterprise_managers()) + + return managers + + @classmethod + @functools.lru_cache + def _get_manager(cls, manager: str) -> Type[_Manager]: + return cls._managers[manager] + def _self_reload(manager: str): def __reload(fct): @@ -65,7 +104,7 @@ def __set_entity(fct): @functools.wraps(fct) def _do_set_entity(self, *args, **kwargs): fct(self, *args, **kwargs) - entity_manager = _get_manager(manager) + entity_manager = _Reloader._get_manager(manager) value = args[0] if len(args) == 1 else args event = _make_event( self, @@ -84,24 +123,3 @@ def _do_set_entity(self, *args, **kwargs): return _do_set_entity return __set_entity - - -@functools.lru_cache -def _get_manager(manager: str) -> _Manager: - from ..cycle._cycle_manager_factory import _CycleManagerFactory - from ..data._data_manager_factory import _DataManagerFactory - from ..job._job_manager_factory import _JobManagerFactory - from ..scenario._scenario_manager_factory import _ScenarioManagerFactory - from ..sequence._sequence_manager_factory import _SequenceManagerFactory - from ..submission._submission_manager_factory import _SubmissionManagerFactory - from ..task._task_manager_factory import _TaskManagerFactory - - return { - "scenario": _ScenarioManagerFactory._build_manager(), - "sequence": _SequenceManagerFactory._build_manager(), - "data": _DataManagerFactory._build_manager(), - "cycle": _CycleManagerFactory._build_manager(), - "job": _JobManagerFactory._build_manager(), - "task": _TaskManagerFactory._build_manager(), - "submission": _SubmissionManagerFactory._build_manager(), - }[manager] # type: ignore diff --git a/taipy/core/_manager/_manager_factory.py b/taipy/core/_manager/_manager_factory.py index baa03827e4..ff42695d10 100644 --- a/taipy/core/_manager/_manager_factory.py +++ b/taipy/core/_manager/_manager_factory.py @@ -20,7 +20,7 @@ class _ManagerFactory: @classmethod @abstractmethod - def _build_manager(cls) -> Type[_Manager]: # type: ignore + def _build_manager(cls) -> Type[_Manager]: raise NotImplementedError @classmethod diff --git a/taipy/core/data/_data_manager_factory.py b/taipy/core/data/_data_manager_factory.py index df69842c4f..33a0dcd455 100644 --- a/taipy/core/data/_data_manager_factory.py +++ b/taipy/core/data/_data_manager_factory.py @@ -8,6 +8,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on # 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. + from functools import lru_cache from typing import Type @@ -27,7 +28,7 @@ def _build_manager(cls) -> Type[_DataManager]: if EnterpriseEditionUtils._using_enterprise(): data_manager = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".data._data_manager", "_DataManager" - ) # type: ignore + ) build_repository = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".data._data_manager_factory", "_DataManagerFactory", diff --git a/taipy/core/job/_job_manager_factory.py b/taipy/core/job/_job_manager_factory.py index be2645bd7b..96f2407222 100644 --- a/taipy/core/job/_job_manager_factory.py +++ b/taipy/core/job/_job_manager_factory.py @@ -8,6 +8,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on # 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. + from functools import lru_cache from typing import Type @@ -27,7 +28,7 @@ def _build_manager(cls) -> Type[_JobManager]: if EnterpriseEditionUtils._using_enterprise(): job_manager = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".job._job_manager", "_JobManager" - ) # type: ignore + ) build_repository = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".job._job_manager_factory", "_JobManagerFactory" )._build_repository # type: ignore diff --git a/taipy/core/notification/__init__.py b/taipy/core/notification/__init__.py index c450a2f2e4..cead5789fb 100644 --- a/taipy/core/notification/__init__.py +++ b/taipy/core/notification/__init__.py @@ -26,6 +26,6 @@ from ._registration import _Registration from ._topic import _Topic from .core_event_consumer import CoreEventConsumerBase -from .event import _ENTITY_TO_EVENT_ENTITY_TYPE, Event, EventEntityType, EventOperation, _make_event +from .event import Event, EventEntityType, EventOperation, _make_event from .notifier import Notifier, _publish_event from .registration_id import RegistrationId diff --git a/taipy/core/notification/_topic.py b/taipy/core/notification/_topic.py index d5fd55ca65..be7901480b 100644 --- a/taipy/core/notification/_topic.py +++ b/taipy/core/notification/_topic.py @@ -12,7 +12,7 @@ from typing import Optional from ..exceptions.exceptions import InvalidEventOperation -from .event import _UNSUBMITTABLE_ENTITY_TYPES, EventEntityType, EventOperation +from .event import Event, EventEntityType, EventOperation class _Topic: @@ -35,7 +35,7 @@ def __preprocess_operation( if ( entity_type and operation - and entity_type in _UNSUBMITTABLE_ENTITY_TYPES + and entity_type in Event._UNSUBMITTABLE_ENTITY_TYPES and operation == EventOperation.SUBMISSION ): raise InvalidEventOperation diff --git a/taipy/core/notification/event.py b/taipy/core/notification/event.py index 845eb4c1b9..63eafca714 100644 --- a/taipy/core/notification/event.py +++ b/taipy/core/notification/event.py @@ -62,23 +62,20 @@ class EventEntityType(_ReprEnum): JOB = 6 SUBMISSION = 7 - -_NO_ATTRIBUTE_NAME_OPERATIONS = {EventOperation.CREATION, EventOperation.DELETION, EventOperation.SUBMISSION} -_UNSUBMITTABLE_ENTITY_TYPES = ( - EventEntityType.CYCLE, - EventEntityType.DATA_NODE, - EventEntityType.JOB, - EventEntityType.SUBMISSION, -) -_ENTITY_TO_EVENT_ENTITY_TYPE = { - "scenario": EventEntityType.SCENARIO, - "sequence": EventEntityType.SEQUENCE, - "task": EventEntityType.TASK, - "data": EventEntityType.DATA_NODE, - "job": EventEntityType.JOB, - "cycle": EventEntityType.CYCLE, - "submission": EventEntityType.SUBMISSION, -} + @classmethod + def add_member(cls, name, value): + # Check if the member already exists to prevent duplication + if name in cls._member_map_: + return + + # Create a new enum member + new_member = object.__new__(cls) + new_member._name_ = name + new_member._value_ = value + # Update the class dictionary and member maps + setattr(cls, name, new_member) + cls._member_map_[name] = new_member + cls._value2member_map_[value] = new_member @dataclass(frozen=True) @@ -88,6 +85,23 @@ class Event: An event holds the necessary attributes to identify the change. """ + _NO_ATTRIBUTE_NAME_OPERATIONS = {EventOperation.CREATION, EventOperation.DELETION, EventOperation.SUBMISSION} + _UNSUBMITTABLE_ENTITY_TYPES = { + EventEntityType.CYCLE, + EventEntityType.DATA_NODE, + EventEntityType.JOB, + EventEntityType.SUBMISSION, + } + _ENTITY_TO_EVENT_ENTITY_TYPE = { + "scenario": EventEntityType.SCENARIO, + "sequence": EventEntityType.SEQUENCE, + "task": EventEntityType.TASK, + "data": EventEntityType.DATA_NODE, + "job": EventEntityType.JOB, + "cycle": EventEntityType.CYCLE, + "submission": EventEntityType.SUBMISSION, + } + entity_type: EventEntityType """Type of the entity that was changed (`DataNode^`, `Scenario^`, `Cycle^`, etc. ).""" operation: EventOperation @@ -112,11 +126,11 @@ def __post_init__(self): super().__setattr__("creation_date", datetime.now()) # Check operation: - if self.entity_type in _UNSUBMITTABLE_ENTITY_TYPES and self.operation == EventOperation.SUBMISSION: + if self.entity_type in self._UNSUBMITTABLE_ENTITY_TYPES and self.operation == EventOperation.SUBMISSION: raise InvalidEventOperation # Check attribute name: - if self.operation in _NO_ATTRIBUTE_NAME_OPERATIONS and self.attribute_name is not None: + if self.operation in self._NO_ATTRIBUTE_NAME_OPERATIONS and self.attribute_name is not None: raise InvalidEventAttributeName diff --git a/taipy/core/scenario/_scenario_manager_factory.py b/taipy/core/scenario/_scenario_manager_factory.py index bb9630f907..6d0785221c 100644 --- a/taipy/core/scenario/_scenario_manager_factory.py +++ b/taipy/core/scenario/_scenario_manager_factory.py @@ -8,6 +8,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on # 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. + from functools import lru_cache from typing import Type @@ -27,7 +28,7 @@ def _build_manager(cls) -> Type[_ScenarioManager]: if EnterpriseEditionUtils._using_enterprise(): scenario_manager = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".scenario._scenario_manager", "_ScenarioManager" - ) # type: ignore + ) build_repository = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".scenario._scenario_manager_factory", "_ScenarioManagerFactory", diff --git a/taipy/core/sequence/_sequence_manager_factory.py b/taipy/core/sequence/_sequence_manager_factory.py index d2490a35e7..5d11e6a46b 100644 --- a/taipy/core/sequence/_sequence_manager_factory.py +++ b/taipy/core/sequence/_sequence_manager_factory.py @@ -8,6 +8,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on # 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. + from functools import lru_cache from typing import Type @@ -20,11 +21,11 @@ class _SequenceManagerFactory(_ManagerFactory): @classmethod @lru_cache - def _build_manager(cls) -> Type[_SequenceManager]: # type: ignore + def _build_manager(cls) -> Type[_SequenceManager]: if EnterpriseEditionUtils._using_enterprise(): sequence_manager = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".sequence._sequence_manager", "_SequenceManager" - ) # type: ignore + ) else: sequence_manager = _SequenceManager return sequence_manager # type: ignore diff --git a/taipy/core/submission/_submission_manager_factory.py b/taipy/core/submission/_submission_manager_factory.py index 4d0f2f84ee..8758a34e08 100644 --- a/taipy/core/submission/_submission_manager_factory.py +++ b/taipy/core/submission/_submission_manager_factory.py @@ -8,6 +8,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on # 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. + from functools import lru_cache from typing import Type @@ -28,7 +29,7 @@ def _build_manager(cls) -> Type[_SubmissionManager]: submission_manager = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".submission._submission_manager", "_SubmissionManager", - ) # type: ignore + ) build_repository = _load_fct( EnterpriseEditionUtils._TAIPY_ENTERPRISE_CORE_MODULE + ".submission._submission_manager_factory", "_SubmissionManagerFactory",