소스 검색

Merge branch 'develop' into feature/server-generalize

Dinh Long Nguyen 1 주 전
부모
커밋
66f50ab31f

+ 1 - 1
.github/actions/install/action.yml

@@ -37,7 +37,7 @@ runs:
         cache-dependency-path: 'Pipfile'
 
     - name: Install pipenv
-      run: pip install pipenv --upgrade
+      run: pip install "pipenv<2025.0.0"
       shell: bash
 
     - name: Install pipenv dependencies

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

@@ -135,7 +135,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install build wheel pipenv mypy black isort
+          pip install build wheel "pipenv<2025.0.0" mypy black isort
 
       - name: Install GUI dependencies
         if: ${{ github.event.inputs.target_package == 'gui' || github.event.inputs.target_package == 'taipy' }}
@@ -168,7 +168,7 @@ jobs:
           if compgen -G "./dist/*_*" > /dev/null; then
             for file in ./dist/*_*; do mv "$file" "${file//_/-}"; done
           fi
-          
+
       - name: Create tag and release
         working-directory: "build_${{ github.event.inputs.target_package }}"
         run: |

+ 2 - 2
.github/workflows/build-and-release.yml

@@ -128,7 +128,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install build wheel pipenv mypy black isort
+          pip install build wheel "pipenv<2025.0.0" mypy black isort
 
       - name: Build GUI front-end
         if: ${{ matrix.package == 'gui' }}
@@ -211,7 +211,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install build wheel pipenv mypy black isort
+          pip install build wheel "pipenv<2025.0.0" mypy black isort
 
       - uses: actions/download-artifact@v4
         with:

+ 4 - 3
.github/workflows/partial-tests.yml

@@ -17,6 +17,7 @@ jobs:
           mypy_flags:  "--ignore-missing-imports --implicit-optional --disable-error-code attr-defined --no-namespace-packages --exclude (taipy/templates/|tools/|doc/gui/examples/.*/builder.py|taipy/common/config/config.pyi) --follow-imports skip --disable-error-code import-untyped"
 
       - uses: chartboost/ruff-action@v1
+
   tests:
     needs: linter
     timeout-minutes: 70
@@ -56,7 +57,7 @@ jobs:
         run: pip install --upgrade setuptools wheel
 
       - name: Install pipenv
-        run: pip install pipenv --upgrade
+        run: pip install "pipenv<2025.0.0"
 
       - name: Install Dependencies
         run: pipenv install --dev --python=${{ matrix.python-version }}
@@ -154,7 +155,7 @@ jobs:
 
       - name: Install pipenv
         if: steps.changes.outputs.core == 'true'
-        run: pip install pipenv --upgrade
+        run: pip install "pipenv<2025.0.0"
 
       - name: Install Dependencies
         if: steps.changes.outputs.core == 'true'
@@ -197,7 +198,7 @@ jobs:
 
       - name: Install pipenv
         if: steps.changes.outputs.core == 'true'
-        run: pip install pipenv --upgrade
+        run: pip install "pipenv<2025.0.0"
 
       - name: Install Dependencies
         if: steps.changes.outputs.core == 'true'

+ 5 - 0
.github/workflows/publish.yml

@@ -27,6 +27,11 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
+      - name: Install mandatory Python packages
+        run: |
+          python -m pip install --upgrade pip
+          pip install requests
+
       - name: Verify if all releases exist
         run: |
           python tools/release/check_releases.py dist ${{ github.event.inputs.version }}

+ 0 - 1
Pipfile

@@ -64,7 +64,6 @@ pytest-cov = "*"
 pytest-mock = "*"
 pytest-playwright = "*"
 pytest-timeout = "*"
-python-dotenv = "*"
 testbook = "*"
 twine = "*"
 types-flask = "*"

+ 2 - 2
SECURITY.md

@@ -7,8 +7,8 @@ The following table summarizes the supported and maintained versions of Taipy th
 
 | Version | Supported          |
 | ------- | ------------------ |
