Преглед изворни кода

select the right types
fix the submission

Fred Lefévère-Laoide пре 1 година
родитељ
комит
8cff1175ea
3 измењених фајлова са 65 додато и 31 уклоњено
  1. 3 2
      taipy/gui/extension/library.py
  2. 1 0
      taipy/gui_core/_GuiCoreLib.py
  3. 61 29
      taipy/gui_core/_context.py

+ 3 - 2
taipy/gui/extension/library.py

@@ -39,7 +39,7 @@ class ElementProperty:
 
 
     def __init__(
     def __init__(
         self,
         self,
-        property_type: PropertyType,
+        property_type: t.Union[PropertyType, t.Type[_TaipyBase]],
         default_value: t.Optional[t.Any] = None,
         default_value: t.Optional[t.Any] = None,
         js_name: t.Optional[str] = None,
         js_name: t.Optional[str] = None,
     ) -> None:
     ) -> None:
@@ -54,6 +54,7 @@ class ElementProperty:
                 JavaScript code.
                 JavaScript code.
         """
         """
         self.default_value = default_value
         self.default_value = default_value
+        self.property_type: t.Union[PropertyType, t.Type[_TaipyBase]]
         if property_type == PropertyType.broadcast:
         if property_type == PropertyType.broadcast:
             if isinstance(default_value, str):
             if isinstance(default_value, str):
                 self.default_value = _get_broadcast_var_name(default_value)
                 self.default_value = _get_broadcast_var_name(default_value)
@@ -205,7 +206,7 @@ class Element:
             if default_attr is not None:
             if default_attr is not None:
                 elt_built.set_value_and_default(
                 elt_built.set_value_and_default(
                     var_name=default_name,
                     var_name=default_name,
-                    var_type=default_attr.property_type,
+                    var_type=t.cast(PropertyType, default_attr.property_type),
                     default_val=default_attr.default_value,
                     default_val=default_attr.default_value,
                     with_default=default_attr.property_type != PropertyType.data,
                     with_default=default_attr.property_type != PropertyType.data,
                 )
                 )

+ 1 - 0
taipy/gui_core/_GuiCoreLib.py

@@ -14,6 +14,7 @@ from datetime import datetime
 
 
 from taipy.gui import Gui, State
 from taipy.gui import Gui, State
 from taipy.gui.extension import Element, ElementLibrary, ElementProperty, PropertyType
 from taipy.gui.extension import Element, ElementLibrary, ElementProperty, PropertyType
+from taipy.gui.utils import _TaipyBase
 
 
 from ..version import _get_version
 from ..version import _get_version
 from ._adapters import _GuiCoreDatanodeAdapter, _GuiCoreScenarioAdapter, _GuiCoreScenarioDagAdapter
 from ._adapters import _GuiCoreDatanodeAdapter, _GuiCoreScenarioAdapter, _GuiCoreScenarioDagAdapter

+ 61 - 29
taipy/gui_core/_context.py

@@ -24,13 +24,26 @@ import pandas as pd
 from dateutil import parser
 from dateutil import parser
 
 
 from taipy.config import Config
 from taipy.config import Config
