From 0214c5bb742200bb077db5e72c24c1168b03fa05 Mon Sep 17 00:00:00 2001
From: NAUD Maxence <maxence.naud@cea.fr>
Date: Fri, 29 Nov 2024 22:18:50 +0000
Subject: [PATCH] fix: release with python3.8

---
 aidge_core/show_graphview.py           | 17 ++++++++-------
 aidge_core/testing/utils/tree_cache.py | 28 +++++++++++++++++++------
 aidge_core/testing/utils/tree_utils.py | 29 ++++++++++++++++++++------
 3 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/aidge_core/show_graphview.py b/aidge_core/show_graphview.py
index 4f6a29603..14bb6c3e9 100644
--- a/aidge_core/show_graphview.py
+++ b/aidge_core/show_graphview.py
@@ -4,8 +4,9 @@ import builtins
 import aidge_core
 import numpy as np
 from pathlib import Path
+from typing import Any, Dict, List, Optional
 
-def _retrieve_operator_attrs(node : aidge_core.Node) -> dict[str, int, float, bool, None]:
+def _retrieve_operator_attrs(node : aidge_core.Node) -> Dict[str, Optional[Any]]:
     """
     Returns the dictionary containing the attributes of a given Node.
 
@@ -13,7 +14,7 @@ def _retrieve_operator_attrs(node : aidge_core.Node) -> dict[str, int, float, bo
     :type graph: aidge_core.Node
 
     :return: A dictionary with the Node's attributes.
-    :rtype: dict[str, int, float, bool, None]
+    :rtype: Dict[str, Optional[Any]]
     """
 
     if node.get_operator().attr is not None:
