Skip to content

Commit

Permalink
Fix - Add wait when stop dispatcher (#801)
Browse files Browse the repository at this point in the history
* fix: add wait when stop dispatcher to make sure the thread is fully terminated

* fix: remove unnecessary calls in tests

* fix: remove internal imports from the assert_true_after_time()

* fix: stop the dispatcher in the core conftest
  • Loading branch information
trgiangdo authored Feb 20, 2024
1 parent 16dfc8c commit 07a0fbc
Show file tree
Hide file tree
Showing 23 changed files with 70 additions and 371 deletions.
9 changes: 6 additions & 3 deletions taipy/core/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,19 @@ def run(self, force_restart=False):

self.__start_dispatcher(force_restart)

def stop(self):
def stop(self, wait: bool = True, timeout: Optional[float] = None):
"""
Stop the Core service.
This function stops the dispatcher and unblock the Config for update.
Parameters:
wait (bool): If True, the method will wait for the dispatcher to stop.
timeout (Optional[float]): The maximum time to wait. If None, the method will wait indefinitely.
"""
Config.unblock_update()

if self._dispatcher:
self._dispatcher = _OrchestratorFactory._remove_dispatcher()
self._dispatcher = _OrchestratorFactory._remove_dispatcher(wait, timeout)
self.__logger.info("Core service has been stopped.")

with self.__class__.__lock_is_running:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
# 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 typing import Optional

from ...job.job import Job
from .._abstract_orchestrator import _AbstractOrchestrator
from ._job_dispatcher import _JobDispatcher
Expand All @@ -26,7 +29,7 @@ def start(self):
def is_running(self) -> bool:
return True

def stop(self):
def stop(self, wait: bool = True, timeout: Optional[float] = None):
raise NotImplementedError

def run(self):
Expand Down
18 changes: 13 additions & 5 deletions taipy/core/_orchestrator/_dispatcher/_job_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import threading
from abc import abstractmethod
from queue import Empty
from typing import Dict
from typing import Dict, Optional

from taipy.config.config import Config
from taipy.logger._taipy_logger import _TaipyLogger
Expand Down Expand Up @@ -47,12 +47,20 @@ def is_running(self) -> bool:
"""Return True if the dispatcher is running"""
return self.is_alive()

def stop(self):
"""Stop the dispatcher"""
def stop(self, wait: bool = True, timeout: Optional[float] = None):
"""Stop the dispatcher.
Parameters:
wait (bool): If True, the method will wait for the dispatcher to stop.
timeout (Optional[float]): The maximum time to wait. If None, the method will wait indefinitely.
"""
self._STOP_FLAG = True
if wait and self.is_alive():
self._logger.debug("Waiting for the dispatcher thread to stop...")
self.join(timeout=timeout)

def run(self):
_TaipyLogger._get_logger().info("Start job dispatcher...")
self._logger.info("Start job dispatcher...")
while not self._STOP_FLAG:
try:
if self._can_execute():
Expand All @@ -64,7 +72,7 @@ def run(self):
except Empty: # In case the last job of the queue has been removed.
pass
except Exception as e:
_TaipyLogger._get_logger().exception(e)
self._logger.exception(e)
pass
self._logger.info("Job dispatcher stopped.")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 concurrent.futures import Executor, ProcessPoolExecutor
from functools import partial
from typing import Callable, Optional
Expand All @@ -29,7 +30,7 @@ def __init__(self, orchestrator: _AbstractOrchestrator, subproc_initializer: Opt
max_workers = Config.job_config.max_nb_of_workers or 1
self._executor: Executor = ProcessPoolExecutor(
max_workers=max_workers,
initializer=subproc_initializer
initializer=subproc_initializer,
) # type: ignore
self._nb_available_workers = self._executor._max_workers # type: ignore

Expand Down
4 changes: 2 additions & 2 deletions taipy/core/_orchestrator/_orchestrator_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ def _build_dispatcher(cls, force_restart=False) -> Optional[_JobDispatcher]:
return cls._dispatcher

@classmethod
def _remove_dispatcher(cls) -> Optional[_JobDispatcher]:
def _remove_dispatcher(cls, wait: bool = True, timeout: Optional[float] = None) -> None:
if cls._dispatcher is not None and not isinstance(cls._dispatcher, _DevelopmentJobDispatcher):
cls._dispatcher.stop()
cls._dispatcher.stop(wait, timeout)
cls._dispatcher = None
return cls._dispatcher

Expand Down
10 changes: 5 additions & 5 deletions tests/core/_orchestrator/test_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_submit_task_multithreading_multiple_task():
task_1 = _create_task(partial(lock_multiply, lock_1))
task_2 = _create_task(partial(lock_multiply, lock_2))

_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)

with lock_1:
with lock_2:
Expand Down Expand Up @@ -104,7 +104,7 @@ def test_submit_submittable_multithreading_multiple_task():

scenario = Scenario("scenario_config", [task_1, task_2], {})

_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)

