Commit 9114b860 authored by Duggan, John's avatar Duggan, John
Browse files

Inherit the DataSelector model properly

parent 512f75a7
Loading
Loading
Loading
Loading
Loading
+21 −14
Original line number Diff line number Diff line
@@ -20,8 +20,9 @@ class DataSelectorState(BaseModel, validate_assignment=True):
class DataSelectorModel:
    """Manages file system interactions for the DataSelector widget."""

    def __init__(self, directory: str, extensions: List[str], prefix: str) -> None:
        self.state = DataSelectorState()
    def __init__(self, state: DataSelectorState, directory: str, extensions: List[str], prefix: str) -> None:
        self.state: DataSelectorState = state

        self.state.directory = directory
        self.state.extensions = extensions
        self.state.prefix = prefix
@@ -37,15 +38,7 @@ class DataSelectorModel:

        return sorted_dirs

    def get_directories(self, base_path: Optional[Path] = None) -> List[Dict[str, Any]]:
        if base_path:
            pass
        else:
            base_path = Path(self.state.directory)

        if not base_path:
            return []

    def get_directories_from_path(self, base_path: Path) -> List[Dict[str, Any]]:
        directories = []
        try:
            for dirpath, dirs, _ in os.walk(base_path):
@@ -78,10 +71,19 @@ class DataSelectorModel:

        return self.sort_directories(directories)

    def get_datafiles(self) -> List[str]:
        datafiles = []

    def get_directories(self, base_path: Optional[Path] = None) -> List[Dict[str, Any]]:
        if base_path:
            pass
        else:
            base_path = Path(self.state.directory)

        if not base_path:
            return []

        return self.get_directories_from_path(base_path)

    def get_datafiles_from_path(self, base_path: Path) -> List[str]:
        datafiles = []
        try:
            if self.state.prefix:
                datafile_path = base_path / self.state.prefix
@@ -101,5 +103,10 @@ class DataSelectorModel:

        return natsorted(datafiles)

    def get_datafiles(self) -> List[str]:
        base_path = Path(self.state.directory)

        return self.get_datafiles_from_path(base_path)

    def set_subdirectory(self, subdirectory_path: str) -> None:
        self.state.subdirectory = subdirectory_path
+17 −73
Original line number Diff line number Diff line
@@ -6,9 +6,11 @@ from typing import Any, Dict, List, Optional
from warnings import warn

from natsort import natsorted
from pydantic import BaseModel, Field, field_validator, model_validator
from pydantic import Field, field_validator, model_validator
from typing_extensions import Self

from ..data_selector import DataSelectorModel, DataSelectorState

CUSTOM_DIRECTORIES_LABEL = "Custom Directory"