-from taipy.core import Cycle, DataNode, Job, Scenario, Sequence, cancel_job, create_scenario
+from taipy.core import (
+    Cycle,
+    DataNode,
+    DataNodeId,
+    Job,
+    JobId,
+    Scenario,
+    ScenarioId,
+    Sequence,
+    SequenceId,
+    cancel_job,
+    create_scenario,
+)
 from taipy.core import delete as core_delete
 from taipy.core import delete as core_delete
 from taipy.core import delete_job
 from taipy.core import delete_job
 from taipy.core import get as core_get
 from taipy.core import get as core_get
 from taipy.core import (
 from taipy.core import (
     get_cycles_scenarios,
     get_cycles_scenarios,
     get_data_nodes,
     get_data_nodes,
+    get_jobs,
     is_deletable,
     is_deletable,
     is_editable,
     is_editable,
     is_promotable,
     is_promotable,
@@ -44,6 +57,7 @@ from taipy.core.notification import CoreEventConsumerBase, EventEntityType
 from taipy.core.notification.event import Event, EventOperation
 from taipy.core.notification.event import Event, EventOperation
 from taipy.core.notification.notifier import Notifier
 from taipy.core.notification.notifier import Notifier
 from taipy.core.submission.submission import Submission
 from taipy.core.submission.submission import Submission
+from taipy.core.submission._submission_manager_factory import _SubmissionManagerFactory
 from taipy.core.submission.submission_status import SubmissionStatus
 from taipy.core.submission.submission_status import SubmissionStatus
 from taipy.gui import Gui, State
 from taipy.gui import Gui, State
 from taipy.gui._warnings import _warn
 from taipy.gui._warnings import _warn
@@ -111,17 +125,19 @@ class _GuiCoreContext(CoreEventConsumerBase):
     def process_event(self, event: Event):
     def process_event(self, event: Event):
         if event.entity_type == EventEntityType.SCENARIO:
         if event.entity_type == EventEntityType.SCENARIO:
             if event.operation == EventOperation.SUBMISSION:
             if event.operation == EventOperation.SUBMISSION:
-                self.scenario_status_callback(event.attribute_name, True)
+                self.scenario_status_callback(event.attribute_name)
                 return
                 return
             self.scenario_refresh(
             self.scenario_refresh(
-                event.entity_id if event.operation != EventOperation.DELETION and is_readable(event.entity_id) else None
+                event.entity_id
+                if event.operation != EventOperation.DELETION and is_readable(t.cast(ScenarioId, event.entity_id))
+                else None
             )
             )
         elif event.entity_type == EventEntityType.SEQUENCE and event.entity_id:
         elif event.entity_type == EventEntityType.SEQUENCE and event.entity_id:
             sequence = None
             sequence = None
             try:
             try:
                 sequence = (
                 sequence = (
                     core_get(event.entity_id)
                     core_get(event.entity_id)
-                    if event.operation != EventOperation.DELETION and is_readable(event.entity_id)
+                    if event.operation != EventOperation.DELETION and is_readable(t.cast(SequenceId, event.entity_id))
                     else None
                     else None
                 )
                 )
                 if sequence and hasattr(sequence, "parent_ids") and sequence.parent_ids:
                 if sequence and hasattr(sequence, "parent_ids") and sequence.parent_ids:
@@ -130,6 +146,9 @@ class _GuiCoreContext(CoreEventConsumerBase):
                     )
                     )
             except Exception as e:
             except Exception as e:
                 _warn(f"Access to sequence {event.entity_id} failed", e)
                 _warn(f"Access to sequence {event.entity_id} failed", e)
+        elif event.entity_type == EventEntityType.JOB:
+            with self.lock:
+                self.jobs_list = None
         elif event.entity_type == EventEntityType.SUBMISSION:
         elif event.entity_type == EventEntityType.SUBMISSION:
             self.scenario_status_callback(event.entity_id)
             self.scenario_status_callback(event.entity_id)
         elif event.entity_type == EventEntityType.DATA_NODE:
         elif event.entity_type == EventEntityType.DATA_NODE:
@@ -149,18 +168,16 @@ class _GuiCoreContext(CoreEventConsumerBase):
             {"scenario": scenario_id or True},
             {"scenario": scenario_id or True},
         )
         )
 
 
-    def scenario_status_callback(self, submission_id: str, is_submission: t.Optional[bool] = False):
-        if not submission_id or not (is_submission or is_readable(submission_id)):
+    def scenario_status_callback(self, submission_id: t.Optional[str]):
+        if not submission_id or not is_readable_submission(submission_id):
             return
             return
         try:
         try:
-            if is_submission:
-                sub_id = submission_id
-                submission = None
-            else:
-                submission: Submission = core_get(submission_id)
-            sub_details: t.Optional[_SubmissionDetails] = self.client_submission.get(sub_id)
+            sub_details: t.Optional[_SubmissionDetails] = self.client_submission.get(submission_id)
+            if not sub_details:
+                return
 
 
-            if not submission or not submission.entity_id or sub_details:
+            submission = core_get_submission(submission_id)
+            if not submission or not submission.entity_id:
                 return
                 return
 
 
             entity = core_get(submission.entity_id)
             entity = core_get(submission.entity_id)
@@ -182,12 +199,12 @@ class _GuiCoreContext(CoreEventConsumerBase):
                     SubmissionStatus.FAILED,
                     SubmissionStatus.FAILED,
                     SubmissionStatus.CANCELED,
                     SubmissionStatus.CANCELED,
                 ):
                 ):