with lock_1:
with lock_2:
Expand Down Expand Up @@ -146,7 +146,7 @@ def test_submit_task_multithreading_multiple_task_in_sync_way_to_check_job_statu
task_1 = _create_task(partial(lock_multiply, lock_1))
task_2 = _create_task(partial(lock_multiply, lock_2))

_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)

with lock_0:
submission_0 = _Orchestrator.submit_task(task_0)
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_blocked_task():
bar_cfg = Config.configure_data_node("bar")
baz_cfg = Config.configure_data_node("baz")

_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)

dns = _DataManager._bulk_get_or_create([foo_cfg, bar_cfg, baz_cfg])
foo = dns[foo_cfg]
Expand Down Expand Up @@ -273,7 +273,7 @@ def test_blocked_submittable():
bar_cfg = Config.configure_data_node("bar")
baz_cfg = Config.configure_data_node("baz")

_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)

dns = _DataManager._bulk_get_or_create([foo_cfg, bar_cfg, baz_cfg])
foo = dns[foo_cfg]
Expand Down
9 changes: 6 additions & 3 deletions tests/core/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
from taipy.core.task.task import Task

current_time = datetime.now()
_OrchestratorFactory._build_orchestrator()


@pytest.fixture(scope="function")
Expand Down Expand Up @@ -369,9 +368,11 @@ def _init_managers():
@pytest.fixture
def init_orchestrator():
def _init_orchestrator():
_OrchestratorFactory._remove_dispatcher()

if _OrchestratorFactory._orchestrator is None:
_OrchestratorFactory._build_orchestrator()
_OrchestratorFactory._build_dispatcher()
_OrchestratorFactory._build_dispatcher(force_restart=True)
_OrchestratorFactory._orchestrator.jobs_to_run = Queue()
_OrchestratorFactory._orchestrator.blocked_jobs = []

Expand All @@ -392,7 +393,7 @@ def sql_engine():


@pytest.fixture
def init_sql_repo(tmp_sqlite):
def init_sql_repo(tmp_sqlite, init_managers):
Config.configure_core(repository_type="sql", repository_properties={"db_location": tmp_sqlite})

# Clean SQLite database
Expand All @@ -401,4 +402,6 @@ def init_sql_repo(tmp_sqlite):
_SQLConnection._connection = None
_SQLConnection.init_db()

init_managers()

return tmp_sqlite
6 changes: 0 additions & 6 deletions tests/core/cycle/test_cycle_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
from taipy.config.common.frequency import Frequency
from taipy.config.common.scope import Scope
from taipy.config.config import Config
from taipy.core._orchestrator._orchestrator_factory import _OrchestratorFactory
from taipy.core.config.job_config import JobConfig
from taipy.core.cycle._cycle_manager import _CycleManager
from taipy.core.cycle.cycle import Cycle
from taipy.core.cycle.cycle_id import CycleId
Expand Down Expand Up @@ -190,8 +188,6 @@ def test_get_cycle_start_date_and_end_date():


def test_hard_delete_shared_entities():
Config.configure_job_executions(mode=JobConfig._DEVELOPMENT_MODE)

dn_config_1 = Config.configure_data_node("my_input_1", "pickle", scope=Scope.SCENARIO, default_data="testing")
dn_config_2 = Config.configure_data_node("my_input_2", "pickle", scope=Scope.SCENARIO, default_data="testing")
dn_config_3 = Config.configure_data_node("my_input_3", "pickle", scope=Scope.CYCLE, default_data="testing")
Expand Down Expand Up @@ -219,8 +215,6 @@ def test_hard_delete_shared_entities():
scenario_config_2 = Config.configure_scenario("scenario_config_2", [task_config_2, task_config_3])
scenario_config_2.add_sequences({"sequence_3": [task_config_3]})

_OrchestratorFactory._build_dispatcher()

scenario_1 = _ScenarioManager._create(scenario_config_1)
scenario_2 = _ScenarioManager._create(scenario_config_1)
scenario_3 = _ScenarioManager._create(scenario_config_2)
Expand Down
5 changes: 0 additions & 5 deletions tests/core/cycle/test_cycle_manager_with_sql_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
from taipy.config.common.frequency import Frequency
from taipy.config.common.scope import Scope
from taipy.config.config import Config
from taipy.core._orchestrator._orchestrator_factory import _OrchestratorFactory
from taipy.core.config.job_config import JobConfig
from taipy.core.cycle._cycle_manager import _CycleManager
from taipy.core.cycle._cycle_manager_factory import _CycleManagerFactory
from taipy.core.cycle.cycle import Cycle
Expand Down Expand Up @@ -199,7 +197,6 @@ def test_get_cycle_start_date_and_end_date(init_sql_repo):


def test_hard_delete_shared_entities(init_sql_repo):
Config.configure_job_executions(mode=JobConfig._DEVELOPMENT_MODE)
_ScenarioManager._repository = _ScenarioManagerFactory._build_repository()