@@ -27,7 +28,7 @@ def _retrieve_operator_attrs(node : aidge_core.Node) -> dict[str, int, float, bo
 
     return node_attr_dict
 
-def _create_dict(ordered_nodes : list[aidge_core.Node], write_trainable_params_embed : bool, write_trainable_params_ext : bool, path_trainable_params : Path, params_file_format : str) -> dict[str, int, float, bool, None]:
+def _create_dict(ordered_nodes : List[aidge_core.Node], write_trainable_params_embed : bool, write_trainable_params_ext : bool, path_trainable_params : Path, params_file_format : str) -> Dict[str, Optional[Any]]:
     """
     Creates a dictionary to store the information of a given ordered GraphView.
 
@@ -43,7 +44,7 @@ def _create_dict(ordered_nodes : list[aidge_core.Node], write_trainable_params_e
     :type params_file_format: str
 
     :return: A dictionary with the GraphView description.
-    :rtype: dict[str, int, float, bool, None]
+    :rtype: Dict[str, Optional[Any]]
     """
 
     graphview_dict = {'graph': []}
@@ -79,7 +80,7 @@ def _create_dict(ordered_nodes : list[aidge_core.Node], write_trainable_params_e
                 if parents[0] is None: parents.append(parents.pop(0))
             else:
                 pass
-           
+
             parents_inputs = []
             input_idx = 0
             for parent in node.get_parents():
@@ -88,11 +89,11 @@ def _create_dict(ordered_nodes : list[aidge_core.Node], write_trainable_params_e
                         for child in children:
                             if child[0] == node and child[1] == input_idx:
                                 parents_inputs.append((parent.name(), input_idx))
-                
+
                 elif parent is None:
                     if input_idx not in [item[1] for item in parents_inputs]:
                         parents_inputs.append((None, input_idx))
-                
+
                 input_idx += 1
             node_dict['parents'] = parents_inputs
 
@@ -167,7 +168,7 @@ def _create_dict(ordered_nodes : list[aidge_core.Node], write_trainable_params_e
 
     return graphview_dict
 
-def _write_dict_json(graphview_dict : dict[str, int, float, bool, None], json_path : str) -> None:
+def _write_dict_json(graphview_dict : Dict[str, Optional[Any]], json_path : str) -> None:
     """
     Writes dictionary containing GraphView description to a JSON file.
 
diff --git a/aidge_core/testing/utils/tree_cache.py b/aidge_core/testing/utils/tree_cache.py
index 5b363c7c7..9bb4f7734 100644
--- a/aidge_core/testing/utils/tree_cache.py
+++ b/aidge_core/testing/utils/tree_cache.py
@@ -43,6 +43,7 @@ For more evolved scenarii, specialize the provided FileTreeCache class.
 
 from pathlib import Path
 import shutil
+import sys
 import filecmp
 from typing import Optional, Union, List
 
@@ -54,6 +55,21 @@ __all__ = [
     "tree_update_from_cache",
 ]
 
+def is_relative_to(path: Path, other: Path) -> bool:
+    """
+    Dynamically choose implementation based on Python version
+    """
+    # Python 3.9+
+    if sys.version_info >= (3, 9):
+        return path.is_relative_to(other)
+
+    # Python 3.8 and earlier
+    try:
+        path.relative_to(other)
+        return True
+    except ValueError:
+        return False
+
 
 class FileTreeCache():
     """
@@ -66,8 +82,8 @@ class FileTreeCache():
     default_tmp_prefix = "__tmp_"
 
     def __init__(self,
-                 src_path: Union[str|Path],
-                 cache_path: Optional[Union[str|Path]] = None
+                 src_path: Union[str, Path],
+                 cache_path: Optional[Union[str, Path]] = None
                  ) -> None:
         self.src_path = Path(src_path).absolute()
         self.cache_path = (
@@ -78,7 +94,7 @@ class FileTreeCache():
         )
         ctx_msg = f"tree_cache: {src_path = }, {cache_path = }"
         assert self.src_path != self.cache_path, f"src_path and cache_path must differ on {ctx_msg}"
-        assert not self.src_path.is_relative_to(self.cache_path), f"src_path must not be relative to cache_path on {ctx_msg}"
+        assert not is_relative_to(self.src_path, self.cache_path), f"src_path must not be relative to cache_path on {ctx_msg}"
         self._tmp_path = (
             self.src_path.parent /
             f"{self.default_tmp_prefix}{self.src_path.name}")
@@ -92,7 +108,7 @@ class FileTreeCache():
         assert not dst_cache_dir.exists()
         assert src_dir.is_dir()
         assert not cache_dir.exists() or cache_dir.is_dir()
-        assert not cache_dir.is_relative_to(src_dir)
+        assert not is_relative_to(cache_dir, src_dir)
 
         def copy_or_cache(src, dst):
             base_src = Path(src).relative_to(src_dir)
@@ -132,8 +148,8 @@ class FileTreeCache():
 
 
 def tree_update_from_cache(
-        src_path: Union[str|Path],
-        cache_path: Optional[Union[str|Path]] = None) -> None:
+        src_path: Union[str, Path],
+        cache_path: Optional[Union[str, Path]] = None) -> None:
     """
     Update from cache the current generation of a tree from the
     older generations, preserving file stamps when files contents are identical.
diff --git a/aidge_core/testing/utils/tree_utils.py b/aidge_core/testing/utils/tree_utils.py
index 3a6b2aad8..990ab2641 100644
--- a/aidge_core/testing/utils/tree_utils.py
+++ b/aidge_core/testing/utils/tree_utils.py
@@ -5,8 +5,9 @@ Provide utility function for file trees manipulations.
 """
 
 import shutil
+import sys
 from pathlib import Path
-from typing import Union, Optional
+from typing import Union
 
 
 __all__ = [
@@ -15,8 +16,24 @@ __all__ = [
 ]
 
 
+def is_relative_to(path: Path, other: Path) -> bool:
+    """
+    Dynamically choose implementation based on Python version
+    """
+    # Python 3.9+
+    if sys.version_info >= (3, 9):
+        return path.is_relative_to(other)
+
+    # Python 3.8 and earlier
+    try:
+        path.relative_to(other)
+        return True
+    except ValueError:
+        return False
+
+
 def tree_remove(
-        path: Union[str|Path],
+        path: Union[str, Path],
         ignore_missing: bool = False,
 ) -> None:
     """
@@ -35,8 +52,8 @@ def tree_remove(
 
 
 def tree_move(
-        src_path: Union[str|Path],
-        dst_path: Union[str|Path],
+        src_path: Union[str, Path],
+        dst_path: Union[str, Path],
         ignore_missing: bool = False,
         exist_ok: bool = False,
 ) -> None:
@@ -56,8 +73,8 @@ def tree_move(
     assert ignore_missing or src_path.exists(), f"src_path must exists when ignore_missing is False on {ctx_msg}"
     assert exist_ok or not dst_path.exists(), f"dst_path must not exists when exist_ok is False on {ctx_msg}"
     assert src_path != dst_path, f"paths must not be identical on {ctx_msg}"
-    assert not dst_path.is_relative_to(src_path), f"dst_path must not be relative to src_path on {ctx_msg}"
-    assert not src_path.is_relative_to(dst_path), f"src_path must not be relative to dst_path on {ctx_msg}"
+    assert not is_relative_to(dst_path, src_path), f"dst_path must not be relative to src_path on {ctx_msg}"
+    assert not is_relative_to(src_path, dst_path), f"src_path must not be relative to dst_path on {ctx_msg}"
     if ignore_missing and not src_path.exists():
         return
     if exist_ok and dst_path.exists():
-- 
GitLab