From 9a2b8cadf38ff08c5e82fcffbbeb2651f5e2684c Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Mon, 7 Aug 2023 18:28:13 +0200 Subject: [PATCH 1/3] fix: don't change folder when new folder is parent of root. closes #862 --- sepal_ui/sepalwidgets/inputs.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/sepal_ui/sepalwidgets/inputs.py b/sepal_ui/sepalwidgets/inputs.py index 51638b69..840162ea 100644 --- a/sepal_ui/sepalwidgets/inputs.py +++ b/sepal_ui/sepalwidgets/inputs.py @@ -52,7 +52,6 @@ reason="Empty v_model will be treated as empty string: :code:`v_model=''`.", ) class DatePicker(v.Layout, SepalWidget): - menu: Optional[v.Menu] = None "the menu widget to display the datepicker" @@ -178,7 +177,6 @@ def is_valid_date(date: str) -> bool: class FileInput(v.Flex, SepalWidget): - extensions: List[str] = [] "list: the extensions list" @@ -330,7 +328,6 @@ def reset(self, *args) -> Self: # do nothing if nothing is set to avoids extremely long waiting # time when multiple fileInput are reset at the same time as in the aoiView if self.v_model is not None: - # move to root self._on_file_select({"new": Path.home()}) @@ -369,7 +366,10 @@ def _on_file_select(self, change: dict) -> Self: if new_value.is_dir(): self.folder = new_value - self._change_folder() + + # don't change folder if the folder is the parent of the root + if not self.folder == Path(self.root).parent: + self._change_folder() elif new_value.is_file(): self.file = str(new_value) @@ -410,7 +410,6 @@ def _get_items(self) -> List[v.ListItem]: file_list = [] for el in list_dir: - if el.is_dir(): icon = self.ICON_STYLE[""]["icon"] color = self.ICON_STYLE[""]["color"][v.theme.dark] @@ -439,10 +438,7 @@ def _get_items(self) -> List[v.ListItem]: folder_list = humansorted(folder_list, key=lambda x: x.value) file_list = humansorted(file_list, key=lambda x: x.value) - folder_list.extend(file_list) - # add the parent item if root is set and is not reached yet - # if root is not set then we always display it parent_item = v.ListItem( value=str(folder.parent), children=[ @@ -459,16 +455,13 @@ def _get_items(self) -> List[v.ListItem]: ), ], ) - root_folder = Path(self.root) - if self.root == "": - folder_list.insert(0, parent_item) - elif root_folder in folder.parents: - folder_list.insert(0, parent_item) + + folder_list.extend(file_list) + folder_list.insert(0, parent_item) return folder_list def _on_reload(self, *args) -> None: - # force the update of the current folder self._change_folder() @@ -484,7 +477,6 @@ def close_menu(self, change: dict) -> None: class LoadTableField(v.Col, SepalWidget): - fileInput: Optional[FileInput] = None "The file input to select the .csv or .txt file" @@ -638,7 +630,6 @@ def _set_v_model(self, key: str, value: Any) -> None: class AssetSelect(v.Combobox, SepalWidget): - TYPES: dict = { "IMAGE": ms.widgets.asset_select.types[0], "TABLE": ms.widgets.asset_select.types[1], @@ -723,7 +714,6 @@ def _validate(self, change: dict) -> None: self.v_model = self.v_model.strip() if change["new"]: - # check that the asset can be accessed try: self.asset_info = ee.data.getAsset(self.v_model) @@ -735,7 +725,6 @@ def _validate(self, change: dict) -> None: ) except Exception: - self.error_messages = ms.widgets.asset_select.no_access self.valid = self.error_messages is None @@ -745,13 +734,11 @@ def _validate(self, change: dict) -> None: @sd.switch("loading", "disabled") def _get_items(self, *args) -> Self: - # init the item list items = [] # add the default values if needed if self.default_asset: - if isinstance(self.default_asset, str): self.default_asset = [self.default_asset] @@ -828,7 +815,6 @@ def _toggle_pwd(self, *args) -> None: class NumberField(v.TextField, SepalWidget): - max_: t.Int = t.Int(10).tag(sync=True) "Maximum selectable number." @@ -879,7 +865,6 @@ def decrement(self, *args) -> None: class VectorField(v.Col, SepalWidget): - original_gdf: Optional[gpd.GeoDataFrame] = None "The originally selected dataframe" From fe4571412346532c84bda8ffc255f4a439bc278f Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Tue, 8 Aug 2023 12:17:00 +0200 Subject: [PATCH 2/3] test: change root folder test --- tests/test_sepalwidgets/test_FileInput.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/test_sepalwidgets/test_FileInput.py b/tests/test_sepalwidgets/test_FileInput.py index 291d3f1d..125198e1 100644 --- a/tests/test_sepalwidgets/test_FileInput.py +++ b/tests/test_sepalwidgets/test_FileInput.py @@ -3,7 +3,6 @@ from pathlib import Path from typing import List -import ipyvuetify as v import pytest from traitlets import Any @@ -170,9 +169,18 @@ def test_root(file_input: sw.FileInput, root_dir: Path) -> None: # set the root to the current folder and reload file_input.root = str(root_dir) file_input._on_reload() - first_title_item = file_input.get_children(klass=v.ListItemTitle)[0] - assert ".. /" not in first_title_item.children[0] + current_items = file_input.file_list + + # Try to go to the parent root folder + root_parent = Path(file_input.root).parent + + file_input._on_file_select({"new": root_parent}) + + new_items = file_input.file_list + + # Assert that trying to go to the parent root folder does not work + assert current_items == new_items return From f7eda5a1507cd3f3a50455e92b92de26b34ef86b Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Tue, 8 Aug 2023 12:20:16 +0200 Subject: [PATCH 3/3] feat: use cache on InputFile widget to improve loading times --- sepal_ui/sepalwidgets/inputs.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sepal_ui/sepalwidgets/inputs.py b/sepal_ui/sepalwidgets/inputs.py index 840162ea..760c9100 100644 --- a/sepal_ui/sepalwidgets/inputs.py +++ b/sepal_ui/sepalwidgets/inputs.py @@ -183,6 +183,9 @@ class FileInput(v.Flex, SepalWidget): folder: Path = Path.home() "the current folder" + initial_folder: Path = Path.home() + "the starting point of the file input" + file: t.Unicode = t.Unicode("").tag(sync=True) "the current file" @@ -221,6 +224,7 @@ def __init__( v_model: str = "", clearable: bool = False, root: Union[str, Path] = "", + cache=False, **kwargs, ) -> None: """Custom input field to select a file in the sepal folders. @@ -235,8 +239,10 @@ def __init__( kwargs: any parameter from a v.Flex abject. If set, 'children' will be overwritten. """ self.extensions = extensions + self.initial_folder = folder self.folder = Path(folder) self.root = str(root) if isinstance(root, Path) else root + self.cache_dirs = {} self.selected_file = v.TextField( readonly=True, @@ -329,7 +335,7 @@ def reset(self, *args) -> Self: # time when multiple fileInput are reset at the same time as in the aoiView if self.v_model is not None: # move to root - self._on_file_select({"new": Path.home()}) + self._on_file_select({"new": self.initial_folder}) # remove v_model self.v_model = "" @@ -406,6 +412,10 @@ def _get_items(self) -> List[v.ListItem]: el for el in list_dir if el.is_dir() or el.suffix in self.extensions ] + if folder in self.cache_dirs: + if self.cache_dirs[folder]["files"] == list_dir: + return self.cache_dirs[folder]["items"] + folder_list = [] file_list = [] @@ -459,6 +469,10 @@ def _get_items(self) -> List[v.ListItem]: folder_list.extend(file_list) folder_list.insert(0, parent_item) + self.cache_dirs.setdefault(folder, {}) + self.cache_dirs[folder]["files"] = list_dir + self.cache_dirs[folder]["items"] = folder_list + return folder_list def _on_reload(self, *args) -> None: