Răsfoiți Sursa

Merge branch 'develop' into test/StatusList

Nam Nguyen 9 luni în urmă
părinte
comite
f73eb9b781

+ 6 - 1
.github/workflows/build-and-release-single-package.yml

@@ -153,10 +153,15 @@ jobs:
         run: |
         run: |
           cp -r taipy/_cli/. ${{ steps.set-variables.outputs.package_dir }}/taipy/_cli
           cp -r taipy/_cli/. ${{ steps.set-variables.outputs.package_dir }}/taipy/_cli
 
 
+      - name: Update pyproject.toml
+        working-directory: ${{ steps.set-variables.outputs.package_dir }}
+        run: |
+          python tools/release/setup_project.py . prod
+
       - name: Build package
       - name: Build package
         working-directory: ${{ steps.set-variables.outputs.package_dir }}
         working-directory: ${{ steps.set-variables.outputs.package_dir }}
         run: |
         run: |
-          python setup.py build_py && python -m build
+          python -m build
 
 
       - name: Rename files
       - name: Rename files
         run: |
         run: |

+ 13 - 8
.github/workflows/build-and-release.yml

@@ -151,10 +151,15 @@ jobs:
         run: |
         run: |
           cp -r taipy/_cli/. ${{ steps.set-variables.outputs.package_dir }}/taipy/_cli
           cp -r taipy/_cli/. ${{ steps.set-variables.outputs.package_dir }}/taipy/_cli
 
 
+      - name: Update pyproject.toml
+        working-directory: ${{ steps.set-variables.outputs.package_dir }}
+        run: |
+          python tools/release/setup_project.py . prod
+
       - name: Build package
       - name: Build package
         working-directory: ${{ steps.set-variables.outputs.package_dir }}
         working-directory: ${{ steps.set-variables.outputs.package_dir }}
         run: |
         run: |
-          python setup.py build_py && python -m build
+          python -m build
           for file in ./dist/*; do mv "$file" "${file//_/-}"; done
           for file in ./dist/*; do mv "$file" "${file//_/-}"; done
 
 
       - name: Create tag and release
       - name: Create tag and release
@@ -204,18 +209,18 @@ jobs:
           python -m pip install --upgrade pip
           python -m pip install --upgrade pip
           pip install build wheel
           pip install build wheel
 
 
-
-      - name: Backup setup.py
-        run: |
-          mv setup.py setup.old.py
-
       - name: Copy files from tools
       - name: Copy files from tools
         run: |
         run: |
           cp -r tools/packages/taipy/. .
           cp -r tools/packages/taipy/. .
 
 
+      - name: Update pyproject.toml
+        working-directory: ${{ steps.set-variables.outputs.package_dir }}
+        run: |
+          python tools/release/setup_project.py . prod
+
       - name: Build Taipy package
       - name: Build Taipy package
         run: |
         run: |
-          python setup.py build_py && python -m build
+          python -m build
 
 
       - name: Create tag and release Taipy
       - name: Create tag and release Taipy
         run: |
         run: |
@@ -244,7 +249,7 @@ jobs:
         env:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
 
-      - uses: stefanzweifel/git-auto-commit-action@v4
+      - uses: stefanzweifel/git-auto-commit-action@v5
         with:
         with:
           file_pattern: '*/version.json'
           file_pattern: '*/version.json'
           commit_message: Update version to ${{ needs.fetch-versions.outputs.NEW_VERSION }}
           commit_message: Update version to ${{ needs.fetch-versions.outputs.NEW_VERSION }}

+ 1 - 1
.github/workflows/check-config-pyi.yml

@@ -18,6 +18,6 @@ jobs:
           python-version: '3.11'
           python-version: '3.11'
       - name: Update config.pyi
       - name: Update config.pyi
         run: python taipy/config/stubs/generate_pyi.py
         run: python taipy/config/stubs/generate_pyi.py
-      - uses: stefanzweifel/git-auto-commit-action@v4
+      - uses: stefanzweifel/git-auto-commit-action@v5
         with:
         with:
           commit_message: "Update config.pyi"
           commit_message: "Update config.pyi"

+ 18 - 1
.github/workflows/packaging.yml

@@ -31,11 +31,28 @@ jobs:
         with:
         with:
           python-version: ${{ matrix.python-versions }}
           python-version: ${{ matrix.python-versions }}
 
 
+      - name: Install Dependencies
+        run: |
+          pip install toml
+
       - name: Build frontends
       - name: Build frontends
         run: |
         run: |
           python tools/frontend/bundle_build.py
           python tools/frontend/bundle_build.py
 
 
-      - name: Install Taipy without dependencies
+      - name: Update pyproject.toml
+        run: |
+          python tools/release/setup_project.py taipy/config
+          python tools/release/setup_project.py taipy/core
+          python tools/release/setup_project.py taipy/gui
+          python tools/release/setup_project.py taipy/rest
+          python tools/release/setup_project.py taipy/templates
+          python tools/release/setup_project.py .
+
+      - name: Install Taipy Subpackages
+        run: |
+          pip install taipy/config taipy/core taipy/gui taipy/rest taipy/templates
+
+      - name: Install Taipy
         run: |
         run: |
           pip install .
           pip install .
 
 

+ 64 - 0
pyproject.toml