dn_config_1 = Config.configure_data_node("my_input_1", "in_memory", scope=Scope.SCENARIO, default_data="testing")
Expand Down Expand Up @@ -228,8 +225,6 @@ def test_hard_delete_shared_entities(init_sql_repo):
) # No Frequency so cycle attached to scenarios
scenario_config_2.add_sequences({"sequence_3": [task_config_3]})

_OrchestratorFactory._build_dispatcher()

scenario_1 = _ScenarioManager._create(scenario_config_1)
scenario_2 = _ScenarioManager._create(scenario_config_1)
scenario_3 = _ScenarioManager._create(scenario_config_2)
Expand Down
28 changes: 0 additions & 28 deletions tests/core/data/test_data_manager_with_sql_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from taipy.core._version._version_manager import _VersionManager
from taipy.core.config.data_node_config import DataNodeConfig
from taipy.core.data._data_manager import _DataManager
from taipy.core.data._data_manager_factory import _DataManagerFactory
from taipy.core.data.csv import CSVDataNode
from taipy.core.data.data_node_id import DataNodeId
from taipy.core.data.in_memory import InMemoryDataNode
Expand All @@ -30,14 +29,8 @@ def file_exists(file_path: str) -> bool:
return os.path.exists(file_path)


def init_managers():
_DataManagerFactory._build_manager()._delete_all()


class TestDataManager:
def test_create_data_node_and_modify_properties_does_not_modify_config(self, init_sql_repo):
init_managers()

