From 7153e5d8de5157bcb26d8a98db2d41f0de77043d Mon Sep 17 00:00:00 2001 From: rdgsllw8 Date: Wed, 26 Mar 2025 12:16:28 -0500 Subject: [PATCH 1/2] --Update and ui-implementation for dynamic execution directory specification by users --- uit/gui_tools/submit.py | 65 ++++++++++++++++++++++++++++++----------- uit/job.py | 9 +++++- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/uit/gui_tools/submit.py b/uit/gui_tools/submit.py index 66cae46..6ee693a 100644 --- a/uit/gui_tools/submit.py +++ b/uit/gui_tools/submit.py @@ -7,9 +7,10 @@ import param import panel as pn -from .file_browser import HpcFileBrowser, create_file_browser, get_js_loading_code, FileSelector +from .file_browser import HpcFileBrowser, create_file_browser, get_js_loading_code from .utils import HpcBase, HpcConfigurable from ..uit import QUEUES +from .file_browser import AsyncHpcPath from ..pbs_script import NODE_TYPES, factors, PbsScript from ..job import PbsJob @@ -74,21 +75,51 @@ class PbsScriptInputs(HpcBase): wall_time_maxes = None node_maxes = None + base_dir = param.Selector( + label="Base Directory", + doc="Base directory that the job's working directory path will be created in.\n\n" + "**Note:** by default the job's working directory is: " + f"`/{PbsJob.DEFAULT_JOB_LABEL}/./`", + ) + use_namespace = param.Boolean(label="Use Namespace Path", default=True) + namespace_path = param.String(label="Namespace Path", doc="Path created within the Base Directory") + execution_dir = param.String(label="Execution Directory", doc="Full Directory path in which job(s) will be run.") + def __init__(self, **params): super().__init__(**params) - self.workdir = FileSelector( - title="Base Directory", - show_browser=False, - help_text=( - "Base directory that the job's working directory path will be created in.\n\n" - "**Note:** by default the job's working directory is: " - f"`/{PbsJob.DEFAULT_JOB_LABEL}/./`" - ), + options = pn.widgets.Button(icon="menu-2", align="center", margin=(15, 0, 0, 0)) + options.on_click(self.toggle_exec_dir_widgets) + self.exec_dir_wg_box = pn.layout.WidgetBox( + self.param.base_dir, self.param.use_namespace, self.param.namespace_path, visible=False ) - @param.depends("uit_client", watch=True) - def set_file_browser(self): - self.workdir.file_browser = create_file_browser(self.uit_client, patterns=[]) + self.execution_dir_col = pn.Column( + pn.Row(pn.widgets.TextInput.from_param(self.param.execution_dir, disabled=True, width=500), options), + self.exec_dir_wg_box, + ) + + # @param.depends("uit_client", watch=True) + async def populate_base_dir_selector(self): + options = {} + if AsyncHpcPath(self.uit_client.WORKDIR, uit_client=self.uit_client).exists(): + options["WORKDIR"] = self.uit_client.WORKDIR + workdir2 = await self.uit_client.env.get_environmental_variable("WORKDIR2") + if workdir2 and AsyncHpcPath(self.uit_client.WORKDIR2, uit_client=self.uit_client).exists(): + options["WORKDIR2"] = self.uit_client.WORKDIR2 + self.param.base_dir.objects = options + self.base_dir = options["WORKDIR"] + + def default_namespace_path(self): + return f"{self.workflow_group}/{self.workflow_name}" + + @param.depends("use_namespace", "base_dir", "namespace_path", watch=True) + def update_job_dir(self): + namespace = self.namespace_path + "/" if self.use_namespace else "" + self.exec_dir_wg_box[-1] = self.param.namespace_path if self.use_namespace else None + self.execution_dir = f"{self.base_dir}/{namespace}./" + + def toggle_exec_dir_widgets(self, _): + self.exec_dir_wg_box.visible = not self.exec_dir_wg_box.visible @staticmethod def get_default(value, objects): @@ -98,14 +129,13 @@ def get_default(value, objects): async def update_hpc_connection_dependent_defaults(self): if not self.uit_client.connected: return - queues_stats = await self.await_if_async(self.uit_client.get_raw_queue_stats()) self.subproject_usage = await self.await_if_async(self.uit_client.show_usage(as_df=True)) subprojects = self.subproject_usage["Subproject"].to_list() self.param.hpc_subproject.objects = subprojects self.hpc_subproject = self.get_default(self.hpc_subproject, subprojects) - self.workdir.file_path = self.uit_client.WORKDIR.as_posix() + await self.populate_base_dir_selector() self.param.node_type.objects = list(NODE_TYPES[self.uit_client.system].keys()) self.node_type = self.get_default(self.node_type, self.param.node_type.objects) self.param.queue.objects = await self.await_if_async(self.uit_client.get_queues()) @@ -119,6 +149,7 @@ async def update_hpc_connection_dependent_defaults(self): ) self.max_wall_time = self.wall_time_maxes[self.queue] self.nodes = round(self.DEFAULT_PROCESSES_PER_JOB / self.processes_per_node) + self.namespace_path = self.default_namespace_path() @param.depends("queue", watch=True) def update_queue_depended_bounds(self): @@ -196,6 +227,7 @@ def add_email_directives(self, pbs_script): if self.notification_email: pbs_script.set_directive("-M", self.notification_email) + @pn.depends("namespace_path", watch=True) def pbs_options_view(self): return pn.Column( pn.Column( @@ -220,8 +252,7 @@ def pbs_options_view(self): ), pn.Column( self.param.hpc_subproject, - self.workdir, - self.param.node_type, + self.execution_dir_col, pn.widgets.Spinner.from_param(self.param.nodes), self.param.processes_per_node, self.param.wall_time, @@ -522,7 +553,7 @@ def job(self): script=self.pbs_script, client=self.uit_client, workspace=self.user_workspace, - base_dir=self.workdir.file_path, + base_dir=self.base_dir, ) return self._job diff --git a/uit/job.py b/uit/job.py index 02251b2..b47023a 100644 --- a/uit/job.py +++ b/uit/job.py @@ -28,9 +28,11 @@ def __init__( home_input_files=None, archive_input_files=None, base_dir=None, + namespace_path=None, description=None, metadata=None, post_processing_script=None, + use_namespace=True, ): self.script = script self.post_processing_script = post_processing_script @@ -52,6 +54,8 @@ def __init__( self._post_processing_job_id = None self._remote_workspace_id = None self._remote_workspace = None + self.use_namespace = use_namespace + self.namespace_path = namespace_path def __repr__(self): return f"<{self.__class__.__name__} name={self.name} id={self.job_id}>" @@ -116,7 +120,10 @@ def remote_workspace_suffix(self): str: Suffix """ if not self._remote_workspace: - self._remote_workspace = PurePosixPath(self.label, f"{self.name}.{self.remote_workspace_id}") + if self.use_namespace: + self._remote_workspace = PurePosixPath(self.namespace_path, f"{self.name}.{self.remote_workspace_id}") + else: + self._remote_workspace = PurePosixPath(f"{self.name}.{self.remote_workspace_id}") return self._remote_workspace @property From 341d22a83feb338c9dab05f335a460faf29fb19d Mon Sep 17 00:00:00 2001 From: rdgsllw8 Date: Wed, 26 Mar 2025 16:17:00 -0500 Subject: [PATCH 2/2] --small style fixes --- uit/gui_tools/submit.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/uit/gui_tools/submit.py b/uit/gui_tools/submit.py index 6ee693a..f49872e 100644 --- a/uit/gui_tools/submit.py +++ b/uit/gui_tools/submit.py @@ -98,7 +98,6 @@ def __init__(self, **params): self.exec_dir_wg_box, ) - # @param.depends("uit_client", watch=True) async def populate_base_dir_selector(self): options = {} if AsyncHpcPath(self.uit_client.WORKDIR, uit_client=self.uit_client).exists(): @@ -227,7 +226,6 @@ def add_email_directives(self, pbs_script): if self.notification_email: pbs_script.set_directive("-M", self.notification_email) - @pn.depends("namespace_path", watch=True) def pbs_options_view(self): return pn.Column( pn.Column(