From 2530cf1fe1c37b30bf8ff431b8425fee88ba3655 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Fri, 7 Jul 2023 18:00:00 -0700 Subject: [PATCH 1/6] Add ruff, mypy, .env to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1980c4777..b5eafb63f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ bin/.netmiko.cfg .idea/ # Virtual Environment files +.env/ .venv/ bin/ lib/ @@ -37,6 +38,8 @@ docs/build/doctrees/ .tox/* .pytest_cache/* +.mypy_cache/ +.ruff_cache/ # Mac stuff .DS_Store From 46131f91a89f3135e6aeddb2b9a1b30d09568de9 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Fri, 7 Jul 2023 18:00:19 -0700 Subject: [PATCH 2/6] Configure ruff to ignore E501 line too long --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a5fd71783..3f6c97bcc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,3 +52,6 @@ ttp = ">=0.9.0" "netmiko-grep" = "netmiko.cli_tools.netmiko_grep:main_ep" "netmiko-show" = "netmiko.cli_tools.netmiko_show:main_ep" "netmiko-cfg" = "netmiko.cli_tools.netmiko_cfg:main_ep" + +[tool.ruff] +ignore = ["E501"] From 40aa6d81ba8a4e3c8297c930ca9644394d8fd5f7 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Fri, 7 Jul 2023 18:01:03 -0700 Subject: [PATCH 3/6] Fix E713 courtesy of ruff --- netmiko/audiocode/audiocode_ssh.py | 2 +- netmiko/base_connection.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/netmiko/audiocode/audiocode_ssh.py b/netmiko/audiocode/audiocode_ssh.py index 8d67cf8dc..73a7d171c 100644 --- a/netmiko/audiocode/audiocode_ssh.py +++ b/netmiko/audiocode/audiocode_ssh.py @@ -39,7 +39,7 @@ def set_base_prompt( else: prompt = self.find_prompt(delay_factor=delay_factor) - if not prompt[-1] in (pri_prompt_terminator, alt_prompt_terminator): + if prompt[-1] not in (pri_prompt_terminator, alt_prompt_terminator): raise ValueError(f"Router prompt not found: {repr(prompt)}") # If all we have is the 'terminator' just use that :-( diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 8fa3daf05..0b6c86dc1 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -1364,7 +1364,7 @@ def set_base_prompt( else: prompt = self.find_prompt(delay_factor=delay_factor) - if not prompt[-1] in (pri_prompt_terminator, alt_prompt_terminator): + if prompt[-1] not in (pri_prompt_terminator, alt_prompt_terminator): raise ValueError(f"Router prompt not found: {repr(prompt)}") # If all we have is the 'terminator' just use that :-( From 462088498ecd77dff87711966e8842ca4a064f50 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Fri, 7 Jul 2023 18:01:55 -0700 Subject: [PATCH 4/6] Blank line fixes courtesy of black --- netmiko/adva/adva_aos_fsp_150_f2.py | 1 - netmiko/adva/adva_aos_fsp_150_f3.py | 2 -- netmiko/apresia/apresia_aeos.py | 1 - netmiko/audiocode/audiocode_ssh.py | 6 ------ netmiko/base_connection.py | 2 -- netmiko/centec/centec_os.py | 2 -- netmiko/cisco/cisco_ios.py | 1 - netmiko/cisco/cisco_wlc_ssh.py | 2 -- netmiko/dell/dell_isilon_ssh.py | 1 - netmiko/ericsson/ericsson_mltn.py | 1 - netmiko/hp/hp_procurve.py | 1 - netmiko/nokia/nokia_srl.py | 1 - netmiko/paloalto/paloalto_panos.py | 1 - netmiko/raisecom/raisecom_roap.py | 1 - netmiko/ruijie/ruijie_os.py | 1 - netmiko/sixwind/sixwind_os.py | 1 - 16 files changed, 25 deletions(-) diff --git a/netmiko/adva/adva_aos_fsp_150_f2.py b/netmiko/adva/adva_aos_fsp_150_f2.py index f53a2e753..53f2f969a 100644 --- a/netmiko/adva/adva_aos_fsp_150_f2.py +++ b/netmiko/adva/adva_aos_fsp_150_f2.py @@ -60,7 +60,6 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: - prompt = self.find_prompt() match = re.search(pri_prompt_terminator, prompt) if not match: diff --git a/netmiko/adva/adva_aos_fsp_150_f3.py b/netmiko/adva/adva_aos_fsp_150_f3.py index 23e32ec11..9732fc59e 100644 --- a/netmiko/adva/adva_aos_fsp_150_f3.py +++ b/netmiko/adva/adva_aos_fsp_150_f3.py @@ -96,7 +96,6 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: - prompt = self.find_prompt() match = re.search(pri_prompt_terminator, prompt) if not match: @@ -121,7 +120,6 @@ def send_config_set( terminator: str = r"#", bypass_commands: Optional[str] = None, ) -> str: - if bypass_commands is None: categories = ( r"(?:superuser|crypto|maintenance|provisioning|retrieve|test-user)" diff --git a/netmiko/apresia/apresia_aeos.py b/netmiko/apresia/apresia_aeos.py index 8ef0f5ea3..14a7ade83 100644 --- a/netmiko/apresia/apresia_aeos.py +++ b/netmiko/apresia/apresia_aeos.py @@ -16,7 +16,6 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: - self.enable() check_command = f"show running-config | include {command}" show_run = self._send_command_str(check_command) diff --git a/netmiko/audiocode/audiocode_ssh.py b/netmiko/audiocode/audiocode_ssh.py index 73a7d171c..1167803a8 100644 --- a/netmiko/audiocode/audiocode_ssh.py +++ b/netmiko/audiocode/audiocode_ssh.py @@ -30,7 +30,6 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: - if pattern is None: pattern = rf"\*?{self.prompt_pattern}" @@ -60,7 +59,6 @@ def find_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: - if pattern is None: pattern = rf"\*?{self.prompt_pattern}" return super().find_prompt( @@ -228,7 +226,6 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: - if command: return super().disable_paging( command=command, @@ -292,7 +289,6 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: - if command: return super().disable_paging( command=command, @@ -320,7 +316,6 @@ def _enable_paging( self, delay_factor: Optional[float] = 0.5, ) -> str: - command_list: List[str] = [ "cli-terminal", "set window-height 100", @@ -401,7 +396,6 @@ def send_config_set( terminator: str = r"/.*>", bypass_commands: Optional[str] = None, ) -> str: - return super().send_config_set( config_commands=config_commands, exit_config_mode=exit_config_mode, diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 0b6c86dc1..dc9dcab94 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -667,7 +667,6 @@ def read_until_pattern( start_time = time.time() # if read_timeout == 0 or 0.0 keep reading indefinitely while (time.time() - start_time < read_timeout) or (not read_timeout): - output += self.read_channel() if re.search(pattern, output, flags=re_flags): @@ -1447,7 +1446,6 @@ def clear_buffer( return output def command_echo_read(self, cmd: str, read_timeout: float) -> str: - # Make sure you read until you detect the command echo (avoid getting out of sync) new_data = self.read_until_pattern( pattern=re.escape(cmd), read_timeout=read_timeout diff --git a/netmiko/centec/centec_os.py b/netmiko/centec/centec_os.py index d1e1307f6..50cf2e5aa 100644 --- a/netmiko/centec/centec_os.py +++ b/netmiko/centec/centec_os.py @@ -19,10 +19,8 @@ def save_config( class CentecOSSSH(CentecOSBase): - pass class CentecOSTelnet(CentecOSBase): - pass diff --git a/netmiko/cisco/cisco_ios.py b/netmiko/cisco/cisco_ios.py index 3f002993e..7304a8f9b 100644 --- a/netmiko/cisco/cisco_ios.py +++ b/netmiko/cisco/cisco_ios.py @@ -103,7 +103,6 @@ def __init__( progress4: Optional[Callable[..., Any]] = None, hash_supported: bool = True, ) -> None: - if not dest_file: raise ValueError( "Destination file must be specified for InlineTransfer operations." diff --git a/netmiko/cisco/cisco_wlc_ssh.py b/netmiko/cisco/cisco_wlc_ssh.py index b4ece3b23..e10df9b0d 100644 --- a/netmiko/cisco/cisco_wlc_ssh.py +++ b/netmiko/cisco/cisco_wlc_ssh.py @@ -97,13 +97,11 @@ def send_command_w_enter(self, *args: Any, **kwargs: Any) -> str: kwargs["max_loops"] = 150 if "Press any key" in output or "Press Enter to" in output: - # Send an 'enter' output += self._send_command_timing_str(*second_args, **kwargs) # WLC has excessive delay after this appears on screen if "802.11b Advanced Configuration" in output: - # Defaults to 30 seconds time.sleep(kwargs["delay_factor"] * 30) not_done = True diff --git a/netmiko/dell/dell_isilon_ssh.py b/netmiko/dell/dell_isilon_ssh.py index 6ee1676de..a1159214c 100644 --- a/netmiko/dell/dell_isilon_ssh.py +++ b/netmiko/dell/dell_isilon_ssh.py @@ -67,7 +67,6 @@ def enable( check_state: bool = True, re_flags: int = re.IGNORECASE, ) -> str: - delay_factor = self.select_delay_factor(delay_factor=1) output = "" diff --git a/netmiko/ericsson/ericsson_mltn.py b/netmiko/ericsson/ericsson_mltn.py index 1b6eb8f8c..3aefa9ecb 100644 --- a/netmiko/ericsson/ericsson_mltn.py +++ b/netmiko/ericsson/ericsson_mltn.py @@ -20,7 +20,6 @@ def __init__( *args: Any, **kwargs: Any, ) -> None: - # Set default auth_timeout if kwargs.get("auth_timeout") is None: kwargs["auth_timeout"] = 20 diff --git a/netmiko/hp/hp_procurve.py b/netmiko/hp/hp_procurve.py index f59394981..e7efb74b6 100644 --- a/netmiko/hp/hp_procurve.py +++ b/netmiko/hp/hp_procurve.py @@ -147,7 +147,6 @@ def cleanup(self, command: str = "logout") -> None: output = "" for _ in range(10): - # The connection might be dead here. try: # "Do you want to log out" diff --git a/netmiko/nokia/nokia_srl.py b/netmiko/nokia/nokia_srl.py index 781467aeb..ea46c2796 100644 --- a/netmiko/nokia/nokia_srl.py +++ b/netmiko/nokia/nokia_srl.py @@ -83,7 +83,6 @@ def check_config_mode( pattern: str = r"#", force_regex: bool = True, ) -> bool: - return super().check_config_mode( check_string=check_string, pattern=pattern, force_regex=force_regex ) diff --git a/netmiko/paloalto/paloalto_panos.py b/netmiko/paloalto/paloalto_panos.py index acbb08746..50b5a7df3 100644 --- a/netmiko/paloalto/paloalto_panos.py +++ b/netmiko/paloalto/paloalto_panos.py @@ -14,7 +14,6 @@ class SSHClient_interactive(SSHClient): def pa_banner_handler( self, title: str, instructions: str, prompt_list: List[Tuple[str, bool]] ) -> List[str]: - resp = [] for prompt, echo in prompt_list: if "Do you accept" in prompt: diff --git a/netmiko/raisecom/raisecom_roap.py b/netmiko/raisecom/raisecom_roap.py index 2278a0446..83cb1cbd3 100644 --- a/netmiko/raisecom/raisecom_roap.py +++ b/netmiko/raisecom/raisecom_roap.py @@ -97,7 +97,6 @@ def telnet_login( delay_factor: float = 1.0, max_loops: int = 20, ) -> str: - # set callback function to handle telnet options. assert isinstance(self.remote_conn, Telnet) self.remote_conn.set_option_negotiation_callback(self._process_option) diff --git a/netmiko/ruijie/ruijie_os.py b/netmiko/ruijie/ruijie_os.py index f3a070da4..259c9474d 100644 --- a/netmiko/ruijie/ruijie_os.py +++ b/netmiko/ruijie/ruijie_os.py @@ -28,7 +28,6 @@ def save_config( class RuijieOSSSH(RuijieOSBase): - pass diff --git a/netmiko/sixwind/sixwind_os.py b/netmiko/sixwind/sixwind_os.py index 8fdaa37ea..35a6a70a6 100644 --- a/netmiko/sixwind/sixwind_os.py +++ b/netmiko/sixwind/sixwind_os.py @@ -108,5 +108,4 @@ def save_config( class SixwindOSSSH(SixwindOSBase): - pass From 2d058ac102e4b8e157ff0e31bd0c1a003fddd807 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Fri, 7 Jul 2023 18:05:19 -0700 Subject: [PATCH 5/6] Remove external dependency on grep, add typing, add --write-output --- netmiko/cli_tools/netmiko_show.py | 116 +++++++++++++++++------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/netmiko/cli_tools/netmiko_show.py b/netmiko/cli_tools/netmiko_show.py index 4dc987def..5d0ba50db 100755 --- a/netmiko/cli_tools/netmiko_show.py +++ b/netmiko/cli_tools/netmiko_show.py @@ -5,8 +5,6 @@ import argparse import sys -import os -import subprocess import threading try: @@ -15,43 +13,38 @@ from queue import Queue from datetime import datetime from getpass import getpass +from typing import Dict from netmiko import ConnectHandler -from netmiko.utilities import load_devices, display_inventory -from netmiko.utilities import obtain_all_devices -from netmiko.utilities import obtain_netmiko_filename, write_tmp_file, ensure_dir_exists -from netmiko.utilities import find_netmiko_dir -from netmiko.utilities import SHOW_RUN_MAPPER - -GREP = "/bin/grep" -if not os.path.exists(GREP): - GREP = "/usr/bin/grep" +from netmiko.utilities import ( + load_devices, + display_inventory, + obtain_all_devices, + obtain_netmiko_filename, + write_tmp_file, + ensure_dir_exists, + find_netmiko_dir, + SHOW_RUN_MAPPER, +) + + NETMIKO_BASE_DIR = "~/.netmiko" ERROR_PATTERN = "%%%failed%%%" __version__ = "0.1.0" -def grepx(files, pattern, grep_options, use_colors=True): - """Call system grep""" - if not isinstance(files, (list, tuple)): - files = [files] - if use_colors: - grep_options += ["--color=auto"] +def print_output(device_name: str, output: str) -> None: + """Print device output to stdout.""" + sys.stdout.write("{0}:\n--------------------\n{1}\n\n".format(device_name, output)) - # Make grep output look nicer by 'cd netmiko_full_dir' - _, netmiko_full_dir = find_netmiko_dir() - os.chdir(netmiko_full_dir) - # Convert files to strip off the directory - retrieve_file = lambda x: x.split("/")[-1] # noqa - files = [retrieve_file(a_file) for a_file in files] - files.sort() - grep_list = [GREP] + grep_options + [pattern] + files - proc = subprocess.Popen(grep_list, shell=False) - proc.communicate() - return "" - -def ssh_conn(device_name, a_device, cli_command, output_q): +def ssh_conn( + device_name: str, + a_device: Dict[str, str], + cli_command: str, + output_q: Queue, +) -> None: + """SSH connection thread entry point.""" try: net_connect = ConnectHandler(**a_device) net_connect.enable() @@ -62,7 +55,7 @@ def ssh_conn(device_name, a_device, cli_command, output_q): output_q.put({device_name: output}) -def parse_arguments(args): +def parse_arguments() -> "argparse.Namespace": """Parse command-line arguments.""" description = ( "Return output from single show cmd using Netmiko (defaults to running-config)" @@ -95,21 +88,23 @@ def parse_arguments(args): parser.add_argument( "--hide-failed", help="Hide failed devices", action="store_true" ) + parser.add_argument( + "--write-output", + help="Write output to files instead of displaying on console", + action="store_true", + ) parser.add_argument("--version", help="Display version", action="store_true") - cli_args = parser.parse_args(args) + cli_args = parser.parse_args() if not cli_args.list_devices and not cli_args.version: if not cli_args.devices: parser.error("Devices not specified.") return cli_args -def main_ep(): - sys.exit(main(sys.argv[1:])) - - -def main(args): +def main() -> int: + """Primary execution thread.""" start_time = datetime.now() - cli_args = parse_arguments(args) + cli_args = parse_arguments() cli_username = cli_args.username if cli_args.username else None cli_password = getpass() if cli_args.password else None @@ -121,7 +116,11 @@ def main(args): return 0 list_devices = cli_args.list_devices if list_devices: - my_devices = load_devices() + try: + my_devices = load_devices() + except OSError as e: + sys.stderr.write("ERROR: Could not load device inventory: {0}\n".format(e)) + return 1 display_inventory(my_devices) return 0 @@ -130,12 +129,15 @@ def main(args): if cli_command: cmd_arg = True device_or_group = cli_args.devices.strip() - pattern = r"." use_cached_files = cli_args.use_cache hide_failed = cli_args.hide_failed output_q = Queue() - my_devices = load_devices() + try: + my_devices = load_devices() + except OSError as e: + sys.stderr.write("ERROR: Could not load device inventory: {0}\n".format(e)) + return 1 if device_or_group == "all": device_group = obtain_all_devices(my_devices) else: @@ -148,13 +150,13 @@ def main(args): else: device_group[device_or_group] = devicedict_or_group except KeyError: - return ( + sys.stderr.write( "Error reading from netmiko devices file." - " Device or group not found: {0}".format(device_or_group) + " Device or group not found: {0}\n".format(device_or_group) ) + return 1 # Retrieve output from devices - my_files = [] failed_devices = [] if not use_cached_files: for device_name, a_device in device_group.items(): @@ -184,7 +186,11 @@ def main(args): for device_name, output in my_dict.items(): file_name = write_tmp_file(device_name, output) if ERROR_PATTERN not in output: - my_files.append(file_name) + if cli_args.write_output: + with open("{0}.txt".format(device_name), "w") as f: + f.write(output) + else: + print_output(device_name, output) else: failed_devices.append(device_name) else: @@ -194,14 +200,19 @@ def main(args): with open(file_name) as f: output = f.read() except IOError: - return "Some cache files are missing: unable to use --use-cache option." + sys.stderr.write( + "Some cache files are missing: unable to use --use-cache option.\n" + ) + return 1 if ERROR_PATTERN not in output: - my_files.append(file_name) + if cli_args.write_output: + with open("{0}.txt".format(device_name), "w") as f: + f.write(output) + else: + print_output(device_name, output) else: failed_devices.append(device_name) - grep_options = [] - grepx(my_files, pattern, grep_options) if cli_args.display_runtime: print("Total time: {0}".format(datetime.now() - start_time)) @@ -217,5 +228,10 @@ def main(args): return 0 +def main_ep() -> None: + """Primary execution entry point.""" + sys.exit(main()) + + if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) + main_ep() From 419218f5daceb835d49a6215f3ccd51373b2b796 Mon Sep 17 00:00:00 2001 From: ReK42 Date: Sat, 8 Jul 2023 20:10:35 -0700 Subject: [PATCH 6/6] Revert "Blank line fixes courtesy of black" This reverts commit 462088498ecd77dff87711966e8842ca4a064f50. --- netmiko/adva/adva_aos_fsp_150_f2.py | 1 + netmiko/adva/adva_aos_fsp_150_f3.py | 2 ++ netmiko/apresia/apresia_aeos.py | 1 + netmiko/audiocode/audiocode_ssh.py | 6 ++++++ netmiko/base_connection.py | 2 ++ netmiko/centec/centec_os.py | 2 ++ netmiko/cisco/cisco_ios.py | 1 + netmiko/cisco/cisco_wlc_ssh.py | 2 ++ netmiko/dell/dell_isilon_ssh.py | 1 + netmiko/ericsson/ericsson_mltn.py | 1 + netmiko/hp/hp_procurve.py | 1 + netmiko/nokia/nokia_srl.py | 1 + netmiko/paloalto/paloalto_panos.py | 1 + netmiko/raisecom/raisecom_roap.py | 1 + netmiko/ruijie/ruijie_os.py | 1 + netmiko/sixwind/sixwind_os.py | 1 + 16 files changed, 25 insertions(+) diff --git a/netmiko/adva/adva_aos_fsp_150_f2.py b/netmiko/adva/adva_aos_fsp_150_f2.py index 53f2f969a..f53a2e753 100644 --- a/netmiko/adva/adva_aos_fsp_150_f2.py +++ b/netmiko/adva/adva_aos_fsp_150_f2.py @@ -60,6 +60,7 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: + prompt = self.find_prompt() match = re.search(pri_prompt_terminator, prompt) if not match: diff --git a/netmiko/adva/adva_aos_fsp_150_f3.py b/netmiko/adva/adva_aos_fsp_150_f3.py index 9732fc59e..23e32ec11 100644 --- a/netmiko/adva/adva_aos_fsp_150_f3.py +++ b/netmiko/adva/adva_aos_fsp_150_f3.py @@ -96,6 +96,7 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: + prompt = self.find_prompt() match = re.search(pri_prompt_terminator, prompt) if not match: @@ -120,6 +121,7 @@ def send_config_set( terminator: str = r"#", bypass_commands: Optional[str] = None, ) -> str: + if bypass_commands is None: categories = ( r"(?:superuser|crypto|maintenance|provisioning|retrieve|test-user)" diff --git a/netmiko/apresia/apresia_aeos.py b/netmiko/apresia/apresia_aeos.py index 14a7ade83..8ef0f5ea3 100644 --- a/netmiko/apresia/apresia_aeos.py +++ b/netmiko/apresia/apresia_aeos.py @@ -16,6 +16,7 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: + self.enable() check_command = f"show running-config | include {command}" show_run = self._send_command_str(check_command) diff --git a/netmiko/audiocode/audiocode_ssh.py b/netmiko/audiocode/audiocode_ssh.py index 1167803a8..73a7d171c 100644 --- a/netmiko/audiocode/audiocode_ssh.py +++ b/netmiko/audiocode/audiocode_ssh.py @@ -30,6 +30,7 @@ def set_base_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: + if pattern is None: pattern = rf"\*?{self.prompt_pattern}" @@ -59,6 +60,7 @@ def find_prompt( delay_factor: float = 1.0, pattern: Optional[str] = None, ) -> str: + if pattern is None: pattern = rf"\*?{self.prompt_pattern}" return super().find_prompt( @@ -226,6 +228,7 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: + if command: return super().disable_paging( command=command, @@ -289,6 +292,7 @@ def disable_paging( cmd_verify: bool = True, pattern: Optional[str] = None, ) -> str: + if command: return super().disable_paging( command=command, @@ -316,6 +320,7 @@ def _enable_paging( self, delay_factor: Optional[float] = 0.5, ) -> str: + command_list: List[str] = [ "cli-terminal", "set window-height 100", @@ -396,6 +401,7 @@ def send_config_set( terminator: str = r"/.*>", bypass_commands: Optional[str] = None, ) -> str: + return super().send_config_set( config_commands=config_commands, exit_config_mode=exit_config_mode, diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index dc9dcab94..0b6c86dc1 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -667,6 +667,7 @@ def read_until_pattern( start_time = time.time() # if read_timeout == 0 or 0.0 keep reading indefinitely while (time.time() - start_time < read_timeout) or (not read_timeout): + output += self.read_channel() if re.search(pattern, output, flags=re_flags): @@ -1446,6 +1447,7 @@ def clear_buffer( return output def command_echo_read(self, cmd: str, read_timeout: float) -> str: + # Make sure you read until you detect the command echo (avoid getting out of sync) new_data = self.read_until_pattern( pattern=re.escape(cmd), read_timeout=read_timeout diff --git a/netmiko/centec/centec_os.py b/netmiko/centec/centec_os.py index 50cf2e5aa..d1e1307f6 100644 --- a/netmiko/centec/centec_os.py +++ b/netmiko/centec/centec_os.py @@ -19,8 +19,10 @@ def save_config( class CentecOSSSH(CentecOSBase): + pass class CentecOSTelnet(CentecOSBase): + pass diff --git a/netmiko/cisco/cisco_ios.py b/netmiko/cisco/cisco_ios.py index 7304a8f9b..3f002993e 100644 --- a/netmiko/cisco/cisco_ios.py +++ b/netmiko/cisco/cisco_ios.py @@ -103,6 +103,7 @@ def __init__( progress4: Optional[Callable[..., Any]] = None, hash_supported: bool = True, ) -> None: + if not dest_file: raise ValueError( "Destination file must be specified for InlineTransfer operations." diff --git a/netmiko/cisco/cisco_wlc_ssh.py b/netmiko/cisco/cisco_wlc_ssh.py index e10df9b0d..b4ece3b23 100644 --- a/netmiko/cisco/cisco_wlc_ssh.py +++ b/netmiko/cisco/cisco_wlc_ssh.py @@ -97,11 +97,13 @@ def send_command_w_enter(self, *args: Any, **kwargs: Any) -> str: kwargs["max_loops"] = 150 if "Press any key" in output or "Press Enter to" in output: + # Send an 'enter' output += self._send_command_timing_str(*second_args, **kwargs) # WLC has excessive delay after this appears on screen if "802.11b Advanced Configuration" in output: + # Defaults to 30 seconds time.sleep(kwargs["delay_factor"] * 30) not_done = True diff --git a/netmiko/dell/dell_isilon_ssh.py b/netmiko/dell/dell_isilon_ssh.py index a1159214c..6ee1676de 100644 --- a/netmiko/dell/dell_isilon_ssh.py +++ b/netmiko/dell/dell_isilon_ssh.py @@ -67,6 +67,7 @@ def enable( check_state: bool = True, re_flags: int = re.IGNORECASE, ) -> str: + delay_factor = self.select_delay_factor(delay_factor=1) output = "" diff --git a/netmiko/ericsson/ericsson_mltn.py b/netmiko/ericsson/ericsson_mltn.py index 3aefa9ecb..1b6eb8f8c 100644 --- a/netmiko/ericsson/ericsson_mltn.py +++ b/netmiko/ericsson/ericsson_mltn.py @@ -20,6 +20,7 @@ def __init__( *args: Any, **kwargs: Any, ) -> None: + # Set default auth_timeout if kwargs.get("auth_timeout") is None: kwargs["auth_timeout"] = 20 diff --git a/netmiko/hp/hp_procurve.py b/netmiko/hp/hp_procurve.py index e7efb74b6..f59394981 100644 --- a/netmiko/hp/hp_procurve.py +++ b/netmiko/hp/hp_procurve.py @@ -147,6 +147,7 @@ def cleanup(self, command: str = "logout") -> None: output = "" for _ in range(10): + # The connection might be dead here. try: # "Do you want to log out" diff --git a/netmiko/nokia/nokia_srl.py b/netmiko/nokia/nokia_srl.py index ea46c2796..781467aeb 100644 --- a/netmiko/nokia/nokia_srl.py +++ b/netmiko/nokia/nokia_srl.py @@ -83,6 +83,7 @@ def check_config_mode( pattern: str = r"#", force_regex: bool = True, ) -> bool: + return super().check_config_mode( check_string=check_string, pattern=pattern, force_regex=force_regex ) diff --git a/netmiko/paloalto/paloalto_panos.py b/netmiko/paloalto/paloalto_panos.py index 50b5a7df3..acbb08746 100644 --- a/netmiko/paloalto/paloalto_panos.py +++ b/netmiko/paloalto/paloalto_panos.py @@ -14,6 +14,7 @@ class SSHClient_interactive(SSHClient): def pa_banner_handler( self, title: str, instructions: str, prompt_list: List[Tuple[str, bool]] ) -> List[str]: + resp = [] for prompt, echo in prompt_list: if "Do you accept" in prompt: diff --git a/netmiko/raisecom/raisecom_roap.py b/netmiko/raisecom/raisecom_roap.py index 83cb1cbd3..2278a0446 100644 --- a/netmiko/raisecom/raisecom_roap.py +++ b/netmiko/raisecom/raisecom_roap.py @@ -97,6 +97,7 @@ def telnet_login( delay_factor: float = 1.0, max_loops: int = 20, ) -> str: + # set callback function to handle telnet options. assert isinstance(self.remote_conn, Telnet) self.remote_conn.set_option_negotiation_callback(self._process_option) diff --git a/netmiko/ruijie/ruijie_os.py b/netmiko/ruijie/ruijie_os.py index 259c9474d..f3a070da4 100644 --- a/netmiko/ruijie/ruijie_os.py +++ b/netmiko/ruijie/ruijie_os.py @@ -28,6 +28,7 @@ def save_config( class RuijieOSSSH(RuijieOSBase): + pass diff --git a/netmiko/sixwind/sixwind_os.py b/netmiko/sixwind/sixwind_os.py index 35a6a70a6..8fdaa37ea 100644 --- a/netmiko/sixwind/sixwind_os.py +++ b/netmiko/sixwind/sixwind_os.py @@ -108,4 +108,5 @@ def save_config( class SixwindOSSSH(SixwindOSBase): + pass