-                    self.client_submission.pop(sub_id, None)
+                    self.client_submission.pop(submission_id, None)
                 else:
                 else:
-                    self.client_submission[sub_id] = sub_details.set_submission(new_status)
+                    self.client_submission[submission_id] = sub_details.set_submission(submission)
 
 
         except Exception as e:
         except Exception as e:
-            _warn(f"Job ({submission_id}) is not available", e)
+            _warn(f"Submission ({submission_id}) is not available", e)
 
 
         finally:
         finally:
             self.gui._broadcast(_GuiCoreContext._CORE_CHANGED_NAME, {"jobs": True})
             self.gui._broadcast(_GuiCoreContext._CORE_CHANGED_NAME, {"jobs": True})
@@ -243,10 +260,10 @@ class _GuiCoreContext(CoreEventConsumerBase):
         state.assign(_GuiCoreContext._SCENARIO_SELECTOR_ID_VAR, args[0])
         state.assign(_GuiCoreContext._SCENARIO_SELECTOR_ID_VAR, args[0])
 
 
     def get_scenario_by_id(self, id: str) -> t.Optional[Scenario]:
     def get_scenario_by_id(self, id: str) -> t.Optional[Scenario]:
-        if not id or not is_readable(id):
+        if not id or not is_readable(t.cast(ScenarioId, id)):
             return None
             return None
         try:
         try:
-            return core_get(id)
+            return core_get(t.cast(ScenarioId, id))
         except Exception:
         except Exception:
             return None
             return None
 
 
@@ -417,14 +434,14 @@ class _GuiCoreContext(CoreEventConsumerBase):
         if entity:
         if entity:
             try:
             try:
                 jobs = core_submit(entity)
                 jobs = core_submit(entity)
+                submission_entity = core_get_submission(jobs[0].submit_id if isinstance(jobs, list) else jobs.submit_id)
                 if submission_cb := data.get("on_submission_change"):
                 if submission_cb := data.get("on_submission_change"):
                     submission_fn = self.gui._get_user_function(submission_cb)
                     submission_fn = self.gui._get_user_function(submission_cb)
                     if callable(submission_fn):
                     if callable(submission_fn):
-                        submission_entity = core_get(jobs[0].submit_id if isinstance(jobs, list) else jobs.submit_id)
                         client_id = self.gui._get_client_id()
                         client_id = self.gui._get_client_id()
                         module_context = self.gui._get_locals_context()
                         module_context = self.gui._get_locals_context()
                         with self.submissions_lock:
                         with self.submissions_lock:
