From 9cd1d5b6c845ad5e2b5a140d7ff665b4b7794cfc Mon Sep 17 00:00:00 2001 From: chieto Date: Thu, 25 May 2023 13:15:59 +0000 Subject: [PATCH 1/5] Removed reference to python2 --- docs/requirements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.rst b/docs/requirements.rst index fe7cb19..cc20cb4 100644 --- a/docs/requirements.rst +++ b/docs/requirements.rst @@ -5,7 +5,7 @@ Requirements * Arista EOS 4.12 or later * Arista eAPI enabled for at least one transport (see Official EOS Config Guide at arista.com for details) -* Python 2.7 or 3.4+ (Python 3 support is work in progress) +* Python 3.7+ * Pyeapi requires the netaddr Python module .. Note:: netaddr gets installed automatically if you use pip to install pyeapi From 926fd8442fd8b2bb40d89a229b74b4e33a6d3a4d Mon Sep 17 00:00:00 2001 From: chieto Date: Thu, 25 May 2023 17:13:37 +0000 Subject: [PATCH 2/5] Removed support for lower versions of python --- pyeapi/client.py | 5 ++--- pyeapi/eapilib.py | 22 +++++++++++----------- pyeapi/utils.py | 4 ++-- setup.py | 5 +---- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/pyeapi/client.py b/pyeapi/client.py index f267ea2..9383f8a 100644 --- a/pyeapi/client.py +++ b/pyeapi/client.py @@ -102,9 +102,8 @@ from configparser import ConfigParser as SafeConfigParser from configparser import Error as SafeConfigParserError except ImportError: - # Use Python 2.7 import as a fallback - from ConfigParser import SafeConfigParser - from ConfigParser import Error as SafeConfigParserError + # Throw incompatible version error + print("A supported version of configParser is missing. Please upgrade to a higher version that is supported by Python 3.7 or higher.") from pyeapi.utils import load_module, make_iterable, debug, CliVariants diff --git a/pyeapi/eapilib.py b/pyeapi/eapilib.py index 7816a39..43c937b 100644 --- a/pyeapi/eapilib.py +++ b/pyeapi/eapilib.py @@ -56,9 +56,9 @@ from http.client import HTTPConnection, HTTPSConnection from http.cookies import SimpleCookie except ImportError: - # Use Python 2.7 import as a fallback - from httplib import HTTPConnection, HTTPSConnection - from Cookie import SimpleCookie + # Throw incompatible version error + print("Could not find a suitable import for HTTPConnection, HTTPSConnection and SimpleCookie. Please install or upgrade to a higher version that is supported by Python 3.7 or higher.") + from pyeapi.utils import make_iterable @@ -250,7 +250,7 @@ def connect(self): Redefined/copied and extended from httplib.py:1105 (Python 2.6.x). This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter - to ssl.wrap_socket(), which forces SSL to check server certificate + to ssl.wrap_socket()(Now changed to ssl.SSLContext.wrap_socket() as the former has been deprecated from python 3.7), which forces SSL to check server certificate against our client certificate. """ sock = socket.create_connection((self.host, self.port), self.timeout) @@ -259,11 +259,11 @@ def connect(self): self._tunnel() # If there's no CA File, don't force Server Certificate Check if self.ca_file: - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, + self.sock = ssl.SSLContext.wrap_socket(sock, self.key_file, self.cert_file, ca_certs=self.ca_file, cert_reqs=ssl.CERT_REQUIRED) else: - self.sock = ssl.wrap_socket(sock, self.key_file, + self.sock = ssl.SSLContext.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_NONE) @@ -309,8 +309,7 @@ def authentication(self, username, password): _auth_bin = base64.encodebytes(_auth_text.encode()) _auth = _auth_bin.decode() else: - # For Python 2.7 - _auth = str(base64.encodestring(_auth_text)) + raise Exception("Incompatible python version.") _auth = _auth.replace('\n', '') self._auth = ("Authorization", "Basic %s" % _auth) @@ -449,10 +448,11 @@ def send(self, data): self.transport.endheaders(message_body=data) - try: # Python 2.7: use buffering of HTTP responses - response = self.transport.getresponse(buffering=True) - except TypeError: # Python 2.6: older, and 3.x on + try: #For Python 3.x+ response = self.transport.getresponse() + except TypeError: #For < Python3.x + print("Incompatible python version") + response_content = response.read() _LOGGER.debug('Response: status:{status}, reason:{reason}'.format( diff --git a/pyeapi/utils.py b/pyeapi/utils.py index bfc3581..a313c8b 100644 --- a/pyeapi/utils.py +++ b/pyeapi/utils.py @@ -43,8 +43,8 @@ # Try Python 3.x import first from itertools import zip_longest except ImportError: - # Use Python 2.7 import as a fallback - from itertools import izip_longest as zip_longest + # Throw incompatible version error + print("A supported version of itertools is missing. Please upgrade to a higher version that is supported by Python 3.7 or higher.") _LOGGER = logging.getLogger(__name__) _LOGGER.setLevel(logging.DEBUG) diff --git a/setup.py b/setup.py index 2103ce5..6f5b9d4 100644 --- a/setup.py +++ b/setup.py @@ -46,10 +46,7 @@ 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3 :: Only' ], keywords='networking arista eos eapi', From 0132bc708bb1fdf4cb4981723aa4e6a3e8eddb61 Mon Sep 17 00:00:00 2001 From: chieto Date: Fri, 26 May 2023 09:28:49 +0000 Subject: [PATCH 3/5] Updated EOS version to the minimum supported --- docs/requirements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.rst b/docs/requirements.rst index cc20cb4..fbb30ae 100644 --- a/docs/requirements.rst +++ b/docs/requirements.rst @@ -2,7 +2,7 @@ Requirements ############ -* Arista EOS 4.12 or later +* Arista EOS 4.22 or later * Arista eAPI enabled for at least one transport (see Official EOS Config Guide at arista.com for details) * Python 3.7+ From 871a0a13fa4b4a2888c4269061229e2acf857f30 Mon Sep 17 00:00:00 2001 From: chieto Date: Fri, 26 May 2023 15:31:18 +0100 Subject: [PATCH 4/5] Addressed formatting and error handling comments --- pyeapi/client.py | 11 +++------- pyeapi/eapilib.py | 51 ++++++++++++++--------------------------------- pyeapi/utils.py | 10 ++-------- 3 files changed, 20 insertions(+), 52 deletions(-) diff --git a/pyeapi/client.py b/pyeapi/client.py index 9383f8a..2de2fce 100644 --- a/pyeapi/client.py +++ b/pyeapi/client.py @@ -96,14 +96,9 @@ from functools import lru_cache -try: - # Try Python 3.x import first - # Note: SafeConfigParser is deprecated and replaced by ConfigParser - from configparser import ConfigParser as SafeConfigParser - from configparser import Error as SafeConfigParserError -except ImportError: - # Throw incompatible version error - print("A supported version of configParser is missing. Please upgrade to a higher version that is supported by Python 3.7 or higher.") +# Note: SafeConfigParser is deprecated and replaced by ConfigParser +from configparser import ConfigParser as SafeConfigParser +from configparser import Error as SafeConfigParserError from pyeapi.utils import load_module, make_iterable, debug, CliVariants diff --git a/pyeapi/eapilib.py b/pyeapi/eapilib.py index 43c937b..6b88b59 100644 --- a/pyeapi/eapilib.py +++ b/pyeapi/eapilib.py @@ -51,14 +51,8 @@ except ImportError: import json -try: - # Try Python 3.x import first - from http.client import HTTPConnection, HTTPSConnection - from http.cookies import SimpleCookie -except ImportError: - # Throw incompatible version error - print("Could not find a suitable import for HTTPConnection, HTTPSConnection and SimpleCookie. Please install or upgrade to a higher version that is supported by Python 3.7 or higher.") - +from http.client import HTTPConnection, HTTPSConnection +from http.cookies import SimpleCookie from pyeapi.utils import make_iterable @@ -250,8 +244,9 @@ def connect(self): Redefined/copied and extended from httplib.py:1105 (Python 2.6.x). This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter - to ssl.wrap_socket()(Now changed to ssl.SSLContext.wrap_socket() as the former has been deprecated from python 3.7), which forces SSL to check server certificate - against our client certificate. + to ssl.wrap_socket() (Now changed to ssl.SSLContext.wrap_socket() + as the former has been deprecated from python 3.7), which forces + SSL to check server certificate against our client certificate. """ sock = socket.create_connection((self.host, self.port), self.timeout) if self._tunnel_host: @@ -259,13 +254,14 @@ def connect(self): self._tunnel() # If there's no CA File, don't force Server Certificate Check if self.ca_file: - self.sock = ssl.SSLContext.wrap_socket(sock, self.key_file, self.cert_file, - ca_certs=self.ca_file, - cert_reqs=ssl.CERT_REQUIRED) + self.sock = ssl.SSLContext.wrap_socket(sock, self.key_file, + self.cert_file, + ca_certs=self.ca_file, + cert_reqs=ssl.CERT_REQUIRED) else: self.sock = ssl.SSLContext.wrap_socket(sock, self.key_file, - self.cert_file, - cert_reqs=ssl.CERT_NONE) + self.cert_file, + cert_reqs=ssl.CERT_NONE) class EapiConnection(object): @@ -302,15 +298,8 @@ def authentication(self, username, password): """ _auth_text = '{}:{}'.format(username, password) - - # Work around for Python 2.7/3.x compatibility - if int(sys.version[0]) > 2: - # For Python 3.x - _auth_bin = base64.encodebytes(_auth_text.encode()) - _auth = _auth_bin.decode() - else: - raise Exception("Incompatible python version.") - _auth = _auth.replace('\n', '') + _auth_bin = base64.encodebytes(_auth_text.encode()) + _auth = _auth_bin.decode().replace('\n', '') self._auth = ("Authorization", "Basic %s" % _auth) _LOGGER.debug('Authentication string is: {}:***'.format(username)) @@ -435,25 +424,15 @@ def send(self, data): # debug('eapi_request: %s' % data) self.transport.putrequest('POST', '/command-api') - self.transport.putheader('Content-type', 'application/json-rpc') self.transport.putheader('Content-length', '%d' % len(data)) if self._auth: self.transport.putheader(*self._auth) - - if int(sys.version[0]) > 2: - # For Python 3.x compatibility - data = data.encode() + data = data.encode() self.transport.endheaders(message_body=data) - - try: #For Python 3.x+ - response = self.transport.getresponse() - except TypeError: #For < Python3.x - print("Incompatible python version") - - + response = self.transport.getresponse() response_content = response.read() _LOGGER.debug('Response: status:{status}, reason:{reason}'.format( status=response.status, diff --git a/pyeapi/utils.py b/pyeapi/utils.py index a313c8b..13116d7 100644 --- a/pyeapi/utils.py +++ b/pyeapi/utils.py @@ -37,14 +37,8 @@ import logging.handlers from collections.abc import Iterable -from itertools import tee - -try: - # Try Python 3.x import first - from itertools import zip_longest -except ImportError: - # Throw incompatible version error - print("A supported version of itertools is missing. Please upgrade to a higher version that is supported by Python 3.7 or higher.") +from itertools import tee, zip_longest + _LOGGER = logging.getLogger(__name__) _LOGGER.setLevel(logging.DEBUG) From 81b7a38481e92fba04f6b84227e9f7dae447aa2e Mon Sep 17 00:00:00 2001 From: chieto Date: Fri, 26 May 2023 17:01:35 +0100 Subject: [PATCH 5/5] Refactored extra python2 check --- pyeapi/eapilib.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyeapi/eapilib.py b/pyeapi/eapilib.py index 6b88b59..dd207ad 100644 --- a/pyeapi/eapilib.py +++ b/pyeapi/eapilib.py @@ -36,7 +36,6 @@ for sending and receiving calls over eAPI using a HTTP/S transport. """ -import sys import socket import base64 import logging @@ -718,8 +717,7 @@ def authentication(self, username, password): self.transport.putheader("Content-type", "application/json") self.transport.putheader("Content-length", "%d" % len(data)) - if int(sys.version[0]) > 2: - data = data.encode() + data = data.encode() self.transport.endheaders(message_body=data) resp = self.transport.getresponse() if resp.status != 200: