From 614a6d9bb9fb3b54c8808c4c93246308c75a2263 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Mon, 6 Nov 2023 15:29:03 -0800 Subject: [PATCH 1/2] refactor: dont use deprecated pkg_resources on >=3.9, some pyupgrade housekeeping fixups --- scrapli/channel/async_channel.py | 2 +- scrapli/channel/sync_channel.py | 2 +- scrapli/driver/generic/base_driver.py | 2 +- scrapli/helper.py | 19 +++++++++++++++--- .../transport/plugins/system/ptyprocess.py | 20 +++++++++---------- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/scrapli/channel/async_channel.py b/scrapli/channel/async_channel.py index fa47dc5a..652e8884 100644 --- a/scrapli/channel/async_channel.py +++ b/scrapli/channel/async_channel.py @@ -241,7 +241,7 @@ async def _read_until_prompt_or_time( if (time.time() - start) > read_duration: break - if any((channel_output in search_buf for channel_output in channel_outputs)): + if any(channel_output in search_buf for channel_output in channel_outputs): break if re.search(pattern=regex_channel_outputs_pattern, string=search_buf): break diff --git a/scrapli/channel/sync_channel.py b/scrapli/channel/sync_channel.py index 28651fd2..1584114e 100644 --- a/scrapli/channel/sync_channel.py +++ b/scrapli/channel/sync_channel.py @@ -238,7 +238,7 @@ def _read_until_prompt_or_time( if (time.time() - start) > read_duration: break - if any((channel_output in search_buf for channel_output in channel_outputs)): + if any(channel_output in search_buf for channel_output in channel_outputs): break if re.search(pattern=regex_channel_outputs_pattern, string=search_buf): break diff --git a/scrapli/driver/generic/base_driver.py b/scrapli/driver/generic/base_driver.py index 81a4971c..b0a31f02 100644 --- a/scrapli/driver/generic/base_driver.py +++ b/scrapli/driver/generic/base_driver.py @@ -337,7 +337,7 @@ def _pre_send_from_file(file: str, caller: str) -> List[str]: raise ScrapliTypeError(f"`{caller}` expects a string path to a file, got {type(file)}") resolved_file = resolve_file(file) - with open(resolved_file, "r", encoding="utf-8") as f: + with open(resolved_file, encoding="utf-8") as f: commands = f.read().splitlines() return commands diff --git a/scrapli/helper.py b/scrapli/helper.py index 648da0f6..06eeb776 100644 --- a/scrapli/helper.py +++ b/scrapli/helper.py @@ -1,5 +1,6 @@ """scrapli.helper""" import importlib +import sys import urllib.request from io import BytesIO, TextIOWrapper from pathlib import Path @@ -7,12 +8,22 @@ from typing import Any, Dict, List, Optional, TextIO, Union from warnings import warn -import pkg_resources - from scrapli.exceptions import ScrapliValueError from scrapli.logging import logger from scrapli.settings import Settings +if sys.version_info >= (3, 9): + import importlib.resources as importlib_resources +else: + import pkg_resources as importlib_resources + + +def _textfsm_get_template_directory() -> str: + if sys.version_info >= (3, 9): + return f"{importlib_resources.files('ntc_templates')}/templates" + + return importlib_resources.resource_filename("ntc_templates", "templates") + def _textfsm_get_template(platform: str, command: str) -> Optional[TextIO]: """ @@ -43,7 +54,9 @@ def _textfsm_get_template(platform: str, command: str) -> Optional[TextIO]: ) user_warning(title=title, message=message) return None - template_dir = pkg_resources.resource_filename("ntc_templates", "templates") + + template_dir = _textfsm_get_template_directory() + cli_table = CliTable("index", template_dir) template_index = cli_table.index.GetRowMatch({"Platform": platform, "Command": command}) if not template_index: diff --git a/scrapli/transport/plugins/system/ptyprocess.py b/scrapli/transport/plugins/system/ptyprocess.py index 06f465da..2cb3c2ef 100644 --- a/scrapli/transport/plugins/system/ptyprocess.py +++ b/scrapli/transport/plugins/system/ptyprocess.py @@ -85,7 +85,7 @@ def _make_eof_intr() -> None: raise ValueError("No stream has a fileno") intr = ord(termios.tcgetattr(fd)[6][VINTR]) eof = ord(termios.tcgetattr(fd)[6][VEOF]) - except (ImportError, OSError, IOError, ValueError, termios.error): + except (ImportError, OSError, ValueError, termios.error): # unless the controlling process is also not a terminal, # such as cron(1), or when stdin and stdout are both closed. # Fall-back to using CEOF and CINTR. There @@ -157,7 +157,7 @@ def _setecho(fd: int, state: bool) -> None: attr = termios.tcgetattr(fd) except termios.error as err: if err.args[0] == errno.EINVAL: - raise IOError(err.args[0], "%s: %s." % (err.args[1], errmsg)) + raise OSError(err.args[0], "{}: {}.".format(err.args[1], errmsg)) raise if state: @@ -169,9 +169,9 @@ def _setecho(fd: int, state: bool) -> None: # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent and # blocked on some platforms. TCSADRAIN would probably be ideal. termios.tcsetattr(fd, termios.TCSANOW, attr) - except IOError as err: + except OSError as err: if err.args[0] == errno.EINVAL: - raise IOError(err.args[0], "%s: %s." % (err.args[1], errmsg)) + raise OSError(err.args[0], "{}: {}.".format(err.args[1], errmsg)) raise @@ -196,8 +196,8 @@ def __init__(self, pid: int, fd: int) -> None: _make_eof_intr() # Ensure _EOF and _INTR are calculated self.pid = pid self.fd = fd - readf = io.open(fd, "rb", buffering=0) - writef = io.open(fd, "wb", buffering=0, closefd=False) + readf = open(fd, "rb", buffering=0) + writef = open(fd, "wb", buffering=0, closefd=False) self.fileobj = io.BufferedRWPair(readf, writef) # type: ignore self.terminated = False @@ -283,7 +283,7 @@ def spawn( if pid == CHILD: try: _setwinsize(fd=STDIN_FILENO, rows=rows, cols=cols) - except IOError as err: + except OSError as err: if err.args[0] not in (errno.EINVAL, errno.ENOTTY): raise @@ -291,7 +291,7 @@ def spawn( if echo is False: try: _setecho(STDIN_FILENO, False) - except (IOError, termios.error) as err: + except (OSError, termios.error) as err: if err.args[0] not in (errno.EINVAL, errno.ENOTTY): raise @@ -350,7 +350,7 @@ def spawn( try: inst.setwinsize(rows=rows, cols=cols) - except IOError as err: + except OSError as err: if err.args[0] not in (errno.EINVAL, errno.ENOTTY, errno.ENXIO): raise @@ -481,7 +481,7 @@ def read(self, size: int = 1024) -> bytes: """ try: s = self.fileobj.read1(size) - except (OSError, IOError) as err: + except OSError as err: if err.args[0] == errno.EIO: # Linux-style EOF self.flag_eof = True From d4f876163e99e7eb2864a5bce81236bc0f9d5221 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Tue, 7 Nov 2023 07:50:24 -0800 Subject: [PATCH 2/2] chore: update pytprocess docstring raises after pyupdate fixups --- scrapli/transport/plugins/system/ptyprocess.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scrapli/transport/plugins/system/ptyprocess.py b/scrapli/transport/plugins/system/ptyprocess.py index 2cb3c2ef..9f4ac2de 100644 --- a/scrapli/transport/plugins/system/ptyprocess.py +++ b/scrapli/transport/plugins/system/ptyprocess.py @@ -141,9 +141,9 @@ def _setecho(fd: int, state: bool) -> None: None Raises: - IOError: if termios raises an exception getting the fd + OSError: if termios raises an exception getting the fd or raises an exception setting the + echo state on the fd termios.error: also if termios rasies an exception gettign fd... unclear why the two errors! - IOError: if termios raises an exception setting the echo state on the fd """ import termios @@ -244,7 +244,7 @@ def spawn( ScrapliValueError: if no ssh binary found on PATH Exception: IOError - if unable to set window size of child process Exception: OSError - if unable to spawn command in child process - IOError: failing to reset window size + OSError: failing to reset window size exception: if we get an exception decoding output """