-                            self.client_submission[submission_entity.submit_entity_id] = _SubmissionDetails(
+                            self.client_submission[submission_entity.id] = _SubmissionDetails(
                                 client_id,
                                 client_id,
                                 module_context,
                                 module_context,
                                 submission_fn,
                                 submission_fn,
@@ -490,6 +507,12 @@ class _GuiCoreContext(CoreEventConsumerBase):
 
 
         return None
         return None
 
 
+    def get_jobs_list(self):
+        with self.lock:
+            if self.jobs_list is None:
+                self.jobs_list = get_jobs()
+            return self.jobs_list
+
     def job_adapter(self, job):
     def job_adapter(self, job):
         try:
         try:
             if hasattr(job, "id") and is_readable(job.id) and core_get(job.id) is not None:
             if hasattr(job, "id") and is_readable(job.id) and core_get(job.id) is not None:
@@ -617,10 +640,10 @@ class _GuiCoreContext(CoreEventConsumerBase):
                             cycles_scenarios.extend(scenarios)
                             cycles_scenarios.extend(scenarios)
                         else:
                         else:
                             cycles_scenarios.append(cycle)
                             cycles_scenarios.append(cycle)
-                elif is_readable(owner_id):
+                elif is_readable(t.cast(ScenarioId, owner_id)):
                     entity = core_get(owner_id)
                     entity = core_get(owner_id)
-                    if entity and (scenarios := self.scenario_by_cycle.get(entity)):
-                        cycles_scenarios.extend(scenarios)
+                    if entity and (scenarios_cycle := self.scenario_by_cycle.get(t.cast(Cycle, entity))):
+                        cycles_scenarios.extend(scenarios_cycle)
                     elif isinstance(entity, Scenario):
                     elif isinstance(entity, Scenario):
                         cycles_scenarios.append(entity)
                         cycles_scenarios.append(entity)
         return cycles_scenarios
         return cycles_scenarios
@@ -636,7 +659,7 @@ class _GuiCoreContext(CoreEventConsumerBase):
             res = []
             res = []
             for e in dn.edits:
             for e in dn.edits:
                 job_id = e.get("job_id")
                 job_id = e.get("job_id")
-                job: Job = None
+                job: t.Optional[Job] = None
                 if job_id:
                 if job_id:
                     if not is_readable(job_id):
                     if not is_readable(job_id):
                         job_id += " not readable"
                         job_id += " not readable"
@@ -685,10 +708,10 @@ class _GuiCoreContext(CoreEventConsumerBase):
         return _DoNotUpdate()
         return _DoNotUpdate()
 
 
     def __check_readable_editable(self, state: State, id: str, type: str, var: str):
     def __check_readable_editable(self, state: State, id: str, type: str, var: str):
-        if not is_readable(id):
+        if not is_readable(t.cast(DataNodeId, id)):
             state.assign(var, f"{type} {id} is not readable.")
             state.assign(var, f"{type} {id} is not readable.")
             return False
             return False
-        if not is_editable(id):
+        if not is_editable(t.cast(DataNodeId, id)):
             state.assign(var, f"{type} {id} is not editable.")
             state.assign(var, f"{type} {id} is not editable.")
             return False
             return False
         return True
         return True
@@ -759,7 +782,7 @@ class _GuiCoreContext(CoreEventConsumerBase):
             id
             id
             and isinstance(datanode, DataNode)
             and isinstance(datanode, DataNode)
             and id == datanode.id
             and id == datanode.id
-            and is_readable(id)
+            and is_readable(t.cast(DataNodeId, id))
             and (dn := core_get(id))
             and (dn := core_get(id))
             and isinstance(dn, DataNode)
             and isinstance(dn, DataNode)
             and dn.is_ready_for_reading
             and dn.is_ready_for_reading
@@ -775,7 +798,7 @@ class _GuiCoreContext(CoreEventConsumerBase):
             id
             id
             and isinstance(datanode, DataNode)
             and isinstance(datanode, DataNode)
             and id == datanode.id
             and id == datanode.id
-            and is_readable(id)
+            and is_readable(t.cast(DataNodeId, id))
             and (dn := core_get(id))
             and (dn := core_get(id))
             and isinstance(dn, DataNode)
             and isinstance(dn, DataNode)
             and dn.is_ready_for_reading
             and dn.is_ready_for_reading
@@ -793,7 +816,7 @@ class _GuiCoreContext(CoreEventConsumerBase):
             id
             id
             and isinstance(datanode, DataNode)
             and isinstance(datanode, DataNode)
             and id == datanode.id
             and id == datanode.id
-            and is_readable(id)
+            and is_readable(t.cast(DataNodeId, id))
             and (dn := core_get(id))
             and (dn := core_get(id))
             and isinstance(dn, DataNode)
             and isinstance(dn, DataNode)
             and dn.is_ready_for_reading
             and dn.is_ready_for_reading
@@ -819,3 +842,12 @@ class _GuiCoreContext(CoreEventConsumerBase):
             state.assign(_GuiCoreContext._DATANODE_VIZ_DATA_ID_VAR, data_id)
             state.assign(_GuiCoreContext._DATANODE_VIZ_DATA_ID_VAR, data_id)
         elif chart_id := data.get("chart_id"):
         elif chart_id := data.get("chart_id"):
             state.assign(_GuiCoreContext._DATANODE_VIZ_DATA_CHART_ID_VAR, chart_id)
             state.assign(_GuiCoreContext._DATANODE_VIZ_DATA_CHART_ID_VAR, chart_id)
+
+
+# TODO remove when Submission is supported by Core API
+def is_readable_submission(id: str):
+    return _SubmissionManagerFactory._build_manager()._is_readable(t.cast(Submission, id))
+
+
+def core_get_submission(id: str):
+    return _SubmissionManagerFactory._build_manager()._get(id)