From eb16b953c32f0916c939d85d52b5495390a4a46d Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Tue, 24 Oct 2023 13:35:22 -0700 Subject: [PATCH 01/13] ENH: Add option for PyDMShellCommand to run commands through bash --- examples/shell_command/shell_command.ui | 41 +++++++++++++++++++++++++ pydm/widgets/shell_command.py | 33 +++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/examples/shell_command/shell_command.ui b/examples/shell_command/shell_command.ui index 1acbfd9ba..89b6294dc 100644 --- a/examples/shell_command/shell_command.ui +++ b/examples/shell_command/shell_command.ui @@ -41,17 +41,58 @@ Run Shell Command + + false + + + true + + + + + + + + + false + + + false + + + Are you sure you want to proceed? + + + + + + true + true false + + + echo "Hello World!" + echo AAA; echo BBB + bash -c 'echo AAA; echo BBB' + + false + + + + + + + diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index b50c6810e..3bddd0027 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -68,6 +68,9 @@ def __init__( self.process = None self._show_icon = True self._redirect_output = False + # atm this is mainly to allow for command chaining ("cmd1;cmd2", "cmd1 && cmd2" etc ...), + # which Popen doesn't allow without enabling bash. + self._run_cmds_in_bash = False self._password_protected = False self._password = "" @@ -126,6 +129,29 @@ def showConfirmDialog(self, value: bool) -> None: if self._show_confirm_dialog != value: self._show_confirm_dialog = value + @Property(bool) + def runCommandsInBash(self) -> bool: + """ + Wether or not to run shell cmds with Popen's option to run them in a bash shell. + + Returns + ------- + bool + """ + return self._run_cmds_in_bash + + @runCommandsInBash.setter + def runCommandsInBash(self, value: bool) -> None: + """ + Wether or not to run shell cmds with Popen's option to run them in a bash shell. + + Parameters + ---------- + value : bool + """ + if self._run_cmds_in_bash != value: + self._run_cmds_in_bash = value + @Property(str) def confirmMessage(self) -> str: """ @@ -526,6 +552,9 @@ def execute_command(self, command: str) -> None: if (self.process is None or self.process.poll() is not None) or self._allow_multiple: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) + # when using bash Popen doesn't take the cmd in a list + if self._run_cmds_in_bash: + args = cmd try: logger.debug("Launching process: %s", repr(args)) stdout = subprocess.PIPE @@ -537,7 +566,9 @@ def execute_command(self, command: str) -> None: if self._redirect_output: stdout = None - self.process = subprocess.Popen(args, stdout=stdout, stderr=subprocess.PIPE, env=env_var) + self.process = subprocess.Popen( + args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_bash + ) except Exception as exc: self.show_warning_icon() logger.error("Error in shell command: %s", exc) From 36fb677b0998206a84e9fee0dcb2e4a75e5316ae Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Tue, 24 Oct 2023 14:16:27 -0700 Subject: [PATCH 02/13] WIP: Add files for testing multistate led widget --- examples/shell_command/example_cmd.sh | 2 + examples/shell_command/shell_command_bash.ui | 256 +++++++++++++++++++ pydm/tests/widgets/test_multistate_led.py | 52 ++++ 3 files changed, 310 insertions(+) create mode 100755 examples/shell_command/example_cmd.sh create mode 100644 examples/shell_command/shell_command_bash.ui create mode 100644 pydm/tests/widgets/test_multistate_led.py diff --git a/examples/shell_command/example_cmd.sh b/examples/shell_command/example_cmd.sh new file mode 100755 index 000000000..6fee82af9 --- /dev/null +++ b/examples/shell_command/example_cmd.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Hello World!" && echo "Hello Again!" diff --git a/examples/shell_command/shell_command_bash.ui b/examples/shell_command/shell_command_bash.ui new file mode 100644 index 000000000..b3d5bced1 --- /dev/null +++ b/examples/shell_command/shell_command_bash.ui @@ -0,0 +1,256 @@ + + + Form + + + + 0 + 0 + 379 + 358 + + + + Form + + + + + + + 0 + 0 + + + + The PyDMShellCommand button with run your command through a Bash shell if you enable the "runCommandsInBash" option. + + + true + + + + + + + + + + + + + Bash Option Enabled + + + false + + + true + + + + + + + + + false + + + true + + + Are you sure you want to proceed? + + + + + + true + + + true + + + false + + + + + + + bash -c 'echo AAA; echo BBB' + + + + false + + + + + + + + + + + + + You also can run through Bash (without needing to enable the option) by specifying "bash -c" at the start of your command or by having the shell command call a script the runs multiple commands. + + + true + + + + + + + + + + + + + Using "-c bash" + + + false + + + true + + + + + + + + + false + + + false + + + Are you sure you want to proceed? + + + + + + true + + + false + + + false + + + + + + + bash -c 'echo Hello World! ; echo Hello Again!' + + + + false + + + + + + + + + + + + + + + + Calling external script + + + false + + + true + + + + + + + + + false + + + false + + + Are you sure you want to proceed? + + + + + + true + + + true + + + false + + + + Print "Hello, World!" to terminal + Print current working directory to terminal + + + + + ./example_cmd.sh + + + + false + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + PyDMShellCommand + QPushButton +
pydm.widgets.shell_command
+
+
+ + +
diff --git a/pydm/tests/widgets/test_multistate_led.py b/pydm/tests/widgets/test_multistate_led.py new file mode 100644 index 000000000..4e25238bc --- /dev/null +++ b/pydm/tests/widgets/test_multistate_led.py @@ -0,0 +1,52 @@ +import pytest + +from qtpy.QtGui import QColor +from qtpy.QtCore import Qt +from ...widgets.byte import PyDMMultiStateLEDIndicator + + +@pytest.mark.parametrize( + "value, expectedColor", + [ + (0, QColor(Qt.black)), + (4, QColor(Qt.red)), + (7, QColor(Qt.darkGreen)), + (15, QColor(Qt.yellow)), + ], +) +def test_state_change(qtbot, signals, value, expectedColor): + """ + Test the widget's handling of the value changed event. + + Expectations: + 1. Value coming from the control system is correctly shifted by the predefined value + 2. Resulting value should be non-negative + + Parameters + ---------- + qtbot : fixture + pytest-qt window for widget testing + signals : fixture + The signals fixture, which provides access signals to be bound to the appropriate slots + value : int + The value to be displayed by the widget + shift : int + The value's bit shift + expected : int + Expected resulting value + """ + pydm_multistate = PyDMMultiStateLEDIndicator() + qtbot.addWidget(pydm_multistate) + pydm_multistate.show() + + pydm_multistate.state4Color = QColor(Qt.red) + pydm_multistate.state7Color = QColor(Qt.darkGreen) + pydm_multistate.state15Color = QColor(Qt.yellow) + + pydm_multistate._connected = True + + signals.new_value_signal[type(value)].connect(pydm_multistate.channelValueChanged) + signals.new_value_signal[type(value)].emit(value) + + assert pydm_multistate._curr_state == value + assert pydm_multistate._curr_color == expectedColor From 7623623ed4e6a00d199a36ee00731de2fcfff7bb Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Tue, 24 Oct 2023 14:45:38 -0700 Subject: [PATCH 03/13] WIP: remove files accidently added for shell-command bash option --- examples/shell_command/shell_command.ui | 41 ------------------ pydm/tests/widgets/test_multistate_led.py | 52 ----------------------- 2 files changed, 93 deletions(-) delete mode 100644 pydm/tests/widgets/test_multistate_led.py diff --git a/examples/shell_command/shell_command.ui b/examples/shell_command/shell_command.ui index 89b6294dc..1acbfd9ba 100644 --- a/examples/shell_command/shell_command.ui +++ b/examples/shell_command/shell_command.ui @@ -41,58 +41,17 @@ Run Shell Command - - false - - - true - - - - - - - - - false - - - false - - - Are you sure you want to proceed? - - - - - - true - true false - - - echo "Hello World!" - echo AAA; echo BBB - bash -c 'echo AAA; echo BBB' - - false - - - - - - -
diff --git a/pydm/tests/widgets/test_multistate_led.py b/pydm/tests/widgets/test_multistate_led.py deleted file mode 100644 index 4e25238bc..000000000 --- a/pydm/tests/widgets/test_multistate_led.py +++ /dev/null @@ -1,52 +0,0 @@ -import pytest - -from qtpy.QtGui import QColor -from qtpy.QtCore import Qt -from ...widgets.byte import PyDMMultiStateLEDIndicator - - -@pytest.mark.parametrize( - "value, expectedColor", - [ - (0, QColor(Qt.black)), - (4, QColor(Qt.red)), - (7, QColor(Qt.darkGreen)), - (15, QColor(Qt.yellow)), - ], -) -def test_state_change(qtbot, signals, value, expectedColor): - """ - Test the widget's handling of the value changed event. - - Expectations: - 1. Value coming from the control system is correctly shifted by the predefined value - 2. Resulting value should be non-negative - - Parameters - ---------- - qtbot : fixture - pytest-qt window for widget testing - signals : fixture - The signals fixture, which provides access signals to be bound to the appropriate slots - value : int - The value to be displayed by the widget - shift : int - The value's bit shift - expected : int - Expected resulting value - """ - pydm_multistate = PyDMMultiStateLEDIndicator() - qtbot.addWidget(pydm_multistate) - pydm_multistate.show() - - pydm_multistate.state4Color = QColor(Qt.red) - pydm_multistate.state7Color = QColor(Qt.darkGreen) - pydm_multistate.state15Color = QColor(Qt.yellow) - - pydm_multistate._connected = True - - signals.new_value_signal[type(value)].connect(pydm_multistate.channelValueChanged) - signals.new_value_signal[type(value)].emit(value) - - assert pydm_multistate._curr_state == value - assert pydm_multistate._curr_color == expectedColor From e878eb12ccf879ab88c35398146344a517352a46 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Tue, 24 Oct 2023 14:51:23 -0700 Subject: [PATCH 04/13] STY: minor style updates for adding shell-cmd bash mode --- examples/shell_command/example_cmd.sh | 3 +++ pydm/widgets/shell_command.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/shell_command/example_cmd.sh b/examples/shell_command/example_cmd.sh index 6fee82af9..b2be4133c 100755 --- a/examples/shell_command/example_cmd.sh +++ b/examples/shell_command/example_cmd.sh @@ -1,2 +1,5 @@ #!/bin/sh + +# This script can be called by a PyDMShellCommand widget, +# so it can use command chaining and other Bash features. echo "Hello World!" && echo "Hello Again!" diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index 3bddd0027..bf43a7d75 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -68,8 +68,8 @@ def __init__( self.process = None self._show_icon = True self._redirect_output = False - # atm this is mainly to allow for command chaining ("cmd1;cmd2", "cmd1 && cmd2" etc ...), - # which Popen doesn't allow without enabling bash. + # currently Bash is used to allow for command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...), + # since Popen doesn't allow for this without enabling bash. self._run_cmds_in_bash = False self._password_protected = False @@ -552,7 +552,7 @@ def execute_command(self, command: str) -> None: if (self.process is None or self.process.poll() is not None) or self._allow_multiple: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) - # when using bash Popen doesn't take the cmd in a list + # when bash enabled, Popen takes the cmds as a single string (not list) if self._run_cmds_in_bash: args = cmd try: From 03ddcb00c113990621a54b9bf1945678a25a2534 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Thu, 26 Oct 2023 12:18:54 -0700 Subject: [PATCH 05/13] ENH: Finish adding example for shellcmd enable-bash option --- examples/shell_command/shell_command_bash.ui | 6 +++--- pydm/widgets/shell_command.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/shell_command/shell_command_bash.ui b/examples/shell_command/shell_command_bash.ui index b3d5bced1..a833d9cfd 100644 --- a/examples/shell_command/shell_command_bash.ui +++ b/examples/shell_command/shell_command_bash.ui @@ -79,7 +79,7 @@ - bash -c 'echo AAA; echo BBB' + echo Fist; echo Second @@ -142,7 +142,7 @@ true - false + true false @@ -152,7 +152,7 @@ - bash -c 'echo Hello World! ; echo Hello Again!' + bash -c "echo 'Hello One'; echo 'Hello two'" diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index bf43a7d75..b6f274d10 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -68,8 +68,7 @@ def __init__( self.process = None self._show_icon = True self._redirect_output = False - # currently Bash is used to allow for command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...), - # since Popen doesn't allow for this without enabling bash. + # Bash allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...) self._run_cmds_in_bash = False self._password_protected = False @@ -566,9 +565,11 @@ def execute_command(self, command: str) -> None: if self._redirect_output: stdout = None + self.process = subprocess.Popen( args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_bash ) + except Exception as exc: self.show_warning_icon() logger.error("Error in shell command: %s", exc) From c1ead7055e19367c61b3b21c53b3801fbb28d160 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Thu, 26 Oct 2023 12:29:31 -0700 Subject: [PATCH 06/13] STY: Minor style update for shellCmd enable-bash option --- pydm/widgets/shell_command.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index b6f274d10..61067537d 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -551,7 +551,7 @@ def execute_command(self, command: str) -> None: if (self.process is None or self.process.poll() is not None) or self._allow_multiple: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) - # when bash enabled, Popen takes the cmds as a single string (not list) + # when Bash enabled, Popen takes the cmds as a single string (not list) if self._run_cmds_in_bash: args = cmd try: @@ -565,7 +565,6 @@ def execute_command(self, command: str) -> None: if self._redirect_output: stdout = None - self.process = subprocess.Popen( args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_bash ) From 61bc8fbc7a88bf415fdd00655aa6ef99114417d4 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Thu, 26 Oct 2023 12:33:15 -0700 Subject: [PATCH 07/13] STY: minor change to comment in enable-bash example --- examples/shell_command/example_cmd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/shell_command/example_cmd.sh b/examples/shell_command/example_cmd.sh index b2be4133c..e8ead38b8 100755 --- a/examples/shell_command/example_cmd.sh +++ b/examples/shell_command/example_cmd.sh @@ -1,5 +1,5 @@ #!/bin/sh # This script can be called by a PyDMShellCommand widget, -# so it can use command chaining and other Bash features. +# allowing it to make use of command chaining and other Bash features. echo "Hello World!" && echo "Hello Again!" From 1d25fa18e991715d6edf46d585db1fee0df468ad Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Thu, 26 Oct 2023 12:39:16 -0700 Subject: [PATCH 08/13] STY: minor spelling fix in shellCmd --- pydm/widgets/shell_command.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index 61067537d..ee21f532e 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -108,7 +108,7 @@ def confirmDialog(self) -> bool: @Property(bool) def showConfirmDialog(self) -> bool: """ - Wether or not to display a confirmation dialog. + Whether or not to display a confirmation dialog. Returns ------- @@ -119,7 +119,7 @@ def showConfirmDialog(self) -> bool: @showConfirmDialog.setter def showConfirmDialog(self, value: bool) -> None: """ - Wether or not to display a confirmation dialog. + Whether or not to display a confirmation dialog. Parameters ---------- @@ -131,7 +131,7 @@ def showConfirmDialog(self, value: bool) -> None: @Property(bool) def runCommandsInBash(self) -> bool: """ - Wether or not to run shell cmds with Popen's option to run them in a bash shell. + Whether or not to run shell cmds with Popen's option to run them through a bash shell. Returns ------- @@ -142,7 +142,7 @@ def runCommandsInBash(self) -> bool: @runCommandsInBash.setter def runCommandsInBash(self, value: bool) -> None: """ - Wether or not to run shell cmds with Popen's option to run them in a bash shell. + Whether or not to run shell cmds with Popen's option to run them in through a bash shell. Parameters ---------- From fa1c64588c3d699a008e7b84be35bff5ff0543d2 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Thu, 26 Oct 2023 12:40:05 -0700 Subject: [PATCH 09/13] STY: another minor spelling fix in shellCmd --- pydm/widgets/shell_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index ee21f532e..8d39cfd81 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -142,7 +142,7 @@ def runCommandsInBash(self) -> bool: @runCommandsInBash.setter def runCommandsInBash(self, value: bool) -> None: """ - Whether or not to run shell cmds with Popen's option to run them in through a bash shell. + Whether or not to run shell cmds with Popen's option to run them through a bash shell. Parameters ---------- From eb5d68bed98e9ff56ea62df599e74bfcc5d2f418 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Fri, 3 Nov 2023 10:48:25 -0700 Subject: [PATCH 10/13] STY: update shellcmd shell=true option variables to not explicity reference Bash Since shell=true does not necessarily run cmds through a Bash shell always --- examples/shell_command/example_cmd.sh | 2 +- examples/shell_command/shell_command_bash.ui | 20 ++++++++-------- pydm/widgets/shell_command.py | 24 ++++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/shell_command/example_cmd.sh b/examples/shell_command/example_cmd.sh index e8ead38b8..ff250de46 100755 --- a/examples/shell_command/example_cmd.sh +++ b/examples/shell_command/example_cmd.sh @@ -1,5 +1,5 @@ #!/bin/sh # This script can be called by a PyDMShellCommand widget, -# allowing it to make use of command chaining and other Bash features. +# allowing it to make use of command chaining and other shell features. echo "Hello World!" && echo "Hello Again!" diff --git a/examples/shell_command/shell_command_bash.ui b/examples/shell_command/shell_command_bash.ui index a833d9cfd..7653570c6 100644 --- a/examples/shell_command/shell_command_bash.ui +++ b/examples/shell_command/shell_command_bash.ui @@ -39,7 +39,7 @@ - Bash Option Enabled + runCmdsInFullShell Option Enabled false @@ -56,9 +56,6 @@ false - - true - Are you sure you want to proceed? @@ -91,6 +88,9 @@ + + true + @@ -129,9 +129,6 @@ false - - false - Are you sure you want to proceed? @@ -164,6 +161,9 @@ + + false + @@ -189,9 +189,6 @@ false - - false - Are you sure you want to proceed? @@ -227,6 +224,9 @@ + + false + diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index 8d39cfd81..82b958f2e 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -68,8 +68,8 @@ def __init__( self.process = None self._show_icon = True self._redirect_output = False - # Bash allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...) - self._run_cmds_in_bash = False + # shell allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...) + self._run_cmds_in_full_shell = False self._password_protected = False self._password = "" @@ -129,27 +129,27 @@ def showConfirmDialog(self, value: bool) -> None: self._show_confirm_dialog = value @Property(bool) - def runCommandsInBash(self) -> bool: + def runCommandsInFullShell(self) -> bool: """ - Whether or not to run shell cmds with Popen's option to run them through a bash shell. + Whether or not to run cmds with Popen's option for running them through a shell subprocess. Returns ------- bool """ - return self._run_cmds_in_bash + return self._run_cmds_in_full_shell - @runCommandsInBash.setter - def runCommandsInBash(self, value: bool) -> None: + @runCommandsInFullShell.setter + def runCommandsInFullShell(self, value: bool) -> None: """ - Whether or not to run shell cmds with Popen's option to run them through a bash shell. + Whether or not to run cmds with Popen's option for running them through a shell subprocess. Parameters ---------- value : bool """ - if self._run_cmds_in_bash != value: - self._run_cmds_in_bash = value + if self._run_cmds_in_full_shell != value: + self._run_cmds_in_full_shell = value @Property(str) def confirmMessage(self) -> str: @@ -552,7 +552,7 @@ def execute_command(self, command: str) -> None: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) # when Bash enabled, Popen takes the cmds as a single string (not list) - if self._run_cmds_in_bash: + if self._run_cmds_in_full_shell: args = cmd try: logger.debug("Launching process: %s", repr(args)) @@ -566,7 +566,7 @@ def execute_command(self, command: str) -> None: if self._redirect_output: stdout = None self.process = subprocess.Popen( - args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_bash + args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_full_shell ) except Exception as exc: From 583af7e4b83257465ea189d15eb9877fff6185e8 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Fri, 3 Nov 2023 15:39:31 -0700 Subject: [PATCH 11/13] STY: for shellcmd widget, add comments on more features with shell, update example labels to provide more info --- ...and_bash.ui => shell_command_full_shell.ui} | 18 ++++++++++++++---- pydm/widgets/shell_command.py | 11 ++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) rename examples/shell_command/{shell_command_bash.ui => shell_command_full_shell.ui} (87%) diff --git a/examples/shell_command/shell_command_bash.ui b/examples/shell_command/shell_command_full_shell.ui similarity index 87% rename from examples/shell_command/shell_command_bash.ui rename to examples/shell_command/shell_command_full_shell.ui index 7653570c6..25e900464 100644 --- a/examples/shell_command/shell_command_bash.ui +++ b/examples/shell_command/shell_command_full_shell.ui @@ -6,8 +6,8 @@ 0 0 - 379 - 358 + 458 + 386 @@ -23,7 +23,7 @@ - The PyDMShellCommand button with run your command through a Bash shell if you enable the "runCommandsInBash" option. + <html><head/><body><p>The PyDMShellCommand button with run your command through a full shell if you enable the 'runCmdsInFullShell' option. This allows you to use some additional features such as shell syntax ('|', '&amp;', ';', etc), environment variables ($VAR), glob expansion ('*', '?', etc), and some other features.</p><p><br/></p></body></html> true @@ -96,7 +96,7 @@ - You also can run through Bash (without needing to enable the option) by specifying "bash -c" at the start of your command or by having the shell command call a script the runs multiple commands. + You can run through a Bash shell (without needing to enable any options) by specifying "bash -c" at the start of your command. true @@ -166,6 +166,16 @@ + + + + You can also call a shell script. For this button to work correctly, run pydm from dir 'examples/shell_command' so it can find the script file. + + + true + + + diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index 82b958f2e..5d90e9873 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -68,7 +68,8 @@ def __init__( self.process = None self._show_icon = True self._redirect_output = False - # shell allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...) + # shell allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...), + # use of environment variables, glob expansion ('ls *.txt'), etc... self._run_cmds_in_full_shell = False self._password_protected = False @@ -129,7 +130,7 @@ def showConfirmDialog(self, value: bool) -> None: self._show_confirm_dialog = value @Property(bool) - def runCommandsInFullShell(self) -> bool: + def runCmdsInFullShell(self) -> bool: """ Whether or not to run cmds with Popen's option for running them through a shell subprocess. @@ -139,8 +140,8 @@ def runCommandsInFullShell(self) -> bool: """ return self._run_cmds_in_full_shell - @runCommandsInFullShell.setter - def runCommandsInFullShell(self, value: bool) -> None: + @runCmdsInFullShell.setter + def runCmdsInFullShell(self, value: bool) -> None: """ Whether or not to run cmds with Popen's option for running them through a shell subprocess. @@ -551,7 +552,7 @@ def execute_command(self, command: str) -> None: if (self.process is None or self.process.poll() is not None) or self._allow_multiple: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) - # when Bash enabled, Popen takes the cmds as a single string (not list) + # when shell enabled, Popen should take the cmds as a single string (not list) if self._run_cmds_in_full_shell: args = cmd try: From 1aa9ec7b5a4389c1cb253502fb2d846854abd1e4 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Mon, 6 Nov 2023 23:25:24 -0800 Subject: [PATCH 12/13] STY: rename property to runCommandsInFullShell, other related style fixes --- .../shell_command/shell_command_full_shell.ui | 10 ++++++++-- pydm/widgets/shell_command.py | 18 +++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/examples/shell_command/shell_command_full_shell.ui b/examples/shell_command/shell_command_full_shell.ui index 25e900464..4aca1acbe 100644 --- a/examples/shell_command/shell_command_full_shell.ui +++ b/examples/shell_command/shell_command_full_shell.ui @@ -23,7 +23,7 @@ - <html><head/><body><p>The PyDMShellCommand button with run your command through a full shell if you enable the 'runCmdsInFullShell' option. This allows you to use some additional features such as shell syntax ('|', '&amp;', ';', etc), environment variables ($VAR), glob expansion ('*', '?', etc), and some other features.</p><p><br/></p></body></html> + <html><head/><body><p>The PyDMShellCommand button with run your command through a full shell if you enable the 'runCommandsInFullShell' option. This allows you to use some additional features such as shell syntax ('|', '&amp;', ';', etc), environment variables ($VAR), glob expansion ('*', '?', etc), and some other features.</p><p><br/></p></body></html> true @@ -56,6 +56,9 @@ false + + true + Are you sure you want to proceed? @@ -76,7 +79,7 @@ - echo Fist; echo Second + echo First; echo Second @@ -88,6 +91,9 @@ + + true + true diff --git a/pydm/widgets/shell_command.py b/pydm/widgets/shell_command.py index 5d90e9873..da3c5d139 100644 --- a/pydm/widgets/shell_command.py +++ b/pydm/widgets/shell_command.py @@ -70,7 +70,7 @@ def __init__( self._redirect_output = False # shell allows for more options such as command chaining ("cmd1;cmd2", "cmd1 && cmd2", etc ...), # use of environment variables, glob expansion ('ls *.txt'), etc... - self._run_cmds_in_full_shell = False + self._run_commands_in_full_shell = False self._password_protected = False self._password = "" @@ -130,7 +130,7 @@ def showConfirmDialog(self, value: bool) -> None: self._show_confirm_dialog = value @Property(bool) - def runCmdsInFullShell(self) -> bool: + def runCommandsInFullShell(self) -> bool: """ Whether or not to run cmds with Popen's option for running them through a shell subprocess. @@ -138,10 +138,10 @@ def runCmdsInFullShell(self) -> bool: ------- bool """ - return self._run_cmds_in_full_shell + return self._run_commands_in_full_shell - @runCmdsInFullShell.setter - def runCmdsInFullShell(self, value: bool) -> None: + @runCommandsInFullShell.setter + def runCommandsInFullShell(self, value: bool) -> None: """ Whether or not to run cmds with Popen's option for running them through a shell subprocess. @@ -149,8 +149,8 @@ def runCmdsInFullShell(self, value: bool) -> None: ---------- value : bool """ - if self._run_cmds_in_full_shell != value: - self._run_cmds_in_full_shell = value + if self._run_commands_in_full_shell != value: + self._run_commands_in_full_shell = value @Property(str) def confirmMessage(self) -> str: @@ -553,7 +553,7 @@ def execute_command(self, command: str) -> None: cmd = os.path.expanduser(os.path.expandvars(command)) args = shlex.split(cmd, posix="win" not in sys.platform) # when shell enabled, Popen should take the cmds as a single string (not list) - if self._run_cmds_in_full_shell: + if self._run_commands_in_full_shell: args = cmd try: logger.debug("Launching process: %s", repr(args)) @@ -567,7 +567,7 @@ def execute_command(self, command: str) -> None: if self._redirect_output: stdout = None self.process = subprocess.Popen( - args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_cmds_in_full_shell + args, stdout=stdout, stderr=subprocess.PIPE, env=env_var, shell=self._run_commands_in_full_shell ) except Exception as exc: From 1df62d41465912d49512d4bcb604411f37a1a523 Mon Sep 17 00:00:00 2001 From: Nolan Stelter Date: Mon, 6 Nov 2023 23:30:59 -0800 Subject: [PATCH 13/13] STY: Remove old property from full-shellcmd example --- .../shell_command/shell_command_full_shell.ui | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/examples/shell_command/shell_command_full_shell.ui b/examples/shell_command/shell_command_full_shell.ui index 4aca1acbe..b5e6b2442 100644 --- a/examples/shell_command/shell_command_full_shell.ui +++ b/examples/shell_command/shell_command_full_shell.ui @@ -23,7 +23,7 @@ - <html><head/><body><p>The PyDMShellCommand button with run your command through a full shell if you enable the 'runCommandsInFullShell' option. This allows you to use some additional features such as shell syntax ('|', '&amp;', ';', etc), environment variables ($VAR), glob expansion ('*', '?', etc), and some other features.</p><p><br/></p></body></html> + <html><head/><body><p>The PyDMShellCommand button with run your command through a full shell if you enable the 'runCommandsInFullShell' option. This allows you to use some additional features such as shell syntax ('|', '&amp;', ';', etc), environment variables ($VAR), glob expansion ('*', '?', etc), and some other features.</p></body></html> true @@ -91,9 +91,6 @@ - - true - true @@ -245,19 +242,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - -