multiSSH3 5.74__py3-none-any.whl → 5.75__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of multiSSH3 might be problematic. Click here for more details.

multiSSH3.py CHANGED
@@ -55,10 +55,10 @@ except AttributeError:
55
55
  # If neither is available, use a dummy decorator
56
56
  def cache_decorator(func):
57
57
  return func
58
- version = '5.74'
58
+ version = '5.75'
59
59
  VERSION = version
60
60
  __version__ = version
61
- COMMIT_DATE = '2025-06-03'
61
+ COMMIT_DATE = '2025-06-17'
62
62
 
63
63
  CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
64
64
  '~/multiSSH3.config.json',
@@ -313,6 +313,7 @@ DEFAULT_PRINT_SUCCESS_HOSTS = False
313
313
  DEFAULT_GREPPABLE_MODE = False
314
314
  DEFAULT_SKIP_UNREACHABLE = True
315
315
  DEFAULT_SKIP_HOSTS = ''
316
+ DEFAULT_ENCODING = 'utf-8'
316
317
  SSH_STRICT_HOST_KEY_CHECKING = False
317
318
  ERROR_MESSAGES_TO_IGNORE = [
318
319
  'Pseudo-terminal will not be allocated because stdin is not a terminal',
@@ -360,6 +361,7 @@ __curses_color_table = {}
360
361
  __curses_current_color_index = 10
361
362
  __max_connections_nofile_limit_supported = 0
362
363
  __thread_start_delay = 0
364
+ _encoding = DEFAULT_ENCODING
363
365
  if __resource_lib_available:
364
366
  # Get the current limits
365
367
  _, __system_nofile_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
@@ -1123,11 +1125,12 @@ def __handle_reading_stream(stream,target, host):
1123
1125
  Returns:
1124
1126
  None
1125
1127
  '''
1128
+ global _encoding
1126
1129
  def add_line(current_line,target, host, keepLastLine=True):
1127
1130
  if not keepLastLine:
1128
1131
  target.pop()
1129
1132
  host.output.pop()
1130
- current_line_str = current_line.decode('utf-8',errors='backslashreplace')
1133
+ current_line_str = current_line.decode(_encoding,errors='backslashreplace')
1131
1134
  target.append(current_line_str)
1132
1135
  host.output.append(current_line_str)
1133
1136
  host.lineNumToPrintSet.add(len(host.output)-1)
@@ -1158,7 +1161,7 @@ def __handle_reading_stream(stream,target, host):
1158
1161
  current_line.append(char[0])
1159
1162
  else:
1160
1163
  # curser is bigger than the length of the line
1161
- current_line += b' '*(curser_position - len(current_line)) + char
1164
+ current_line += b' '*(curser_position - len(current_line)) + char[0]
1162
1165
  curser_position += 1
1163
1166
  if time.monotonic() - previousUpdateTime > 0.1:
1164
1167
  # if the time since the last update is more than 10ms, we update the output
@@ -1181,15 +1184,16 @@ def __handle_writing_stream(stream,stop_event,host):
1181
1184
  None
1182
1185
  '''
1183
1186
  global __keyPressesIn
1187
+ global _encoding
1184
1188
  # __keyPressesIn is a list of lists.
1185
1189
  # Each list is a list of characters to be sent to the stdin of the process at once.
1186
1190
  # We do not send the last line as it may be incomplete.
1187
1191
  sentInput = 0
1188
1192
  while not stop_event.is_set():
1189
1193
  if sentInput < len(__keyPressesIn) - 1 :
1190
- stream.write(''.join(__keyPressesIn[sentInput]).encode())
1194
+ stream.write(''.join(__keyPressesIn[sentInput]).encode(encoding=_encoding,errors='backslashreplace'))
1191
1195
  stream.flush()
1192
- line = '> ' + ''.join(__keyPressesIn[sentInput]).encode().decode().replace('\n', '↵')
1196
+ line = '> ' + ''.join(__keyPressesIn[sentInput]).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\n', '↵')
1193
1197
  host.output.append(line)
1194
1198
  host.stdout.append(line)
1195
1199
  host.lineNumToPrintSet.add(len(host.output)-1)
@@ -1866,6 +1870,7 @@ def _get_hosts_to_display (hosts, max_num_hosts, hosts_to_display = None, indexO
1866
1870
  return new_hosts_to_display , {'running':len(running_hosts), 'failed':len(failed_hosts), 'finished':len(finished_hosts), 'waiting':len(waiting_hosts)}, rearrangedHosts
1867
1871
 
1868
1872
  def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window=DEFAULT_SINGLE_WINDOW, config_reason = 'New Configuration'):
1873
+ global _encoding
1869
1874
  _ = config_reason
1870
1875
  try:
1871
1876
  box_ansi_color = None
@@ -2101,7 +2106,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
2101
2106
  stats = f"Total: {len(hosts)} Running: {host_stats['running']} Failed: {host_stats['failed']} Finished: {host_stats['finished']} Waiting: {host_stats['waiting']} ww: {min_char_len} wh:{min_line_len} i:{indexOffset} "
2102
2107
  else:
2103
2108
  # we use the stat bar to display the key presses
2104
- encodedLine = ''.join(__keyPressesIn[lineToDisplay]).encode().decode().strip('\n') + ' '
2109
+ encodedLine = ''.join(__keyPressesIn[lineToDisplay]).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').strip('\n') + ' '
2105
2110
  #stats = '┍'+ f"Send CMD: {encodedLine}"[:max_x - 2].center(max_x - 2, "━")
2106
2111
  # format the stats line with chracter at curser position inverted using ansi escape sequence
2107
2112
  # displayCurserPosition is needed as the curserPosition can be larger than the length of the encodedLine. This is wanted to keep scrolling through the history less painful
@@ -2253,6 +2258,7 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
2253
2258
  def generate_output(hosts, usejson = False, greppable = False):
2254
2259
  global __keyPressesIn
2255
2260
  global __global_suppress_printout
2261
+ global __encoding
2256
2262
  if __global_suppress_printout:
2257
2263
  # remove hosts with returncode 0
2258
2264
  hosts = [dict(host) for host in hosts if host.returncode != 0]
@@ -2286,7 +2292,7 @@ def generate_output(hosts, usejson = False, greppable = False):
2286
2292
  rtnStr += pretty_format_table(rtnList)
2287
2293
  rtnStr += '*'*80+'\n'
2288
2294
  if __keyPressesIn[-1]:
2289
- CMDsOut = [''.join(cmd).encode('unicode_escape').decode().replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
2295
+ CMDsOut = [''.join(cmd).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
2290
2296
  rtnStr += 'User Inputs: '+ '\nUser Inputs: '.join(CMDsOut)
2291
2297
  #rtnStr += '\n'
2292
2298
  else:
@@ -2317,7 +2323,7 @@ def generate_output(hosts, usejson = False, greppable = False):
2317
2323
  if not __global_suppress_printout or outputs:
2318
2324
  rtnStr += '*'*80+'\n'
2319
2325
  if __keyPressesIn[-1]:
2320
- CMDsOut = [''.join(cmd).encode('unicode_escape').decode().replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
2326
+ CMDsOut = [''.join(cmd).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
2321
2327
  #rtnStr += f"Key presses: {''.join(__keyPressesIn).encode('unicode_escape').decode()}\n"
2322
2328
  #rtnStr += f"Key presses: {__keyPressesIn}\n"
2323
2329
  rtnStr += "User Inputs: \n "
@@ -2915,6 +2921,7 @@ def generate_default_config(args):
2915
2921
  'DEFAULT_GREPPABLE_MODE': args.greppable,
2916
2922
  'DEFAULT_SKIP_UNREACHABLE': args.skip_unreachable,
2917
2923
  'DEFAULT_SKIP_HOSTS': args.skip_hosts,
2924
+ 'DEFAULT_ENCODING': args.encoding,
2918
2925
  'SSH_STRICT_HOST_KEY_CHECKING': SSH_STRICT_HOST_KEY_CHECKING,
2919
2926
  'ERROR_MESSAGES_TO_IGNORE': ERROR_MESSAGES_TO_IGNORE,
2920
2927
  }
@@ -2970,6 +2977,7 @@ def main():
2970
2977
  global _env_file
2971
2978
  global __DEBUG_MODE
2972
2979
  global __configs_from_file
2980
+ global _encoding
2973
2981
  _emo = False
2974
2982
  # We handle the signal
2975
2983
  signal.signal(signal.SIGINT, signal_handler)
@@ -3021,6 +3029,7 @@ def main():
3021
3029
  parser.add_argument('-I','-nh','--no_history', action='store_true', help=f'Do not record the command to history. Default: {DEFAULT_NO_HISTORY}', default=DEFAULT_NO_HISTORY)
3022
3030
  parser.add_argument('-hf','--history_file', type=str, help=f'The file to store the history. (default: {DEFAULT_HISTORY_FILE})', default=DEFAULT_HISTORY_FILE)
3023
3031
  parser.add_argument('--script', action='store_true', help='Run the command in script mode, short for -SCRIPT or --no_watch --skip_unreachable --no_env --no_history --greppable --error_only')
3032
+ parser.add_argument('-e','--encoding', type=str, help=f'The encoding to use for the output. (default: {DEFAULT_ENCODING})', default=DEFAULT_ENCODING)
3024
3033
  parser.add_argument("-V","--version", action='version', version=f'%(prog)s {version} @ {COMMIT_DATE} with [ {", ".join(_binPaths.keys())} ] by {AUTHOR} ({AUTHOR_EMAIL})')
3025
3034
 
3026
3035
  # parser.add_argument('-u', '--user', metavar='user', type=str, nargs=1,
@@ -3109,6 +3118,8 @@ def main():
3109
3118
  # set timeout to the default script timeout if timeout is not set
3110
3119
  if args.timeout == DEFAULT_CLI_TIMEOUT:
3111
3120
  args.timeout = DEFAULT_TIMEOUT
3121
+
3122
+ _encoding = args.encoding
3112
3123
 
3113
3124
  if not __global_suppress_printout:
3114
3125
  cmdStr = getStrCommand(args.hosts,args.commands,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiSSH3
3
- Version: 5.74
3
+ Version: 5.75
4
4
  Summary: Run commands on multiple hosts via SSH
5
5
  Home-page: https://github.com/yufei-pan/multiSSH3
6
6
  Author: Yufei Pan
@@ -0,0 +1,6 @@
1
+ multiSSH3.py,sha256=5pDQ7zSeNmfzu-o081Z7VOfW_8Ke48WPHi0BxnBnHAw,149915
2
+ multissh3-5.75.dist-info/METADATA,sha256=1_pBC-nNbRg_aR3LFNNInE5Whrn9hBaQMhnxEkO2IOg,18093
3
+ multissh3-5.75.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
4
+ multissh3-5.75.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
5
+ multissh3-5.75.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
6
+ multissh3-5.75.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- multiSSH3.py,sha256=h8FnoCjcZGOjyPypzJ7H4XLOhMIKU2I-kN-m6PGdjJY,149182
2
- multissh3-5.74.dist-info/METADATA,sha256=ErFNVhzY6qUCJAiI2-paOpyfNiLJKJayjXCYiQRHJPg,18093
3
- multissh3-5.74.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
4
- multissh3-5.74.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
5
- multissh3-5.74.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
6
- multissh3-5.74.dist-info/RECORD,,