@@ -1,3 +1,67 @@
+[build-system]
+requires = ["setuptools>=42", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy"
+version = "0.0.0"  # will be dynamically set
+description = "A 360° open-source platform from Python pilots to production-ready web apps."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+license = {text = "Apache License 2.0"}
+keywords = ["taipy"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+dependencies = []  # will be dynamically set
+
+[project.optional-dependencies]
+test = ["pytest>=3.8"]
+ngrok = ["pyngrok>=5.1,<6.0"]
+image = [
+    "python-magic>=0.4.24,<0.5; platform_system!='Windows'",
+    "python-magic-bin>=0.4.14,<0.5; platform_system=='Windows'"
+]
+rdp = ["rdp>=0.8"]
+arrow = ["pyarrow>=14.0.2,<15.0"]
+mssql = ["pyodbc>=4"]
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-0.0.0/relnotes/"  # version will be dynamically set
+
+[tool.setuptools.packages.find]
+include = ["taipy", "taipy.*"]
+
+[tool.setuptools.package-data]
+"taipy" = ["version.json"]
+
+[tool.setuptools]
+zip-safe = false
+
+[project.scripts]
+taipy = "taipy._entrypoint:_entrypoint"
+
 [tool.ruff]
 [tool.ruff]
 exclude = [
 exclude = [
     ".git",
     ".git",

+ 0 - 121
setup.py

@@ -1,121 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy package"""
-
-import os
-import json
-import platform
-import subprocess
-from pathlib import Path
-
-from setuptools import find_packages, setup
-from setuptools.command.build_py import build_py
-
-root_folder = Path(__file__).parent
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-# get current version
-with open(os.path.join("taipy", "version.json")) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-
-def get_requirements():
-    # get requirements from the different setups in tools/packages (removing taipy packages)
-    reqs = set()
-    for pkg in (root_folder / "tools" / "packages").iterdir():
-        requirements_file = pkg / "setup.requirements.txt"
-        if requirements_file.exists():
-            reqs.update(requirements_file.read_text("UTF-8").splitlines())
-
-    return [r for r in reqs if r and not r.startswith("taipy")]
-
-
-test_requirements = ["pytest>=3.8"]
-
-extras_require = {
-    "ngrok": ["pyngrok>=5.1,<6.0"],
-    "image": [
-        "python-magic>=0.4.24,<0.5;platform_system!='Windows'",
-        "python-magic-bin>=0.4.14,<0.5;platform_system=='Windows'",
-    ],
-    "rdp": ["rdp>=0.8"],
-    "arrow": ["pyarrow>=14.0.2,<15.0"],
-    "mssql": ["pyodbc>=4"],
-}
-
-
-class NPMInstall(build_py):
-    def run(self):
-        subprocess.run(
-            ["python", "bundle_build.py"],
-            cwd=root_folder / "tools" / "frontend",
-            check=True,
-            shell=platform.system() == "Windows",
-        )
-        build_py.run(self)
-
-
-setup(
-    author="Avaiga",
-    author_email="dev@taipy.io",
-    python_requires=">=3.8",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    description="A 360° open-source platform from Python pilots to production-ready web apps.",
-    install_requires=get_requirements(),
-    entry_points={
-        "console_scripts": [
-            "taipy = taipy._entrypoint:_entrypoint",
-        ]
-    },
-    license="Apache License 2.0",
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    keywords="taipy",
-    name="taipy",
-    packages=find_packages(include=["taipy", "taipy.*"]),
-    include_package_data=True,
-    test_suite="tests",
-    version=version_string,
-    zip_safe=False,
-    extras_require=extras_require,
-    cmdclass={"build_py": NPMInstall},
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 58 - 0
taipy/config/pyproject.toml

@@ -0,0 +1,58 @@
+[build-system]
+requires = ["setuptools>=42", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy-config"
+version = "0.0.0"  # will be dynamically set
+description = "A Taipy package dedicated to easily configure a Taipy application."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+license = {text = "Apache License 2.0"}
+keywords = ["taipy-config"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+
+dependencies = [
+    "toml>=0.10,<0.11",
+    "deepdiff>=6.7,<6.8"
+]
+
+[project.optional-dependencies]
+test = [
+    "pytest>=3.8"
+]
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-0.0.0/relnotes/"  # version will be dynamically set
+
+[tool.setuptools.packages]
+find = {where = ["."], include = ["taipy", "taipy.config", "taipy.config.*", "taipy.logger", "taipy.logger.*"]}
+
+[tool.setuptools.package-data]
+"version" = ["version.json"]
+
+[tool.setuptools]
+zip-safe = false

+ 0 - 80
taipy/config/setup.py

@@ -1,80 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy-config package"""
-
-import json
-import os
-from pathlib import Path
-
-from setuptools import find_namespace_packages, find_packages, setup
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-version_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.json")
-
-with open(version_path) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-requirements = ["toml>=0.10,<0.11", "deepdiff>=6.7,<6.8"]
-
-test_requirements = ["pytest>=3.8"]
-
-setup(
-    author="Avaiga",
-    author_email="dev@taipy.io",
-    python_requires=">=3.8",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    description="A Taipy package dedicated to easily configure a Taipy application.",
-    install_requires=requirements,
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    license="Apache License 2.0",
-    keywords="taipy-config",
-    name="taipy-config",
-    packages=find_namespace_packages(where=".")
-    + find_packages(include=["taipy", "taipy.config", "taipy.config.*", "taipy.logger", "taipy.logger.*"]),
-    include_package_data=True,
-    data_files=[('version', ['version.json'])],
-    test_suite="tests",
-    tests_require=test_requirements,
-    version=version_string,
-    zip_safe=False,
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 3 - 0
taipy/core/_version/_version_manager_factory.py

@@ -9,6 +9,7 @@
 # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # 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.
 # specific language governing permissions and limitations under the License.
 
 
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +22,7 @@ class _VersionManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _VersionFSRepository}
     __REPOSITORY_MAP = {"default": _VersionFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_VersionManager]:
     def _build_manager(cls) -> Type[_VersionManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             version_manager = _utils._load_fct(
             version_manager = _utils._load_fct(
@@ -36,5 +38,6 @@ class _VersionManagerFactory(_ManagerFactory):
         return version_manager  # type: ignore
         return version_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 3 - 0
taipy/core/cycle/_cycle_manager_factory.py

@@ -9,6 +9,7 @@
 # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # 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.
 # specific language governing permissions and limitations under the License.
 
 
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +22,7 @@ class _CycleManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _CycleFSRepository}
     __REPOSITORY_MAP = {"default": _CycleFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_CycleManager]:
     def _build_manager(cls) -> Type[_CycleManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             cycle_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".cycle._cycle_manager", "_CycleManager")  # type: ignore
             cycle_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".cycle._cycle_manager", "_CycleManager")  # type: ignore
@@ -34,5 +36,6 @@ class _CycleManagerFactory(_ManagerFactory):
         return cycle_manager  # type: ignore
         return cycle_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 3 - 1
taipy/core/data/_data_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +21,7 @@ class _DataManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _DataFSRepository}
     __REPOSITORY_MAP = {"default": _DataFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_DataManager]:
     def _build_manager(cls) -> Type[_DataManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             data_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".data._data_manager", "_DataManager")  # type: ignore
             data_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".data._data_manager", "_DataManager")  # type: ignore
@@ -34,5 +35,6 @@ class _DataManagerFactory(_ManagerFactory):
         return data_manager  # type: ignore
         return data_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 3 - 1
taipy/core/job/_job_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +21,7 @@ class _JobManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _JobFSRepository}
     __REPOSITORY_MAP = {"default": _JobFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_JobManager]:
     def _build_manager(cls) -> Type[_JobManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             job_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".job._job_manager", "_JobManager")  # type: ignore
             job_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".job._job_manager", "_JobManager")  # type: ignore
@@ -34,5 +35,6 @@ class _JobManagerFactory(_ManagerFactory):
         return job_manager  # type: ignore
         return job_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 62 - 0
taipy/core/pyproject.toml

@@ -0,0 +1,62 @@
+[build-system]
+requires = ["setuptools>=42", "wheel", ]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy-core"
+version = "0.0.0"   # will be dynamically set
+description = "A Python library to build powerful and customized data-driven back-end applications."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+keywords = ["taipy-core", ]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+
+dependencies = []   # will be dynamically set
+
+[project.license]
+text = "Apache License 2.0"
+
+[project.optional-dependencies]
+test = ["pytest>=3.8", ]
+mssql = ["pyodbc>=4,<4.1", ]
+mysql = ["pymysql>1,<1.1", ]
+postgresql = ["psycopg2>2.9,<2.10", ]
+parquet = ["fastparquet==2022.11.0", "pyarrow>=14.0.2,<15.0", ]
+s3 = ["boto3==1.29.1", ]
+mongo = ["pymongo[srv]>=4.2.0,<5.0", ]
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-4.0.0.dev0/relnotes/"
+
+[tool.setuptools]
+zip-safe = false
+
+[tool.setuptools.package-data]
+taipy = ["version.json", ]
+
+[tool.setuptools.packages.find]
+where = [".", ]
+include = ["taipy", "taipy.core", "taipy.core.*", ]

+ 3 - 1
taipy/core/scenario/_scenario_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +21,7 @@ class _ScenarioManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _ScenarioFSRepository}
     __REPOSITORY_MAP = {"default": _ScenarioFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_ScenarioManager]:
     def _build_manager(cls) -> Type[_ScenarioManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             scenario_manager = _load_fct(
             scenario_manager = _load_fct(
@@ -36,5 +37,6 @@ class _ScenarioManagerFactory(_ManagerFactory):
         return scenario_manager  # type: ignore
         return scenario_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 2 - 1
taipy/core/sequence/_sequence_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -18,6 +18,7 @@ from ._sequence_manager import _SequenceManager
 
 
 class _SequenceManagerFactory(_ManagerFactory):
 class _SequenceManagerFactory(_ManagerFactory):
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_SequenceManager]:  # type: ignore
     def _build_manager(cls) -> Type[_SequenceManager]:  # type: ignore
         if cls._using_enterprise():
         if cls._using_enterprise():
             sequence_manager = _load_fct(
             sequence_manager = _load_fct(

+ 0 - 102
taipy/core/setup.py

@@ -1,102 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy-core package"""
-
-import json
-import os
-from pathlib import Path
-
-from setuptools import find_namespace_packages, find_packages, setup
-
-root_folder = Path(__file__).parent
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-version_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.json")
-with open(version_path) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-
-def get_requirements():
-    # get requirements from the different setups in tools/packages (removing taipy packages)
-    reqs = set()
-    for pkg in (root_folder / "tools" / "packages").iterdir():
-        if "taipy-core" not in str(pkg):
-            continue
-        requirements_file = pkg / "setup.requirements.txt"
-        if requirements_file.exists():
-            reqs.update(requirements_file.read_text("UTF-8").splitlines())
-
-    return [r for r in reqs if r and not r.startswith("taipy")]
-
-
-test_requirements = ["pytest>=3.8"]
-
-extras_require = {
-    "mssql": ["pyodbc>=4,<4.1"],
-    "mysql": ["pymysql>1,<1.1"],
-    "postgresql": ["psycopg2>2.9,<2.10"],
-    "parquet": ["fastparquet==2022.11.0", "pyarrow>=14.0.2,<15.0"],
-    "s3": ["boto3==1.29.1"],
-    "mongo": ["pymongo[srv]>=4.2.0,<5.0"],
-}
-
-setup(
-    author="Avaiga",
-    author_email="dev@taipy.io",
-    python_requires=">=3.8",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    description="A Python library to build powerful and customized data-driven back-end applications.",
-    install_requires=get_requirements(),
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    license="Apache License 2.0",
-    keywords="taipy-core",
-    name="taipy-core",
-    packages=find_namespace_packages(where=".") + find_packages(include=["taipy", "taipy.core", "taipy.core.*"]),
-    include_package_data=True,
-    data_files=[('version', ['version.json'])],
-    test_suite="tests",
-    tests_require=test_requirements,
-    version=version_string,
-    zip_safe=False,
-    extras_require=extras_require,
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 3 - 1
taipy/core/submission/_submission_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +21,7 @@ class _SubmissionManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _SubmissionFSRepository}
     __REPOSITORY_MAP = {"default": _SubmissionFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_SubmissionManager]:
     def _build_manager(cls) -> Type[_SubmissionManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             submission_manager = _load_fct(
             submission_manager = _load_fct(
@@ -37,5 +38,6 @@ class _SubmissionManagerFactory(_ManagerFactory):
         return submission_manager  # type: ignore
         return submission_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 3 - 1
taipy/core/task/_task_manager_factory.py

@@ -8,7 +8,7 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # 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
 # 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.
 # specific language governing permissions and limitations under the License.
-
+from functools import lru_cache
 from typing import Type
 from typing import Type
 
 
 from .._manager._manager_factory import _ManagerFactory
 from .._manager._manager_factory import _ManagerFactory
@@ -21,6 +21,7 @@ class _TaskManagerFactory(_ManagerFactory):
     __REPOSITORY_MAP = {"default": _TaskFSRepository}
     __REPOSITORY_MAP = {"default": _TaskFSRepository}
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_manager(cls) -> Type[_TaskManager]:
     def _build_manager(cls) -> Type[_TaskManager]:
         if cls._using_enterprise():
         if cls._using_enterprise():
             task_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".task._task_manager", "_TaskManager")  # type: ignore
             task_manager = _load_fct(cls._TAIPY_ENTERPRISE_CORE_MODULE + ".task._task_manager", "_TaskManager")  # type: ignore
@@ -34,5 +35,6 @@ class _TaskManagerFactory(_ManagerFactory):
         return task_manager  # type: ignore
         return task_manager  # type: ignore
 
 
     @classmethod
     @classmethod
+    @lru_cache
     def _build_repository(cls):
     def _build_repository(cls):
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()
         return cls._get_repository_with_repo_map(cls.__REPOSITORY_MAP)()

+ 2 - 1
taipy/gui/_default_config.py

@@ -58,12 +58,14 @@ default_config: Config = {
     "ngrok_token": "",
     "ngrok_token": "",
     "notebook_proxy": True,
     "notebook_proxy": True,
     "notification_duration": 3000,
     "notification_duration": 3000,
+    "port": 5000,
     "propagate": True,
     "propagate": True,
     "run_browser": True,
     "run_browser": True,
     "run_in_thread": False,
     "run_in_thread": False,
     "run_server": True,
     "run_server": True,
     "server_config": None,
     "server_config": None,
     "single_client": False,
     "single_client": False,
+    "state_retention_period": 0,
     "system_notification": False,
     "system_notification": False,
     "theme": None,
     "theme": None,
     "time_zone": None,
     "time_zone": None,
@@ -74,5 +76,4 @@ default_config: Config = {
     "use_reloader": False,
     "use_reloader": False,
     "watermark": "Taipy inside",
     "watermark": "Taipy inside",
     "webapp_path": None,
     "webapp_path": None,
-    "port": 5000,
 }
 }

+ 6 - 4
taipy/gui/config.py

@@ -46,6 +46,7 @@ ConfigParameter = t.Literal[
     "ngrok_token",
     "ngrok_token",
     "notebook_proxy",
     "notebook_proxy",
     "notification_duration",
     "notification_duration",
+    "port",
     "propagate",
     "propagate",
     "run_browser",
     "run_browser",
     "run_in_thread",
     "run_in_thread",
@@ -56,13 +57,13 @@ ConfigParameter = t.Literal[
     "theme",
     "theme",
     "time_zone",
     "time_zone",
     "title",
     "title",
+    "state_retention_period",
     "stylekit",
     "stylekit",
     "upload_folder",
     "upload_folder",
     "use_arrow",
     "use_arrow",
     "use_reloader",
     "use_reloader",
     "watermark",
     "watermark",
     "webapp_path",
     "webapp_path",
-    "port",
 ]
 ]
 
 
 Stylekit = t.TypedDict(
 Stylekit = t.TypedDict(
@@ -117,23 +118,24 @@ Config = t.TypedDict(
         "ngrok_token": str,
         "ngrok_token": str,
         "notebook_proxy": bool,
         "notebook_proxy": bool,
         "notification_duration": int,
         "notification_duration": int,
+        "port": t.Union[t.Literal["auto"], int],
         "propagate": bool,
         "propagate": bool,
         "run_browser": bool,
         "run_browser": bool,
         "run_in_thread": bool,
         "run_in_thread": bool,
         "run_server": bool,
         "run_server": bool,
         "server_config": t.Optional[ServerConfig],
         "server_config": t.Optional[ServerConfig],
         "single_client": bool,
         "single_client": bool,
+        "state_retention_period": int,
+        "stylekit": t.Union[bool, Stylekit],
         "system_notification": bool,
         "system_notification": bool,
         "theme": t.Optional[t.Dict[str, t.Any]],
         "theme": t.Optional[t.Dict[str, t.Any]],
         "time_zone": t.Optional[str],
         "time_zone": t.Optional[str],
         "title": t.Optional[str],
         "title": t.Optional[str],
-        "stylekit": t.Union[bool, Stylekit],
         "upload_folder": t.Optional[str],
         "upload_folder": t.Optional[str],
         "use_arrow": bool,
         "use_arrow": bool,
         "use_reloader": bool,
         "use_reloader": bool,
         "watermark": t.Optional[str],
         "watermark": t.Optional[str],
         "webapp_path": t.Optional[str],
         "webapp_path": t.Optional[str],
-        "port": t.Union[t.Literal["auto"], int],
     },
     },
     total=False,
     total=False,
 )
 )
@@ -235,7 +237,7 @@ class _Config(object):
                     elif key == "port" and str(value).strip() == "auto":
                     elif key == "port" and str(value).strip() == "auto":
                         config["port"] = "auto"
                         config["port"] = "auto"
                     else:
                     else:
-                        config[key] = value if config[key] is None else type(config[key])(value)  # type: ignore
+                        config[key] = value if config[key] is None else type(config[key])(value)
                 except Exception as e:
                 except Exception as e:
                     _warn(
                     _warn(
                         f"Invalid keyword arguments value in Gui.run {key} - {value}. Unable to parse value to the correct type",  # noqa: E501
                         f"Invalid keyword arguments value in Gui.run {key} - {value}. Unable to parse value to the correct type",  # noqa: E501

+ 17 - 0
taipy/gui/gui.py

@@ -26,6 +26,7 @@ import warnings
 from importlib import metadata, util
 from importlib import metadata, util
 from importlib.util import find_spec
 from importlib.util import find_spec
 from pathlib import Path
 from pathlib import Path
+from threading import Timer
 from types import FrameType, FunctionType, LambdaType, ModuleType, SimpleNamespace
 from types import FrameType, FunctionType, LambdaType, ModuleType, SimpleNamespace
 from urllib.parse import unquote, urlencode, urlparse
 from urllib.parse import unquote, urlencode, urlparse
 
 
@@ -611,6 +612,22 @@ class Gui:
 
 
     def _handle_disconnect(self):
     def _handle_disconnect(self):
         Hooks()._handle_disconnect(self)
         Hooks()._handle_disconnect(self)
+        if (sid := getattr(request, "sid", None)) and (st_to := self._get_config("state_retention_period", 0)) > 0:
+            for cl_id, sids in self.__client_id_2_sid.items():
+                if sid in sids:
+                    if len(sids) == 1:
+                        Timer(st_to, self._remove_state, [cl_id]).start()
+                    else:
+                        sids.remove(sid)
+                    return
+
+    def _remove_state(self, client_id: str):
+        if (sids := self.__client_id_2_sid.get(client_id, None)) and len(sids) == 1:
+            try:
+                del self.__client_id_2_sid[client_id]
+                self._bindings()._delete_scope(client_id)
+            except Exception as e:
+                _warn(f"Unexpected error removing state {client_id}", e)
 
 
     def _manage_message(self, msg_type: _WsType, message: dict) -> None:
     def _manage_message(self, msg_type: _WsType, message: dict) -> None:
         try:
         try:

+ 1 - 1
taipy/gui/hook.py

@@ -11,7 +11,7 @@ class Hook:
 
 
 class Hooks(object, metaclass=_Singleton):
 class Hooks(object, metaclass=_Singleton):
     def __init__(self):
     def __init__(self):
-        self.__hooks: t.List[Hook] = []
+        self.__hooks: t.List[Hook] = []  # type: ignore[annotation-unchecked]
 
 
     def _register_hook(self, hook: Hook):
     def _register_hook(self, hook: Hook):
         # Prevent duplicated hooks
         # Prevent duplicated hooks

+ 58 - 0
taipy/gui/pyproject.toml

@@ -0,0 +1,58 @@
+[build-system]
+requires = [ "setuptools>=42", "wheel", "setuptools_scm",]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy-gui"
+version = "0.0.0"  # will be set dynamically
+description = "Low-code library to create graphical user interfaces on the Web for your Python applications."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+keywords = [ "taipy-gui",]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+dependencies = []  # will be set dynamically
+
+[project.license]
+text = "Apache License 2.0"
+
+[project.optional-dependencies]
+test = [ "pytest>=3.8",]
+ngrok = [ "pyngrok>=5.1,<6.0",]
+image = [ "python-magic>=0.4.24,<0.5; platform_system!='Windows'", "python-magic-bin>=0.4.14,<0.5; platform_system=='Windows'",]
+arrow = [ "pyarrow>=14.0.2,<15.0",]
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-0.0.0/relnotes/"  # will be set dynamically
+
+[tool.setuptools]
+zip-safe = false
+
+[tool.setuptools.package-data]
+taipy = [ "version.json",]
+
+[tool.setuptools.packages.find]
+where = [ ".",]
+include = [ "taipy", "taipy.gui", "taipy.gui.*",]

+ 0 - 118
taipy/gui/setup.py

@@ -1,118 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy-gui package"""
-
-import json
-import os
-from pathlib import Path
-
-from setuptools import find_namespace_packages, find_packages, setup
-from setuptools.command.build_py import build_py
-
-root_folder = Path(__file__).parent
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-version_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.json")
-with open(version_path) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-
-def get_requirements():
-    # get requirements from the different setups in tools/packages (removing taipy packages)
-    reqs = set()
-    for pkg in (root_folder / "tools" / "packages").iterdir():
-        if "taipy-gui" not in str(pkg):
-            continue
-        requirements_file = pkg / "setup.requirements.txt"
-        if requirements_file.exists():
-            reqs.update(requirements_file.read_text("UTF-8").splitlines())
-
-    return [r for r in reqs if r and not r.startswith("taipy")]
-
-
-test_requirements = ["pytest>=3.8"]
-
-extras_require = {
-    "ngrok": ["pyngrok>=5.1,<6.0"],
-    "image": [
-        "python-magic>=0.4.24,<0.5;platform_system!='Windows'",
-        "python-magic-bin>=0.4.14,<0.5;platform_system=='Windows'",
-    ],
-    "arrow": ["pyarrow>=14.0.2,<15.0"],
-}
-
-
-def _build_webapp():
-    already_exists = Path("./taipy/gui/webapp/index.html").exists()
-    if not already_exists:
-        os.system("cd ../../frontend/taipy-gui/dom && npm ci")
-        os.system("cd ../../frontend/taipy-gui && npm ci --omit=optional && npm run build")
-
-
-class NPMInstall(build_py):
-    def run(self):
-        _build_webapp()
-        build_py.run(self)
-
-
-setup(
-    author="Avaiga",
-    author_email="dev@taipy.io",
-    python_requires=">=3.8",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    description="Low-code library to create graphical user interfaces on the Web for your Python applications.",
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    install_requires=get_requirements(),
-    license="Apache License 2.0",
-    include_package_data=True,
-    data_files=[("version", ["version.json"])],
-    keywords="taipy-gui",
-    name="taipy-gui",
-    packages=find_namespace_packages(where=".") + find_packages(include=["taipy", "taipy.gui", "taipy.gui.*"]),
-    test_suite="tests",
-    tests_require=test_requirements,
-    version=version_string,
-    zip_safe=False,
-    extras_require=extras_require,
-    cmdclass={"build_py": NPMInstall},
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 3 - 0
taipy/gui/utils/_bindings.py

@@ -68,6 +68,9 @@ class _Bindings:
         self.__scopes.create_scope(id)
         self.__scopes.create_scope(id)
         return id, create
         return id, create
 
 
+    def _delete_scope(self, id: str):
+        self.__scopes.delete_scope(id)
+
     def _new_scopes(self):
     def _new_scopes(self):
         self.__scopes = _DataScopes(self.__gui)
         self.__scopes = _DataScopes(self.__gui)
 
 

+ 50 - 0
taipy/rest/pyproject.toml

@@ -0,0 +1,50 @@
+[build-system]
+requires = ["setuptools>=42", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy-rest"
+version = "0.0.0"  # will be dynamically set
+description = "Library to expose taipy-core REST APIs."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+license = {text = "Apache License 2.0"}
+keywords = ["taipy-rest"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+dependencies = []  # will be dynamically set
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-0.0.0/relnotes/"  # version will be dynamically set
+
+[tool.setuptools.packages.find]
+where = ["."]
+include = ["taipy", "taipy.rest"]
+
+[tool.setuptools.package-data]
+"taipy" = ["version.json"]
+
+[tool.setuptools]
+zip-safe = false

+ 0 - 87
taipy/rest/setup.py

@@ -1,87 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy-rest package"""
-
-import json
-import os
-from pathlib import Path
-
-from setuptools import find_namespace_packages, find_packages, setup
-
-root_folder = Path(__file__).parent
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-version_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.json")
-with open(version_path) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-
-def get_requirements():
-    # get requirements from the different setups in tools/packages (removing taipy packages)
-    reqs = set()
-    for pkg in (root_folder / "tools" / "packages").iterdir():
-        if "taipy-rest" not in str(pkg):
-            continue
-        requirements_file = pkg / "setup.requirements.txt"
-        if requirements_file.exists():
-            reqs.update(requirements_file.read_text("UTF-8").splitlines())
-
-    return [r for r in reqs if r and not r.startswith("taipy")]
-
-
-setup(
-    author="Avaiga",
-    name="taipy-rest",
-    keywords="taipy-rest",
-    python_requires=">=3.8",
-    version=version_string,
-    author_email="dev@taipy.io",
-    packages=find_namespace_packages(where=".") + find_packages(include=["taipy", "taipy.rest"]),
-    include_package_data=True,
-    data_files=[('version', ['version.json'])],
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    description="Library to expose taipy-core REST APIs.",
-    license="Apache License 2.0",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    install_requires=get_requirements(),
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 53 - 0
taipy/templates/pyproject.toml

@@ -0,0 +1,53 @@
+[build-system]
+requires = ["setuptools>=42", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "taipy-templates"
+version = "0.0.0"  # will be dynamically set
+description = "An open-source package holding Taipy application templates."
+readme = "package_desc.md"
+requires-python = ">=3.8"
+license = {text = "Apache License 2.0"}
+keywords = ["taipy-templates"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Topic :: Software Development",
+    "Topic :: Scientific/Engineering",
+    "Operating System :: Microsoft :: Windows",
+    "Operating System :: POSIX",
+    "Operating System :: Unix",
+    "Operating System :: MacOS",
+]
+dependencies = []  # version will be dynamically set
+
+[project.optional-dependencies]
+test = ["pytest>=3.8"]
+
+[project.urls]
+Homepage = "https://www.taipy.io"
+Documentation = "https://docs.taipy.io"
+Source = "https://github.com/Avaiga/taipy"
+Download = "https://pypi.org/project/taipy/#files"
+Tracker = "https://github.com/Avaiga/taipy/issues"
+Security = "https://github.com/Avaiga/taipy?tab=security-ov-file#readme"
+"Release notes" = "https://docs.taipy.io/en/release-0.0.0/relnotes/"  # version will be dynamically set
+
+[tool.setuptools.packages.find]
+where = ["."]
+include = ["taipy"]
+
+[tool.setuptools.package-data]
+"taipy" = ["version.json"]
+
+[tool.setuptools]
+zip-safe = false

+ 0 - 74
taipy/templates/setup.py

@@ -1,74 +0,0 @@
-# Copyright 2021-2024 Avaiga Private Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-"""The setup script for taipy-templates package"""
-
-import json
-import os
-from pathlib import Path
-
-from setuptools import find_namespace_packages, find_packages, setup
-
-package_desc = Path("package_desc.md").read_text("UTF-8")
-
-version_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.json")
-with open(version_path) as version_file:
-    version = json.load(version_file)
-    version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
-    if vext := version.get("ext"):
-        version_string = f"{version_string}.{vext}"
-
-test_requirements = ["pytest>=3.8"]
-
-setup(
-    author="Avaiga",
-    author_email="dev@taipy.io",
-    python_requires=">=3.8",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Topic :: Software Development",
-        "Topic :: Scientific/Engineering",
-        "Operating System :: Microsoft :: Windows",
-        "Operating System :: POSIX",
-        "Operating System :: Unix",
-        "Operating System :: MacOS",
-    ],
-    description="An open-source package holding Taipy application templates.",
-    license="Apache License 2.0",
-    long_description=package_desc,
-    long_description_content_type="text/markdown",
-    keywords="taipy-templates",
-    name="taipy-templates",
-    packages=find_namespace_packages(where=".") + find_packages(include=["taipy"]),
-    include_package_data=True,
-    data_files=[('version', ['version.json'])],
-    test_suite="tests",
-    version=version_string,
-    zip_safe=False,
-    project_urls={
-        "Homepage": "https://www.taipy.io",
-        "Documentation": "https://docs.taipy.io",
-        "Source": "https://github.com/Avaiga/taipy",
-        "Download": "https://pypi.org/project/taipy/#files",
-        "Tracker": "https://github.com/Avaiga/taipy/issues",
-        "Security": "https://github.com/Avaiga/taipy?tab=security-ov-file#readme",
-        f"Release notes": "https://docs.taipy.io/en/release-{version_string}/relnotes/",
-    },
-)

+ 2 - 1
tests/gui/config/test_cli.py

@@ -82,11 +82,13 @@ def test_gui_service_arguments_hierarchy():
     assert service_config["margin"] is None
     assert service_config["margin"] is None
     assert service_config["ngrok_token"] == ""
     assert service_config["ngrok_token"] == ""
     assert service_config["notification_duration"] == 3000
     assert service_config["notification_duration"] == 3000
+    assert service_config["port"] == 5000
     assert service_config["propagate"]
     assert service_config["propagate"]
     assert service_config["run_browser"]
     assert service_config["run_browser"]
     assert not service_config["run_in_thread"]
     assert not service_config["run_in_thread"]
     assert not service_config["run_server"]
     assert not service_config["run_server"]
     assert not service_config["single_client"]
     assert not service_config["single_client"]
+    assert service_config["state_retention_period"] == 0
     assert not service_config["system_notification"]
     assert not service_config["system_notification"]
     assert service_config["theme"] is None
     assert service_config["theme"] is None
     assert service_config["time_zone"] is None
     assert service_config["time_zone"] is None
@@ -96,7 +98,6 @@ def test_gui_service_arguments_hierarchy():
     assert not service_config["use_reloader"]
     assert not service_config["use_reloader"]
     assert service_config["watermark"] == "Taipy inside"
     assert service_config["watermark"] == "Taipy inside"
     assert service_config["webapp_path"] is None
     assert service_config["webapp_path"] is None
-    assert service_config["port"] == 5000
     gui.stop()
     gui.stop()
 
 
     # Override default configuration by explicit defined arguments in Gui.run()
     # Override default configuration by explicit defined arguments in Gui.run()

+ 5 - 5
tools/gui/generate_pyi.py

@@ -13,7 +13,7 @@ import json
 import os
 import os
 import re
 import re
 import sys
 import sys
-from typing import List
+from typing import Any, Dict, List
 
 
 from markdownify import markdownify
 from markdownify import markdownify
 
 
@@ -79,7 +79,7 @@ with open(builder_pyi_file, "a") as file:
     file.write("from ._element import _Block, _Control, _Element\n")
     file.write("from ._element import _Block, _Control, _Element\n")
 
 
 
 
-def resolve_inherit(name: str, properties, inherits, viselements) -> List[dict[str, any]]:
+def resolve_inherit(name: str, properties, inherits, viselements) -> List[Dict[str, Any]]:
     if not inherits:
     if not inherits:
         return properties
         return properties
     for inherit_name in inherits:
     for inherit_name in inherits:
@@ -137,10 +137,10 @@ def format_as_parameter(property):
     return f"{property['name']}{type}{default_value}"
     return f"{property['name']}{type}{default_value}"
 
 
 
 
-def build_doc(name: str, desc: dict[str, any]):
+def build_doc(name: str, desc: Dict[str, Any]):
     if "doc" not in desc:
     if "doc" not in desc:
         return ""
         return ""
-    doc = desc["doc"]
+    doc = str(desc["doc"])
     if desc["name"] == "class_name":
     if desc["name"] == "class_name":
         doc = doc.replace("<element_type>", name)
         doc = doc.replace("<element_type>", name)
     # This won't work for Scenartio Management and Block elements
     # This won't work for Scenartio Management and Block elements
@@ -166,7 +166,7 @@ def generate_elements(category: str, base_class: str):
         name = element[0]
         name = element[0]
         desc = element[1]
         desc = element[1]
         properties_doc = ""
         properties_doc = ""
-        property_list: List[dict[str, any]] = []
+        property_list: List[Dict[str, Any]] = []
         property_names: List[str] = []
         property_names: List[str] = []
         properties = resolve_inherit(name, desc["properties"], desc.get("inherits", None), viselements)
         properties = resolve_inherit(name, desc["properties"], desc.get("inherits", None), viselements)
         # Remove hidden properties and indexed properties (TODO?)
         # Remove hidden properties and indexed properties (TODO?)

+ 97 - 0
tools/release/setup_project.py

@@ -0,0 +1,97 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+
+import json
+import os
+import platform
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+import toml  # type: ignore
+
+
+def get_requirements(pkg: str, env: str = "dev") -> list:
+    # get requirements from the different setups in tools/packages (removing taipy packages)
+    reqs = set()
+    pkg_name = pkg if pkg == "taipy" else f"taipy-{pkg}"
+    root_folder = Path(__file__).parent
+    package_path = os.path.join(root_folder.parent, "packages", pkg_name)
+    requirements_file = os.path.join(package_path, "setup.requirements.txt")
+    if os.path.exists(requirements_file):
+        reqs.update(Path(requirements_file).read_text("UTF-8").splitlines())
+    if env == "dev":
+        return [r for r in reqs if r and not r.startswith("taipy")]
+    return list(reqs)
+
+
+def update_pyproject(version_path: str, pyproject_path: str, env: str = "dev"):
+    with open(version_path) as version_file:
+        version = json.load(version_file)
+        version_string = f'{version.get("major", 0)}.{version.get("minor", 0)}.{version.get("patch", 0)}'
+        if vext := version.get("ext"):
+            version_string = f"{version_string}.{vext}"
+
+    pyproject_data = toml.load(pyproject_path)
+    pyproject_data["project"]["version"] = version_string
+    pyproject_data["project"]["urls"]["Release notes"] = f"https://docs.taipy.io/en/release-{version_string}/relnotes/"
+    pyproject_data["project"]["dependencies"] = get_requirements(get_pkg_name(pyproject_path), env)
+
+    with open(pyproject_path, "w", encoding="utf-8") as pyproject_file:
+        toml.dump(pyproject_data, pyproject_file)
+
+
+def _build_webapp(webapp_path: str):
+    already_exists = Path(webapp_path).exists()
+    if not already_exists:
+        os.system("cd ../../frontend/taipy-gui/dom && npm ci")
+        os.system("cd ../../frontend/taipy-gui && npm ci --omit=optional && npm run build")
+
+
+def get_pkg_name(path: str) -> str:
+    # The regex pattern
+    pattern = r"([^/\\]+)[/\\]pyproject\.toml$"
+
+    # Search for the pattern
+    match = re.search(pattern, os.path.abspath(path))
+    if not match:
+        raise ValueError(f"Could not find package name in path: {path}")
+    return match.group(1)
+
+
+if __name__ == "__main__":
+    _pyproject_path = os.path.join(sys.argv[1], "pyproject.toml")
+    try:
+        env = sys.argv[2]
+    except IndexError:
+        env = "dev"
+
+    pkg = get_pkg_name(_pyproject_path)
+    if pkg == "taipy":
+        _version_path = os.path.join(sys.argv[1], "taipy", "version.json")
+        _webapp_path = os.path.join(sys.argv[1], "taipy", "gui", "webapp", "index.html")
+    else:
+        _version_path = os.path.join(sys.argv[1], "version.json")
+        _webapp_path = os.path.join(sys.argv[1], "webapp", "index.html")
+
+    update_pyproject(_version_path, _pyproject_path, env)
+
+    if pkg == "gui":
+        _build_webapp(_webapp_path)
+
+    if pkg == "taipy":
+        subprocess.run(
+            ["python", "bundle_build.py"],
+            cwd=os.path.join("tools", "frontend"),
+            check=True,
+            shell=platform.system() == "Windows",
+        )