|
12 | 12 | import socket |
13 | 13 | import termios |
14 | 14 | import getpass |
| 15 | +import signal |
15 | 16 |
|
16 | 17 | MULTI_LC_REXEC_OUTPUT = '''======== LINE-CARD0|sonic-lc1 output: ======== |
17 | 18 | hello world |
@@ -83,7 +84,18 @@ def mock_getpass(prompt="Password:", stream=None): |
83 | 84 |
|
84 | 85 |
|
85 | 86 | class TestRemoteExec(object): |
86 | | - __getpass = getpass.getpass |
| 87 | + # Store the original function at class definition time to avoid recursion |
| 88 | + _original_getpass = getpass.getpass |
| 89 | + |
| 90 | + @staticmethod |
| 91 | + def __getpass(prompt="Password:", stream=None): |
| 92 | + """SIGTTOU-safe wrapper for getpass.getpass() for Python 3.13 compatibility""" |
| 93 | + original_sigttou_handler = signal.signal(signal.SIGTTOU, signal.SIG_IGN) |
| 94 | + try: |
| 95 | + # Call the original function, in case getpass.getpass has been overridden |
| 96 | + return TestRemoteExec._original_getpass(prompt, stream) |
| 97 | + finally: |
| 98 | + signal.signal(signal.SIGTTOU, original_sigttou_handler) |
87 | 99 |
|
88 | 100 | @classmethod |
89 | 101 | def setup_class(cls): |
@@ -225,9 +237,10 @@ def test_rexec_without_password_input(self): |
225 | 237 | runner = CliRunner() |
226 | 238 | getpass.getpass = TestRemoteExec.__getpass |
227 | 239 | LINECARD_NAME = "all" |
228 | | - result = runner.invoke( |
229 | | - rexec.cli, [LINECARD_NAME, "-c", "show version"]) |
| 240 | + |
| 241 | + result = runner.invoke(rexec.cli, [LINECARD_NAME, "-c", "show version"]) |
230 | 242 | getpass.getpass = mock_getpass |
| 243 | + |
231 | 244 | print(result.output) |
232 | 245 | assert result.exit_code == 1, result.output |
233 | 246 | assert "Aborted" in result.output |
|
0 commit comments