INSTRUMENTS = {
@@ -57,7 +59,7 @@ INSTRUMENTS = {
}


class NeutronDataSelectorState(BaseModel, validate_assignment=True):
class NeutronDataSelectorState(DataSelectorState):
    """Selection state for identifying datafiles."""

    allow_custom_directories: bool = Field(default=False)
@@ -65,9 +67,6 @@ class NeutronDataSelectorState(BaseModel, validate_assignment=True):
    instrument: str = Field(default="", title="Instrument")
    experiment: str = Field(default="", title="Experiment")
    custom_directory: str = Field(default="", title="Custom Directory")
    directory: str = Field(default="")
    extensions: List[str] = Field(default=[])
    prefix: str = Field(default="")

    @field_validator("experiment", mode="after")
    @classmethod
@@ -105,13 +104,21 @@ class NeutronDataSelectorState(BaseModel, validate_assignment=True):
        return list(INSTRUMENTS.get(self.facility, {}).keys())


class NeutronDataSelectorModel:
class NeutronDataSelectorModel(DataSelectorModel):
    """Manages file system interactions for the DataSelector widget."""

    def __init__(
        self, facility: str, instrument: str, extensions: List[str], prefix: str, allow_custom_directories: bool
        self,
        state: NeutronDataSelectorState,
        facility: str,
        instrument: str,
        extensions: List[str],
        prefix: str,
        allow_custom_directories: bool,
    ) -> None:
        self.state = NeutronDataSelectorState()
        super().__init__(state, "", extensions, prefix)
        self.state: NeutronDataSelectorState = state

        self.state.facility = facility
        self.state.instrument = instrument
        self.state.extensions = extensions
@@ -140,17 +147,6 @@ class NeutronDataSelectorModel:

        return natsorted(experiments)

    def sort_directories(self, directories: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        # Sort the current level of dictionaries
        sorted_dirs = natsorted(directories, key=lambda x: x["title"])

        # Process each sorted item to sort their children
        for item in sorted_dirs:
            if "children" in item and isinstance(item["children"], list):
                item["children"] = self.sort_directories(item["children"])

        return sorted_dirs

    def get_experiment_directory_path(self) -> Optional[Path]:
        if not self.state.experiment:
            return None
@@ -176,41 +172,9 @@ class NeutronDataSelectorModel:
        if not base_path:
            return []

        directories = []
        try:
            for dirpath, dirs, _ in os.walk(base_path):
                # Get the relative path from the start path
                path_parts = os.path.relpath(dirpath, base_path).split(os.sep)

                if len(path_parts) > 1:
                    dirs.clear()

                # Only create a new entry for top-level directories
                if len(path_parts) == 1 and path_parts[0] != ".":  # This indicates a top-level directory
                    current_dir = {"path": dirpath, "title": path_parts[0]}
                    directories.append(current_dir)

                # Add subdirectories to the corresponding parent directory
                elif len(path_parts) > 1:
                    current_level: Any = directories
                    for part in path_parts[:-1]:  # Parent directories
                        for item in current_level:
                            if item["title"] == part:
                                if "children" not in item:
                                    item["children"] = []
                                current_level = item["children"]
                                break

                    # Add the last part (current directory) as a child
                    current_level.append({"path": dirpath, "title": path_parts[-1]})
        except OSError:
            pass

        return self.sort_directories(directories)
        return self.get_directories_from_path(base_path)

    def get_datafiles(self) -> List[str]:
        datafiles = []

        if self.state.experiment:
            base_path = Path("/") / self.state.facility / self.get_instrument_dir() / self.state.experiment
        elif self.state.custom_directory:
@@ -218,27 +182,7 @@ class NeutronDataSelectorModel:
        else:
            return []

        try:
            if self.state.prefix:
                datafile_path = str(base_path / self.state.prefix)
            else:
                datafile_path = str(base_path / self.state.directory)

            for entry in os.scandir(datafile_path):
                if entry.is_file():
                    if self.state.extensions:
                        for extension in self.state.extensions:
                            if entry.path.lower().endswith(extension):
                                datafiles.append(entry.path)
                    else:
                        datafiles.append(entry.path)
        except OSError:
            pass

        return natsorted(datafiles)

    def set_directory(self, directory_path: str) -> None:
        self.state.directory = directory_path
        return self.get_datafiles_from_path(base_path)

    def set_state(self, facility: Optional[str], instrument: Optional[str], experiment: Optional[str]) -> None:
        if facility is not None:
+3 −2
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ from trame.widgets import client, datagrid, html
from trame.widgets import vuetify3 as vuetify

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.model.data_selector import DataSelectorModel
from nova.trame.model.data_selector import DataSelectorModel, DataSelectorState
from nova.trame.view.layouts import GridLayout, VBoxLayout
from nova.trame.view_model.data_selector import DataSelectorViewModel

@@ -163,7 +163,8 @@ class DataSelector(datagrid.VGrid):
                    )

    def create_model(self, directory: str) -> None:
        self._model = DataSelectorModel(directory, self._extensions, self._prefix)
        state = DataSelectorState()
        self._model = DataSelectorModel(state, directory, self._extensions, self._prefix)

    def create_viewmodel(self) -> None:
        server = get_server(None, client_type="vue3")
+8 −3
Original line number Diff line number Diff line
@@ -8,7 +8,11 @@ from trame.widgets import client, datagrid, html
from trame.widgets import vuetify3 as vuetify

from nova.mvvm.trame_binding import TrameBinding
from nova.trame.model.ornl.neutron_data_selector import CUSTOM_DIRECTORIES_LABEL, NeutronDataSelectorModel
from nova.trame.model.ornl.neutron_data_selector import (
    CUSTOM_DIRECTORIES_LABEL,
    NeutronDataSelectorModel,
    NeutronDataSelectorState,
)
from nova.trame.view.layouts import GridLayout, VBoxLayout
from nova.trame.view_model.ornl.neutron_data_selector import NeutronDataSelectorViewModel

@@ -137,7 +141,7 @@ class NeutronDataSelector(datagrid.VGrid):
                            item_value="path",
                            items=(self._directories_name,),
                            click_open=(self._vm.expand_directory, "[$event.path]"),
                            update_activated=(self._vm.set_directory, "$event"),
                            update_activated=(self._vm.set_subdirectory, "$event"),
                        )
                        vuetify.VListItem("No directories found", classes="flex-0-1 text-center", v_else=True)

@@ -199,8 +203,9 @@ class NeutronDataSelector(datagrid.VGrid):
                    )

    def create_model(self, facility: str, instrument: str) -> None:
        state = NeutronDataSelectorState()
        self._model = NeutronDataSelectorModel(
            facility, instrument, self._extensions, self._prefix, self._allow_custom_directories
            state, facility, instrument, self._extensions, self._prefix, self._allow_custom_directories
        )

    def create_viewmodel(self) -> None:
+3 −3
Original line number Diff line number Diff line
@@ -50,8 +50,8 @@ class NeutronDataSelectorViewModel:
        self.expanded.append(paths[-1])
        self.directories_bind.update_in_view(self.directories)

    def set_directory(self, directory_path: str = "") -> None:
        self.model.set_directory(directory_path)
    def set_subdirectory(self, subdirectory_path: str = "") -> None:
        self.model.set_subdirectory(subdirectory_path)
        self.update_view()

    def set_state(self, facility: Optional[str], instrument: Optional[str], experiment: Optional[str]) -> None:
@@ -59,7 +59,7 @@ class NeutronDataSelectorViewModel:
        self.update_view()

    def reset(self) -> None:
        self.model.set_directory("")
        self.model.set_subdirectory("")
        self.directories = self.model.get_directories()
        self.expanded = []
        self.reset_bind.update_in_view(None)