-| < 3.0   | :x:                |
-| >= 3.0  | :white_check_mark: |
+| < 3.1   | :x:                |
+| >= 3.1  | :white_check_mark: |
 
 
 ## Reporting a Vulnerability

+ 9 - 2
frontend/taipy-gui/src/components/Taipy/Chat.spec.tsx

@@ -23,6 +23,7 @@ import { stringIcon } from "../../utils/icon";
 import { TableValueType } from "./tableUtils";
 
 import { toDataUrl } from "../../utils/image";
+import { LoVElt } from "./lovUtils";
 jest.mock('../../utils/image', () => ({
     toDataUrl: (url: string) => new Promise((resolve) => resolve(url)),
   }));
@@ -40,9 +41,10 @@ const messages: TableValueType = {
         start: 0,
     },
 };
-const user1: [string, stringIcon] = ["Fred", { path: "/images/favicon.png", text: "Fred.png" }];
+const user1: [string, stringIcon] = ["Fred", { path: "/images/favicon.png", text: "Fred" }];
 const user2: [string, stringIcon] = ["Fredi", { path: "/images/fred.png", text: "Fredi.png" }];
 const users = [user1, user2];
+const users2 = [["<taipy.gui.icon.Icon 1", user1[1]], ["<taipy.gui.icon.Icon 2", user2[1]]] as LoVElt[];
 
 const searchMsg = messages[valueKey].data[0][1];
 
@@ -65,7 +67,12 @@ describe("Chat Component", () => {
     });
     it("can display an avatar", async () => {
         const { getByAltText } = render(<Chat messages={messages} users={users} defaultKey={valueKey} mode="raw" />);
-        const elt = getByAltText("Fred.png");
+        const elt = getByAltText("Fred");
+        expect(elt.tagName).toBe("IMG");
+    });
+    it("can display an avatar from Icon", async () => {
+        const { getByAltText } = render(<Chat messages={messages} users={users2} defaultKey={valueKey} mode="raw" />);
+        const elt = getByAltText("Fred");
         expect(elt.tagName).toBe("IMG");
     });
     it("is disabled", async () => {

+ 2 - 1
frontend/taipy-gui/src/components/Taipy/Chat.tsx

@@ -368,7 +368,8 @@ const Chat = (props: ChatProps) => {
     const avatars = useMemo(() => {
         return users.reduce((pv, elt) => {
             if (elt.id) {
-                pv[elt.id] =
+                const id = elt.id.startsWith("<taipy.gui.icon.Icon") && typeof elt.item !== "string" ? elt.item.text : elt.id;
+                pv[id] =
                     typeof elt.item == "string" ? (
                         <Tooltip title={elt.item}>
                             <Avatar sx={chatAvatarSx}>{getInitials(elt.item)}</Avatar>

+ 1 - 1
frontend/taipy-gui/src/utils/index.ts

@@ -206,7 +206,7 @@ export const formatWSValue = (
 export const getInitials = (value: string, max = 2): string =>
     (value || "")
         .split(" ", max)
-        .map((word) => (word.length ? word.charAt(0) : ""))
+        .map((word) => (word.length ? String.fromCodePoint(word.codePointAt(0) || 0) : ""))
         .join("")
         .toUpperCase();
 

+ 7 - 4
pyproject.toml

@@ -1,13 +1,13 @@
 [build-system]
-requires = ["setuptools>=42", "wheel"]
+requires = ["setuptools>=76", "wheel"]
 build-backend = "setuptools.build_meta"
 
 [project]
 name = "taipy"
 description = "A 360° open-source platform from Python pilots to production-ready web apps."
 readme = "package_desc.md"
-requires-python = ">=3.9"
-license = {text = "Apache License 2.0"}
+requires-python = ">=3.9,<3.13"
+license = {text = "Apache-2.0"}
 authors = [{name = "Avaiga", email = "dev@taipy.io"}]
 keywords = ["taipy"]
 classifiers = [
@@ -22,6 +22,9 @@ classifiers = [
 ]
 dynamic = ["version", "dependencies"]
 
+[tool.setuptools.packages]
+find = {include = ["taipy", "taipy.*"]}
+
 [project.optional-dependencies]
 ngrok = ["pyngrok>=5.1,<6.0"]
 image = [
@@ -31,6 +34,7 @@ image = [
 rdp = ["rdp>=0.8"]
 arrow = ["pyarrow>=16.0.0,<19.0"]
 mssql = ["pyodbc>=4"]
+test = ["pytest>=6.0"]
 
 [project.scripts]
 taipy = "taipy._entrypoint:_entrypoint"
@@ -51,7 +55,6 @@ exclude = [
     "build",
     "dist",
     "releases",
-    "tools",
     ".venv",
     ".mypy_cache",
     ".pytest_cache",

+ 19 - 12
taipy/core/common/_check_dependencies.py → taipy/common/_check_dependencies.py

@@ -8,26 +8,33 @@
 # 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 importlib import util
+from typing import Optional
 
 
-def _check_dependency_is_installed(module_name: str, package_name: str) -> None:
+def _check_dependency_is_installed(
+    module_name: str, package_name: str, extra_taipy_package_name: str, taipy_sublibrary: Optional[str] = None
+) -> None:
     """
-        Check if a package is installed.
+    Check if an extra package for taipy is installed.
+
+    Args:
+        module_name: Name of the taipy module importing the package.
+        package_name: Name of the package.
+        extra_taipy_package_name: Name of the extra taipy package.
+        taipy_sublibrary: Optional name of the taipy sublibrary.
 
-        Args:
-            module_name: Name of the taipy module importing the package.
-            package_name: Name of the package.
-    .
+    Raises:
+        RuntimeError: If the package is not installed.
     """
-    extras = {
-        "boto3": "s3",
-        "pymongo": "mongo",
-    }
+    if taipy_sublibrary is None:
+        taipy_sublibrary = "taipy"
+
     if not util.find_spec(package_name):
         raise RuntimeError(
-            f"Cannot use {module_name} as {package_name} package is not installed. Please install it  "
-            f"using `pip install taipy[{extras.get(package_name)}]`."
+            f"Cannot use {module_name} as {package_name} package is not installed. Please install it "
+            f"using `pip install {taipy_sublibrary}[{extra_taipy_package_name}]`."
         )
 
 

+ 1 - 1
taipy/common/_cli/_create_cli_factory.py

@@ -15,7 +15,7 @@ from typing import Type
 
 from taipy.common._cli._base_cli._abstract_cli import _AbstractCLI
 
-from ...core.common._check_dependencies import EnterpriseEditionUtils
+from .._check_dependencies import EnterpriseEditionUtils
 from ._create_cli import _CreateCLI
 
 

+ 1 - 1
taipy/core/_cli/_core_cli_factory.py

@@ -15,7 +15,7 @@ from typing import Type
 
 from taipy.common._cli._base_cli._abstract_cli import _AbstractCLI
 
-from ..common._check_dependencies import EnterpriseEditionUtils
+from ...common._check_dependencies import EnterpriseEditionUtils
 from ._core_cli import _CoreCLI
 
 

+ 1 - 1
taipy/core/_entity/_reload.py

@@ -12,8 +12,8 @@
 import functools
 from typing import Dict, Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager import _Manager
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ..notification import EventOperation, Notifier, _make_event
 

+ 2 - 1
taipy/core/_orchestrator/_orchestrator_factory.py

@@ -8,12 +8,13 @@
 # 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 typing
 from typing import Optional, Type
 
 from taipy.common.config import Config
 
-from ..common._check_dependencies import EnterpriseEditionUtils
+from ...common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ..exceptions.exceptions import ModeNotAvailable, OrchestratorNotBuilt
 from ._abstract_orchestrator import _AbstractOrchestrator

+ 1 - 1
taipy/core/_version/_cli/_version_cli_factory.py

@@ -15,7 +15,7 @@ from typing import Type
 
 from taipy.common._cli._base_cli._abstract_cli import _AbstractCLI
 
-from ...common._check_dependencies import EnterpriseEditionUtils
+from ....common._check_dependencies import EnterpriseEditionUtils
 from ._version_cli import _VersionCLI
 
 

+ 1 - 1
taipy/core/_version/_version_manager_factory.py

@@ -12,9 +12,9 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
 from ..common import _utils
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ._version_fs_repository import _VersionFSRepository
 from ._version_manager import _VersionManager
 

+ 1 - 1
taipy/core/cycle/_cycle_manager_factory.py

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ..cycle._cycle_manager import _CycleManager
 from ._cycle_fs_repository import _CycleFSRepository

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

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._data_fs_repository import _DataFSRepository
 from ._data_manager import _DataManager

+ 2 - 3
taipy/core/data/aws_s3.py

@@ -13,7 +13,7 @@ from datetime import datetime, timedelta
 from importlib import util
 from typing import Any, Dict, List, Optional, Set
 
-from ..common._check_dependencies import _check_dependency_is_installed
+from ...common._check_dependencies import _check_dependency_is_installed
 
 if util.find_spec("boto3"):
     import boto3
@@ -69,7 +69,6 @@ class S3ObjectDataNode(DataNode):
     __AWS_S3_GET_OBJECT_PARAMETERS = "aws_s3_get_object_parameters"
     __AWS_S3_PUT_OBJECT_PARAMETERS = "aws_s3_put_object_parameters"
 
-
     _REQUIRED_PROPERTIES: List[str] = [
         __AWS_ACCESS_KEY_ID,
         __AWS_SECRET_ACCESS_KEY,
@@ -93,7 +92,7 @@ class S3ObjectDataNode(DataNode):
         editor_expiration_date: Optional[datetime] = None,
         properties: Optional[Dict] = None,
     ) -> None:
-        _check_dependency_is_installed("S3 Data Node", "boto3")
+        _check_dependency_is_installed("S3 Data Node", "boto3", "s3")
         if properties is None:
             properties = {}
         required = self._REQUIRED_PROPERTIES

+ 2 - 3
taipy/core/data/mongo.py

@@ -14,8 +14,8 @@ from importlib import util
 from inspect import isclass
 from typing import Any, Dict, List, Optional, Set, Tuple, Union
 
+from ...common._check_dependencies import _check_dependency_is_installed
 from .._version._version_manager_factory import _VersionManagerFactory
-from ..common._check_dependencies import _check_dependency_is_installed
 from ..common.scope import Scope
 
 if util.find_spec("pymongo"):
@@ -84,7 +84,7 @@ class MongoCollectionDataNode(DataNode):
         editor_expiration_date: Optional[datetime] = None,
         properties: Dict = None,
     ) -> None:
-        _check_dependency_is_installed("Mongo Data Node", "pymongo")
+        _check_dependency_is_installed("Mongo Data Node", "pymongo", "mongo")
         if properties is None:
             properties = {}
         required = self._REQUIRED_PROPERTIES
@@ -269,4 +269,3 @@ class MongoCollectionDataNode(DataNode):
             The document dictionary.
         """
         return document_object.__dict__
-

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

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._job_fs_repository import _JobFSRepository
 from ._job_manager import _JobManager

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

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._scenario_fs_repository import _ScenarioFSRepository
 from ._scenario_manager import _ScenarioManager

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

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._sequence_manager import _SequenceManager
 

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

@@ -12,8 +12,8 @@
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._submission_fs_repository import _SubmissionFSRepository
 from ._submission_manager import _SubmissionManager

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

@@ -8,11 +8,12 @@
 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
+
 from functools import lru_cache
 from typing import Type
 
+from ...common._check_dependencies import EnterpriseEditionUtils
 from .._manager._manager_factory import _ManagerFactory
-from ..common._check_dependencies import EnterpriseEditionUtils
 from ..common._utils import _load_fct
 from ._task_fs_repository import _TaskFSRepository
 from ._task_manager import _TaskManager

+ 9 - 9
taipy/gui/pyproject.toml

@@ -1,18 +1,17 @@
 [build-system]
-requires = ["setuptools>=42", "wheel"]
+requires = ["setuptools>=76", "wheel"]
 build-backend = "setuptools.build_meta"
 
 [project]
 name = "taipy-gui"
 description = "Low-code library to create graphical user interfaces on the Web for your Python applications."
 readme = "package_desc.md"
-requires-python = ">=3.9"
-license = {text = "Apache License 2.0"}
+requires-python = ">=3.9,<3.13"
+license = "Apache-2.0"
 authors = [{name = "Avaiga", email = "dev@taipy.io"}]
-keywords = ["taipy-gui"]
+keywords = ["taipy", "gui", "taipy-gui"]
 classifiers = [
     "Intended Audience :: Developers",
-    "License :: OSI Approved :: Apache Software License",
     "Natural Language :: English",
     "Programming Language :: Python :: 3",
     "Programming Language :: Python :: 3.9",
@@ -22,6 +21,9 @@ classifiers = [
 ]
 dynamic = ["version", "dependencies"]
 
+[tool.setuptools.packages]
+find = {include = ["taipy", "taipy.gui", "taipy.gui.*"]}
+
 [project.optional-dependencies]
 ngrok = ["pyngrok>=5.1,<6.0"]
 image = [
@@ -29,9 +31,7 @@ image = [
     "python-magic-bin>=0.4.14,<0.5;platform_system=='Windows'",
 ]
 arrow = ["pyarrow>=16.0.0,<19.0"]
-
-[tool.setuptools.packages]
-find = {include = ["taipy", "taipy.gui", "taipy.gui.*"]}
+test = ["pytest>=6.0"]
 
 [project.urls]
-homepage = "https://github.com/avaiga/taipy"
+Homepage = "https://github.com/Avaiga/taipy"

+ 26 - 23
tools/coverage_check.py

@@ -10,19 +10,20 @@
 # specific language governing permissions and limitations under the License.
 
 import argparse
-import xmltodict
-import sys
 import subprocess
+import sys
+
+import xmltodict
 
 
 def check_total_coverage(coverage_file, threshold=80):
     """Check the total project coverage."""
     with open(coverage_file) as f:
         data = xmltodict.parse(f.read())
-    total_coverage = float(data['coverage']['@line-rate']) * 100
-    print(f"Total Coverage: {total_coverage:.2f}%")
+    total_coverage = float(data["coverage"]["@line-rate"]) * 100
+    print(f"Total Coverage: {total_coverage:.2f}%")  # noqa: T201
     if total_coverage < threshold:
-        print(f"Total project coverage is below {threshold}%: {total_coverage:.2f}%")
+        print(f"Total project coverage is below {threshold}%: {total_coverage:.2f}%")  # noqa: T201
         sys.exit(1)
 
 
@@ -49,56 +50,58 @@ def check_changed_files_coverage(coverage_file, changed_files, threshold=80):
     for file in changed_files:
         if file in files:
             coverage = files[file]
-            print(f"Coverage for {file}: {coverage:.2f}%")
+            print(f"Coverage for {file}: {coverage:.2f}%")  # noqa: T201
             sum_coverage += coverage
             qty += 1
         else:
-            print(f"No coverage data found for {file}")
+            print(f"No coverage data found for {file}")  # noqa: T201
 
     if qty:
-        if sum_coverage/qty < threshold:
-            print(f"Coverage for changed files is below {threshold}%: {sum_coverage/qty:.2f}%")
+        if sum_coverage / qty < threshold:
+            print(f"Coverage for changed files is below {threshold}%: {sum_coverage/qty:.2f}%")  # noqa: T201
             sys.exit(1)
-        print(f"Coverage for changed files: {sum_coverage/qty:.2f}%")
+        print(f"Coverage for changed files: {sum_coverage/qty:.2f}%")  # noqa: T201
     else:
-        print("No file detected to run coverage for.")
+        print("No file detected to run coverage for.")  # noqa: T201
 
 
 def get_changed_files(base_branch):
     """Get the list of changed Python files in the pull request."""
     try:
         result = subprocess.run(
-            ['git', 'diff', '--name-only', f"origin/{base_branch}", '--', '*.py'],
+            ["git", "diff", "--name-only", f"origin/{base_branch}", "--", "*.py"],
             capture_output=True,
             text=True,
             check=True,
         )
         changed_files = [
-            file.replace("taipy/", "") for file in result.stdout.strip().splitlines() if not file.startswith(('tests/', 'tools/'))
+            file.replace("taipy/", "")
+            for file in result.stdout.strip().splitlines()
+            if not file.startswith(("tests/", "tools/"))
         ]
         return changed_files
     except subprocess.CalledProcessError as e:
-        print(f"Error fetching changed files: {e}")
+        print(f"Error fetching changed files: {e}") # noqa: T201
         sys.exit(1)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     parser = argparse.ArgumentParser(description="Coverage check script.")
-    parser.add_argument('command', choices=['check-total', 'check-changed'], help="Command to execute")
-    parser.add_argument('--coverage-file', default='coverage.xml', help="Path to the coverage XML file")
-    parser.add_argument('--threshold', type=float, default=80, help="Coverage threshold percentage")
-    parser.add_argument('--base-branch', help="Base branch for comparing changed files")
+    parser.add_argument("command", choices=["check-total", "check-changed"], help="Command to execute")
+    parser.add_argument("--coverage-file", default="coverage.xml", help="Path to the coverage XML file")
+    parser.add_argument("--threshold", type=float, default=80, help="Coverage threshold percentage")
+    parser.add_argument("--base-branch", help="Base branch for comparing changed files")
 
     args = parser.parse_args()
 
-    if args.command == 'check-total':
+    if args.command == "check-total":
         check_total_coverage(args.coverage_file, args.threshold)
-    elif args.command == 'check-changed':
+    elif args.command == "check-changed":
         if not args.base_branch:
-            print("Error: --base-branch is required for check-changed")
+            print("Error: --base-branch is required for check-changed") # noqa: T201
             sys.exit(1)
         changed_files = get_changed_files(args.base_branch)
         if not changed_files:
-            print("No relevant Python files changed.")
+            print("No relevant Python files changed.") # noqa: T201
             sys.exit(0)
         check_changed_files_coverage(args.coverage_file, changed_files, args.threshold)

+ 5 - 4
tools/gui/generate_pyi.py

@@ -81,9 +81,10 @@ with open(gui_pyi_file, "w", encoding="utf-8") as write_file:
 # Generate Page Builder pyi file (gui/builder/__init__.pyi)
 # ##################################################################################################
 # Types that appear in viselements.json
-from taipy.gui import Icon  # noqa: E402
-from taipy.core import Cycle, DataNode, Job, Scenario  # noqa: E402
-from datetime import datetime
+from datetime import datetime  # noqa: E402, F401
+
+from taipy.core import Cycle, DataNode, Job, Scenario  # noqa: E402, F401
+from taipy.gui import Icon  # noqa: E402, F401
 
 # Read the version
 current_version = "latest"
@@ -187,7 +188,7 @@ def format_as_parameter(property: Dict[str, str], element_name: str):
         elif hasattr(type_desc, "__name__") and type_desc.__name__ not in ["str", "Any"]:
             type = f"Union[{type}, str]"
     except NameError:
-        print(f"WARNING - Couldn't parse type '{type}' in {element_name}.{name}")
+        print(f"WARNING - Couldn't parse type '{type}' in {element_name}.{name}") # noqa: T201
 
     if default_value is None or default_value == "None":
         default_value = " = None"

+ 1 - 1
tools/release/common.py

@@ -20,7 +20,7 @@ import typing as t
 from dataclasses import asdict, dataclass
 from datetime import datetime
 from pathlib import Path
-from functools import total_ordering
+
 import requests