dn_config = Config.configure_data_node(id="name", foo="bar")
dn = _DataManager._create_and_set(dn_config, None, None)
assert dn_config.properties.get("foo") == "bar"
Expand All @@ -51,23 +44,17 @@ def test_create_data_node_and_modify_properties_does_not_modify_config(self, ini
assert dn.properties.get("baz") == "qux"

def test_create_raises_exception_with_wrong_type(self, init_sql_repo):
init_managers()

wrong_type_dn_config = DataNodeConfig(id="foo", storage_type="bar", scope=DataNodeConfig._DEFAULT_SCOPE)
with pytest.raises(InvalidDataNodeType):
_DataManager._create_and_set(wrong_type_dn_config, None, None)

def test_create_from_same_config_generates_new_data_node_and_new_id(self, init_sql_repo):
init_managers()

dn_config = Config.configure_data_node(id="foo", storage_type="in_memory")
dn = _DataManager._create_and_set(dn_config, None, None)
dn_2 = _DataManager._create_and_set(dn_config, None, None)
assert dn_2.id != dn.id

def test_create_uses_overridden_attributes_in_config_file(self, init_sql_repo):
init_managers()

Config.override(os.path.join(pathlib.Path(__file__).parent.resolve(), "data_sample/config.toml"))

csv_dn_cfg = Config.configure_data_node(id="foo", storage_type="csv", path="bar", has_header=True)
Expand All @@ -85,14 +72,10 @@ def test_create_uses_overridden_attributes_in_config_file(self, init_sql_repo):
assert csv_dn.has_header

def test_get_if_not_exists(self, init_sql_repo):
init_managers()

with pytest.raises(ModelNotFound):
_DataManager._repository._load("test_data_node_2")

def test_get_all(self, init_sql_repo):
init_managers()

_DataManager._delete_all()
assert len(_DataManager._get_all()) == 0
dn_config_1 = Config.configure_data_node(id="foo", storage_type="in_memory")
Expand All @@ -106,8 +89,6 @@ def test_get_all(self, init_sql_repo):
assert len([dn for dn in _DataManager._get_all() if dn.config_id == "baz"]) == 2

def test_get_all_on_multiple_versions_environment(self, init_sql_repo):
init_managers()

# Create 5 data nodes with 2 versions each
# Only version 1.0 has the data node with config_id = "config_id_1"
# Only version 2.0 has the data node with config_id = "config_id_6"
Expand Down Expand Up @@ -143,8 +124,6 @@ def test_get_all_on_multiple_versions_environment(self, init_sql_repo):
assert len(_DataManager._get_all_by(filters=[{"version": "2.0", "config_id": "config_id_6"}])) == 1

def test_set(self, init_sql_repo):
init_managers()

dn = InMemoryDataNode(
"config_id",
Scope.SCENARIO,
Expand All @@ -171,7 +150,6 @@ def test_set(self, init_sql_repo):
assert _DataManager._get(dn.id).config_id == "foo"

def test_delete(self, init_sql_repo):
init_managers()
_DataManager._delete_all()

dn_1 = InMemoryDataNode("config_id", Scope.SCENARIO, id="id_1")
Expand All @@ -198,8 +176,6 @@ def test_get_or_create(self, init_sql_repo):
def _get_or_create_dn(config, *args):
return _DataManager._bulk_get_or_create([config], *args)[config]

init_managers()

global_dn_config = Config.configure_data_node(
id="test_data_node", storage_type="in_memory", scope=Scope.GLOBAL, data="In memory Data Node"
)
Expand Down Expand Up @@ -259,8 +235,6 @@ def _get_or_create_dn(config, *args):
assert cycle_dn_4.id == cycle_dn_5.id

def test_get_data_nodes_by_config_id(self, init_sql_repo):
init_managers()

dn_config_1 = Config.configure_data_node("dn_1", scope=Scope.SCENARIO)
dn_config_2 = Config.configure_data_node("dn_2", scope=Scope.SCENARIO)
dn_config_3 = Config.configure_data_node("dn_3", scope=Scope.SCENARIO)
Expand Down Expand Up @@ -290,8 +264,6 @@ def test_get_data_nodes_by_config_id(self, init_sql_repo):
assert sorted([dn_3_1.id]) == sorted([sequence.id for sequence in dn_3_datanodes])

def test_get_data_nodes_by_config_id_in_multiple_versions_environment(self, init_sql_repo):
init_managers()

dn_config_1 = Config.configure_data_node("dn_1", scope=Scope.SCENARIO)
dn_config_2 = Config.configure_data_node("dn_2", scope=Scope.SCENARIO)

Expand Down
6 changes: 0 additions & 6 deletions tests/core/data/test_data_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
from taipy.config import Config
from taipy.config.common.scope import Scope
from taipy.config.exceptions.exceptions import InvalidConfigurationId
from taipy.core._orchestrator._orchestrator_factory import _OrchestratorFactory
from taipy.core.config.job_config import JobConfig
from taipy.core.data._data_manager import _DataManager
from taipy.core.data.data_node import DataNode
from taipy.core.data.data_node_id import DataNodeId
Expand Down Expand Up @@ -355,8 +353,6 @@ def test_is_up_to_date_across_scenarios(self, current_datetime):
assert not dn_3.is_up_to_date

def test_do_not_recompute_data_node_valid_but_continue_sequence_execution(self):
Config.configure_job_executions(mode=JobConfig._DEVELOPMENT_MODE)

a = Config.configure_data_node("A", "pickle", default_data="A")
b = Config.configure_data_node("B", "pickle")
c = Config.configure_data_node("C", "pickle")
Expand All @@ -367,8 +363,6 @@ def test_do_not_recompute_data_node_valid_but_continue_sequence_execution(self):
task_b_d = Config.configure_task("task_b_d", funct_b_d, input=b, output=d)
scenario_cfg = Config.configure_scenario("scenario", [task_a_b, task_b_c, task_b_d])

_OrchestratorFactory._build_dispatcher()

scenario = tp.create_scenario(scenario_cfg)
scenario.submit()
assert scenario.A.read() == "A"
Expand Down
Loading

1 comment on commit 07a0fbc

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Taipy Overall Coverage Report
FileStmtsMissCoverMissing
__init__.py16193%31
_entrypoint.py36488%44, 46, 50–51
_run.py38294%77–78
version.py90100% 
_cli
   __init__.py00100% 
   _help_cli.py190100% 
   _run_cli.py251156%40, 42–46, 48–49, 51, 53, 59
   _scaffold_cli.py18288%41–42
_cli/_base_cli
   __init__.py10100% 
   _cli.py410100% 
config
   __init__.py38976%41–42, 44–49, 70
   _config.py60198%68
   _init.py30100% 
   config.py145497%87, 154, 178, 233
   section.py42685%35, 40, 44, 48, 53, 57
   setup.py15150%14–16, 18, 20–21, 23, 25–29, 31, 33, 35
   unique_section.py50100% 
   version.py90100% 
config/_config_comparator
   __init__.py00100% 
   _comparator_result.py95396%67, 110–111
   _config_comparator.py680100% 
config/_serializer
   __init__.py00100% 
   _base_serializer.py124595%39, 141–142, 144–145
   _json_serializer.py24387%33–35
   _toml_serializer.py230100% 
config/checker
   __init__.py00100% 
   _checker.py140100% 
   issue.py150100% 
   issue_collector.py280100% 
config/checker/_checkers
   __init__.py00100% 
   _auth_config_checker.py25250%12–14, 17–19, 21–24, 26–30, 32–34, 39–40, 47–49, 54–55
   _config_checker.py30196%28
config/common
   __init__.py00100% 
   _classproperty.py50100% 
   _config_blocker.py240100% 
   _repr_enum.py70100% 
   _template_handler.py1111190%39, 53, 55, 59, 61, 63, 99–100, 118, 149–150
   _validate_id.py100100% 
   frequency.py70100% 
   scope.py220100% 
   typing.py30100% 
config/exceptions
   __init__.py10100% 
   exceptions.py50100% 
config/global_app
   __init__.py00100% 
   global_app_config.py32196%38
core
   __init__.py70100% 
   _core.py560100% 
   _core_cli.py460100% 
   _init.py180100% 
   _init_version.py100100% 
   setup.py16160%14–16, 18, 20–21, 23–28, 30, 39, 41, 50
   taipy.py3904588%163, 219, 262, 267, 272, 277, 282, 287, 292, 297, 302, 340–342, 347, 352, 357, 362, 367, 372, 377, 382, 422, 461, 490–491, 498–504, 530–533, 941, 980, 996, 1045–1049
core/_backup
   __init__.py00100% 
   _backup.py33293%54–55
core/_entity
   __init__.py00100% 
   _dag.py65198%94
   _entity.py220100% 
   _entity_ids.py220100% 
   _labeled.py480100% 
   _migrate_cli.py74494%98–99, 117–118
   _properties.py350100% 
   _reload.py62198%72
   submittable.py75494%47, 102, 106, 110
core/_entity/_migrate
   __init__.py30100% 
   _migrate_fs.py66592%43, 68, 104–106
   _migrate_mongo.py76593%52, 71, 87, 105, 127
   _migrate_sql.py1065350%30–31, 33–36, 38–46, 53, 57, 64–65, 69, 76–77, 81, 89–90, 94, 100–101, 105, 110–111, 115, 120–121, 125, 127–137, 139–140, 154, 198–199, 201–202
   _utils.py1993084%32, 34–36, 38, 59–61, 63–67, 69–71, 73–74, 157, 160, 169, 197–199, 202–204, 241–242, 316
core/_manager
   __init__.py00100% 
   _manager.py81198%113
   _manager_factory.py21290%28, 32
core/_orchestrator
   __init__.py00100% 
   _abstract_orchestrator.py23482%27, 40, 53, 58
   _orchestrator.py1891492%146, 190–191, 193–199, 201–203, 291
   _orchestrator_factory.py641182%38, 58, 73–74, 76, 79, 89, 94, 97–98, 100
core/_orchestrator/_dispatcher
   __init__.py30100% 
   _development_job_dispatcher.py19478%27, 30, 33, 36
   _job_dispatcher.py94891%69, 74–76, 99–100, 117, 135
   _standalone_job_dispatcher.py310100% 
   _task_function_wrapper.py57394%75–76, 84
core/_repository
   __init__.py00100% 
   _abstract_converter.py10280%19, 24
   _abstract_repository.py361072%29, 41, 53, 63, 73, 80, 90, 101, 113, 124
   _base_taipy_model.py31487%27–28, 50, 53
   _decoder.py21290%36, 51
   _encoder.py19384%30, 36, 41
   _filesystem_repository.py1592186%147, 173–174, 176, 178–181, 190–193, 197–200, 224, 237–238, 257–258
   _sql_repository.py1311687%79–80, 123, 137, 143–144, 147–148, 153–157, 163, 180, 216
core/_repository/db
   __init__.py00100% 
   _sql_base_model.py30100% 
   _sql_connection.py46295%82–83
core/_version
   __init__.py00100% 
   _utils.py260100% 
   _version.py140100% 
   _version_converter.py140100% 
   _version_fs_repository.py68592%44–45, 100–101, 134
   _version_manager.py149894%98, 104, 148–149, 171, 212, 220, 230
   _version_manager_factory.py19289%26, 29
   _version_mixin.py190100% 
   _version_model.py210100% 
   _version_repository_interface.py26773%22, 26, 30, 34, 38, 42, 46
   _version_sql_repository.py530100% 
core/_version/_cli
   __init__.py00100% 
   _bcolor.py241058%21, 23–25, 27–31, 33
   _version_cli.py138497%81, 85, 193, 195
core/common
   __init__.py10100% 
   _check_dependencies.py5180%28
   _check_instance.py230100% 
   _listattributes.py29389%21–22, 32
   _mongo_connector.py17288%37, 45
   _repr_enum.py70100% 
   _utils.py390100% 
   _warnings.py210100% 
   mongo_default_document.py50100% 
   typing.py70100% 
   warn_if_inputs_not_ready.py140100% 
core/config
   __init__.py300100% 
   core_section.py197597%139, 148, 157, 166, 179
   data_node_config.py350798%287, 291, 637, 639, 643, 645, 1044
   job_config.py73395%125–127
   migration_config.py46197%57
   scenario_config.py149497%211, 215, 223, 227
   task_config.py97792%70–71, 149, 152, 220–222
core/config/checkers
   __init__.py00100% 
   _config_id_checker.py180100% 
   _core_section_checker.py180100% 
   _data_node_config_checker.py91297%112, 147
   _job_config_checker.py190100% 
   _migration_config_checker.py300100% 
   _scenario_config_checker.py610100% 
   _task_config_checker.py340100% 
core/cycle
   __init__.py00100% 
   _cycle_converter.py110100% 
   _cycle_fs_repository.py60100% 
   _cycle_manager.py1010100% 
   _cycle_manager_factory.py20290%28, 31
   _cycle_model.py230100% 
   _cycle_sql_repository.py60100% 
   cycle.py109298%81, 147
   cycle_id.py30100% 
core/data
   __init__.py130100% 
   _abstract_file.py170100% 
   _abstract_sql.py1833083%95, 143, 145, 149, 162–163, 166–167, 179, 185, 187, 189, 195, 202, 235, 254–261, 268, 274, 290, 299–301, 307
   _abstract_tabular.py45197%40
   _data_converter.py175597%114, 183, 225, 258, 267
   _data_fs_repository.py60100% 
   _data_manager.py117298%93, 179
   _data_manager_factory.py20290%28, 31
   _data_model.py320100% 
   _data_sql_repository.py60100% 
   _filter.py1931791%41, 63, 83–91, 143, 183, 190, 205, 213, 222
   aws_s3.py40295%103, 106
   csv.py109397%91, 205, 209
   data_node.py293797%158, 226, 278, 287, 464, 467, 471
   data_node_id.py50100% 
   excel.py2022886%95, 279, 282, 284–288, 292–293, 296, 298–300, 302, 304–305, 307, 312, 314–315, 317–320, 322, 343, 365
   generic.py48197%83
   in_memory.py280100% 
   json.py115595%91, 170, 174, 179, 183
   mongo.py1131289%207–214, 222, 232, 237, 289
   operator.py110100% 
   parquet.py114397%107, 122, 230
   pickle.py630100% 
   sql.py44197%100
   sql_table.py660100% 
core/exceptions
   __init__.py10100% 
   exceptions.py118595%183, 191, 229, 267, 309
core/job
   __init__.py00100% 
   _job_converter.py31293%59–60
   _job_fs_repository.py60100% 
   _job_manager.py570100% 
   _job_manager_factory.py20290%28, 31
   _job_model.py260100% 
   _job_sql_repository.py60100% 
   job.py187597%30, 77, 149, 295, 336
   job_id.py30100% 
   status.py110100% 
core/notification
   __init__.py70100% 
   _registration.py180100% 
   _topic.py23195%65
   core_event_consumer.py26196%84
   event.py40197%139
   notifier.py470100% 
   registration_id.py30100% 
core/scenario
   __init__.py00100% 
   _scenario_converter.py320100% 
   _scenario_fs_repository.py60100% 
   _scenario_manager.py273996%88–91, 183, 188, 384, 429, 440
   _scenario_manager_factory.py20290%28, 31
   _scenario_model.py300100% 
   _scenario_sql_repository.py60100% 
   scenario.py3191495%129, 132, 134–135, 177, 224, 243, 324, 366, 409, 601, 603, 659, 665
   scenario_id.py30100% 
core/sequence
   __init__.py00100% 
   _sequence_converter.py190100% 
   _sequence_manager.py2381294%227, 241, 243, 246, 251, 257, 283–286, 353, 371
   _sequence_manager_factory.py11190%23
   sequence.py144397%81, 160, 172
   sequence_id.py30100% 
core/submission
   __init__.py00100% 
   _submission_converter.py200100% 
   _submission_fs_repository.py60100% 
   _submission_manager.py600100% 
   _submission_manager_factory.py20290%28, 31
   _submission_model.py310100% 
   _submission_sql_repository.py60100% 
   submission.py171795%111, 119, 140, 186, 189, 195, 248
   submission_id.py30100% 
   submission_status.py100100% 
core/task
   __init__.py00100% 
   _task_converter.py28196%68
   _task_fs_repository.py60100% 
   _task_manager.py121595%153–154, 159–160, 200
   _task_manager_factory.py20290%28, 31
   _task_model.py250100% 
   _task_sql_repository.py60100% 
   task.py107595%91, 96, 167–169
   task_id.py30100% 
gui
   __init__.py150100% 
   _default_config.py30100% 
   _gui_cli.py370100% 
   _gui_section.py300100% 
   _init.py10100% 
   _page.py32293%20–21
   _warnings.py110100% 
   config.py1101685%175, 177, 179–180, 184, 193, 201, 203, 207, 209, 211, 275–276, 281–282, 323
   gui.py124123481%41, 362, 364, 410–416, 419–426, 428–429, 431, 433–434, 436–438, 440–441, 443, 445–447, 449–452, 454–455, 457–462, 516, 527, 529, 531, 551, 574, 576, 589–590, 596–597, 618–621, 635, 639, 651, 665, 670, 677–678, 702–704, 714, 743, 752, 772, 789–790, 794–800, 802–807, 840–841, 855, 864, 952, 954, 959–960, 963, 966–967, 969, 971, 975, 977–978, 983, 985, 990, 996–1003, 1005, 1007, 1020–1024, 1026–1029, 1043–1045, 1052, 1054–1055, 1058, 1067, 1069–1071, 1079–1087, 1092, 1124–1126, 1193–1194, 1259, 1261, 1266, 1275–1276, 1287, 1297, 1303, 1331, 1333–1334, 1387, 1477–1479, 1489, 1498–1506, 1530, 1536, 1692–1695, 1741, 1743, 1794, 1810, 1824–1826, 1828, 1831–1832, 1844, 1849–1851, 1853, 1911, 1925–1926, 1955, 1960, 1972–1975, 1981, 1993–1998, 2018, 2025–2027, 2042, 2055, 2067, 2079, 2081, 2085–2086, 2094–2096, 2110, 2226, 2358, 2371, 2381, 2385
   gui_actions.py962771%61, 101, 133, 148, 174, 196–199, 220, 234, 238–239, 261–263, 289, 312–314, 318–319, 371, 380, 382, 387, 393
   gui_types.py91693%147, 152, 157, 164, 175, 177
   icon.py231630%58–63, 66–75
   page.py511864%21, 46, 48, 50, 55–57, 62–67, 98, 109, 112–114
   partial.py27388%21, 66, 73
   server.py1743778%43, 68, 92, 110, 156–162, 164–165, 178–179, 188, 191, 198, 209, 260, 262–263, 286, 295, 297, 302–303, 310–311, 313–315, 325, 327, 329, 332–333
   setup.py26260%14, 16–18, 20–21, 23, 25–30, 32, 51, 53, 63–67, 70–73, 76
   state.py1081883%24, 128, 140, 154, 180, 195, 210–212, 222–223, 235–238, 241–242, 245
gui/_renderers
   __init__.py731086%21–22, 40, 49, 60, 85–87, 91, 98
   builder.py66411382%45, 123, 142–143, 159–161, 163, 176, 203, 235–236, 240, 258–259, 263, 278, 296, 301–302, 306, 317, 334–337, 346, 349–351, 364, 377, 379–380, 383, 387–390, 392, 399, 441, 453, 499–502, 504–508, 510–513, 515–519, 529, 549, 566, 573, 578, 593, 600, 603–604, 606, 609, 613, 628, 635, 661, 673, 675–679, 682–683, 707, 710, 712, 798, 801, 824–825, 829, 861, 866–869, 871–874, 880–881, 891, 944, 961, 966, 973–977, 1000
   factory.py78396%20–21, 578
   json.py30873%26, 33–39
   utils.py66887%38–39, 54, 66–67, 78–79, 90
gui/_renderers/_html
   __init__.py10100% 
   factory.py9188%22
   parser.py981386%41–42, 52–53, 63, 70, 74, 82–83, 108–109, 121, 134
gui/_renderers/_markdown
   __init__.py18194%30
   blocproc.py35488%48–49, 67–68
   control.py110100% 
   factory.py140100% 
   postproc.py190100% 
   preproc.py122695%23, 103, 132, 136, 140, 199
gui/builder
   __init__.py40100% 
   _api_generator.py59689%25, 43, 45, 51, 70, 73
   _context_manager.py13192%17
   _element.py951089%24, 49–50, 65, 73, 78, 160, 171, 189, 192
   _factory.py9188%22
   page.py30970%57, 61–66, 70, 72
gui/custom
   __init__.py10100% 
   _page.py301260%28–32, 45, 48, 52, 63, 70, 79, 86
gui/data
   __init__.py30100% 
   array_dict_data_accessor.py40685%47–48, 50–51, 59, 66
   content_accessor.py961881%51, 58–60, 64, 66, 73, 85–86, 91–92, 109–110, 124–126, 128, 131
   data_accessor.py721579%27, 33, 37, 43, 48, 51, 72, 74, 77, 83, 87–88, 97–99
   data_format.py40100% 
   data_scope.py37294%61–62
   numpy_data_accessor.py21766%30, 33–35, 40–42
   pandas_data_accessor.py2406572%81, 83–92, 94, 96–103, 109, 117, 149–151, 156–159, 182, 204, 207–212, 231, 262–263, 279–280, 283, 292–294, 300–301, 311, 317–319, 353–357, 359, 364–365, 374–376, 406, 409
   utils.py592852%22, 53–54, 57–59, 82, 98, 118–119, 121–125, 127–133, 136, 138, 141–144
gui/data/decimator
   __init__.py40100% 
   lttb.py38294%53, 56
   minmax.py25196%45
   rdp.py64592%85, 112–114, 140
   scatter_decimator.py501374%62–63, 77–83, 87–90
gui/extension
   __init__.py20100% 
   library.py1391887%27–28, 62, 71, 75, 81, 132, 141, 143, 176, 240, 270, 343, 349, 351, 364, 412, 422
gui/utils
   __init__.py220100% 
   _adapter.py1175453%39–40, 44–45, 48–55, 58–70, 82, 87, 92, 98–100, 103–108, 116, 126–133, 141–145, 149, 151, 153
   _attributes.py30776%16, 31–32, 39–40, 56–57
   _bindings.py50198%20
   _evaluator.py2284281%22, 124–126, 149, 151, 161, 169–170, 199–201, 244–248, 250–260, 270, 290–293, 295–298, 301, 313, 326–327, 338
   _locals_context.py48295%54, 60
   _map_dict.py66592%34, 55, 70–71, 73
   _runtime_manager.py13284%17, 30
   _variable_directory.py100892%47–50, 61, 72, 84, 88
   boolean.py9188%27
   chart_config_builder.py1381291%23, 91–92, 107, 154–155, 195, 198–200, 266, 268
   clientvarname.py14285%23, 26
   datatype.py11372%20, 22, 24
   date.py17382%27, 30–31
   expr_var_name.py13192%23
   filename.py120100% 
   filter_locals.py50100% 
   get_imported_var.py110100% 
   get_module_name.py130100% 
   get_page_from_module.py5180%19
   getdatecolstrname.py8187%21
   html.py9188%22
   is_debugging.py3166%17
   is_port_open.py60100% 
   isnotebook.py10100% 
   proxy.py65650%12–17, 19–22, 24, 27, 29, 36–37, 40–46, 49, 52–53, 55–60, 62–63, 70–71, 73–79, 87–88, 91–95, 97–103, 106–109, 111–115
   singleton.py70100% 
   table_col_builder.py461860%21, 29, 38–40, 42, 52–54, 56, 59–61, 63, 66–68, 70
   types.py1493179%49–50, 104–110, 138–141, 144–146, 185–186, 195–199, 201–208
   varnamefromcontent.py6183%17
gui_core
   _GuiCoreLib.py340100% 
   __init__.py10100% 
   _adapters.py823853%59–64, 100–101, 103, 113, 116–129, 133, 146–147, 149, 166–172, 196–197, 199
   _context.py57322161%21–22, 163, 172–173, 199, 203–204, 217, 232–233, 242–248, 250–251, 254–257, 264–265, 268–273, 285, 312–316, 319–325, 327–336, 351, 353–356, 358–359, 368–372, 374, 379, 381–384, 386, 389, 392, 396–407, 412, 423, 435–436, 438–443, 445, 449, 458, 464, 480–487, 492–495, 498–500, 510–514, 521–522, 529–531, 538–539, 547–550, 570–571, 577, 589–590, 601–602, 612, 622–623, 628, 640, 642–643, 650, 656, 659–662, 665–668, 677–679, 681, 685, 691, 698–704, 706–707, 716–717, 722, 725, 728, 735–742, 749–752, 758–761, 775, 795–796, 818–820, 826–827, 846–848, 864, 867–868, 885–886, 890–901
   _init.py50100% 
logger
   __init__.py00100% 
   _taipy_logger.py22290%30–31
rest
   __init__.py40100% 
   _init.py10100% 
   app.py200100% 
   extensions.py30100% 
   rest.py7185%45
   setup.py12120%11–12, 14, 16–17, 19–24, 26
   version.py90100% 
rest/api
   __init__.py20100% 
   error_handler.py49197%88
   views.py64493%165–166, 212–213
rest/api/exceptions
   __init__.py00100% 
   exceptions.py90100% 
rest/api/middlewares
   __init__.py00100% 
   _middleware.py14192%34
rest/api/resources
   __init__.py70100% 
   cycle.py490100% 
   datanode.py87396%465, 584, 603
   job.py70494%201–204
   scenario.py650100% 
   sequence.py66198%293
   task.py65198%202
rest/api/schemas
   __init__.py70100% 
   cycle.py100100% 
   datanode.py630100% 
   job.py120100% 
   scenario.py120100% 
   sequence.py100100% 
   task.py110100% 
rest/commons
   __init__.py00100% 
   apispec.py51982%35, 49, 84, 87, 91, 98–100, 103
   encoder.py13653%22–25, 27–28
   pagination.py14140%12, 14, 16–17, 20–23, 26–29, 36, 44
   to_from_model.py80100% 
templates/default/{{cookiecutter.__root_folder_name}}
   requirements.txt10100% 
   {{cookiecutter.__main_file}}.py00100% 
templates/default/{{cookiecutter.__root_folder_name}}/algorithms
   __init__.py110%12
   algorithms.py10100% 
templates/default/{{cookiecutter.__root_folder_name}}/configuration
   __init__.py110%12
   config.py3233%18, 20
templates/default/{{cookiecutter.__root_folder_name}}/pages
   __init__.py110%12
   root.py3233%19, 21
templates/default/{{cookiecutter.__root_folder_name}}/pages/page_example
   page_example.md00100% 
   page_example.py3233%19, 21
templates/default/{{cookiecutter.__root_folder_name}}/sections
   import.txt10100% 
   page_content.txt00100% 
templates/scenario-management/{{cookiecutter.__root_folder_name}}
   .taipyignore00100% 
templates/scenario-management/{{cookiecutter.__root_folder_name}}/algos
   __init__.py110%12
   algos.py3166%15
templates/scenario-management/{{cookiecutter.__root_folder_name}}/config
   __init__.py00100% 
   config.py9722%17, 22–25, 31, 34
   config.toml18950%3, 15–17, 19–22, 24
   config_with_toml.py440%12, 15–17
templates/scenario-management/{{cookiecutter.__root_folder_name}}/pages/job_page
   __init__.py110%12
   job_page.py2150%12
templates/scenario-management/{{cookiecutter.__root_folder_name}}/pages/scenario_page
   __init__.py110%12
   data_node_management.py141214%20–21, 26, 34–35, 42–43, 46–50
   scenario_page.py11109%12, 17–21, 23, 26–27, 30
TOTAL17607207688% 

Please sign in to comment.