File pynut-replace-telnetlib.patch of Package nut

From 94f6109dfcc34952b00179526b84a6d82eb24e34 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 31 Jan 2025 06:06:00 +0000
Subject: [PATCH 01/16] added replacement read_until and leftover buffer

---
 scripts/python/module/PyNUT.py.in | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index 6838fc373a..484df8b25a 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -84,6 +84,7 @@ class PyNUTClient :
     __password    = None
     __timeout     = None
     __srv_handler = None
+    __recv_leftover = b''
 
     __version     = "1.6.0"
     __release     = "2023-01-18"
@@ -122,6 +123,19 @@ timeout  : Timeout used to wait for network response
         except :
             pass
 
+    def __read_until(self, finished_reading_data):
+        data = self.__recv_leftover
+        while (data_end_index := data.find(finished_reading_data)) == -1:
+            data += self.__srv_handler.recv(50)  # nut_telnetlib.py uses 50
+        data_end_index += len(finished_reading_data)
+
+        if data_end_index == len(data):
+            self.__recv_leftover = b''
+        else:
+            self.__recv_leftover = data[data_end_index:]
+            data = data[:data_end_index]
+        return data
+
     def __connect( self ) :
         """ Connects to the defined server
 

From 60a7ca19a87491be7b58f693977ea5a365290842 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 31 Jan 2025 06:14:33 +0000
Subject: [PATCH 02/16] switch to socket send and replacement read_until

---
 scripts/python/module/PyNUT.py.in | 107 ++++++++++++++----------------
 1 file changed, 51 insertions(+), 56 deletions(-)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index 484df8b25a..18f43954ca 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -55,8 +55,16 @@
 # 2023-01-18 Jim Klimov <jimklimov+nut@gmail.com> - Version 1.6.0
 #            Added CheckUPSAvailable() method originally by Michal Hlavinka
 #            from 2013-01-07 RedHat/Fedora packaging
+#
+# 2024-07-01 Jim Klimov <jimklimov+nut@gmail.com> - Version 1.7.0
+#            Re-arranged dependency on telnetlib module (deprecated/removed
+#            since Python 3.11/3.13), so we can fall back on a privately
+#            stashed copy until a better solution is developed.
+#
+# 2025-01-31 cgar <github.com/cgarz> - Version 1.8.0
+#            Removed telnetlib dependency. Switched to using socket directly.
 
-import telnetlib
+import socket
 
 class PyNUTError( Exception ) :
     """ Base class for custom exceptions """
@@ -119,7 +113,7 @@ timeout  : Timeout used to wait for network response
     def __del__( self ) :
         """ Class destructor method """
         try :
-            self.__srv_handler.write( b"LOGOUT\n" )
+            self.__srv_handler.send( b"LOGOUT\n" )
         except :
             pass
 
@@ -145,23 +139,24 @@ if something goes wrong.
         if self.__debug :
             print( "[DEBUG] Connecting to host" )
 
-        self.__srv_handler = telnetlib.Telnet( self.__host, self.__port )
+        self.__srv_handler = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
+        self.__srv_handler.connect( (self.__host, self.__port) )
 
         if self.__login != None :
-            self.__srv_handler.write( ("USERNAME %s\n" % self.__login).encode('ascii') )
-            result = self.__srv_handler.read_until( b"\n", self.__timeout )
+            self.__srv_handler.send( ("USERNAME %s\n" % self.__login).encode('ascii') )
+            result = self.__read_until( b"\n" )
             if result[:2] != b"OK" :
                 raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
         if self.__password != None :
-            self.__srv_handler.write( ("PASSWORD %s\n" % self.__password).encode('ascii') )
-            result = self.__srv_handler.read_until( b"\n", self.__timeout )
+            self.__srv_handler.send( ("PASSWORD %s\n" % self.__password).encode('ascii') )
+            result = self.__read_until( b"\n" )
             if result[:2] != b"OK" :
                 if result == b"ERR INVALID-ARGUMENT\n" :
                     # Quote the password (if it has whitespace etc)
                     # TODO: Escape special chard like NUT does?
-                    self.__srv_handler.write( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') )
-                    result = self.__srv_handler.read_until( b"\n", self.__timeout )
+                    self.__srv_handler.send( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') )
+                    result = self.__read_until( b"\n" )
                     if result[:2] != b"OK" :
                         raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
                 else:
@@ -179,12 +174,12 @@ which is of little concern for Python2 but is important in Python3
         if self.__debug :
             print( "[DEBUG] GetUPSList from server" )
 
-        self.__srv_handler.write( b"LIST UPS\n" )
-        result = self.__srv_handler.read_until( b"\n" )
-        if result != b"BEGIN LIST UPS\n" :
+        self.__srv_handler.send( b"LIST UPS\n" )
+        result = self.__read_until( b"\n" )
+        if result != b"BEGIN LIST UPS\n":
             raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
-        result = self.__srv_handler.read_until( b"END LIST UPS\n" )
+        result = self.__read_until( b"END LIST UPS\n" )
         ups_list = {}
 
         for line in result.split( b"\n" ) :
@@ -219,13 +214,13 @@ available vars.
         if self.__debug :
             print( "[DEBUG] GetUPSVars called..." )
 
-        self.__srv_handler.write( ("LIST VAR %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("LIST VAR %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if result != ("BEGIN LIST VAR %s\n" % ups).encode('ascii') :
             raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
         ups_vars   = {}
-        result     = self.__srv_handler.read_until( ("END LIST VAR %s\n" % ups).encode('ascii') )
+        result     = self.__read_until( ("END LIST VAR %s\n" % ups).encode('ascii') )
         offset     = len( ("VAR %s " % ups ).encode('ascii') )
         end_offset = 0 - ( len( ("END LIST VAR %s\n" % ups).encode('ascii') ) + 1 )
 
@@ -245,12 +240,12 @@ The result is True (reachable) or False (unreachable)
         if self.__debug :
             print( "[DEBUG] CheckUPSAvailable called..." )
 
-        self.__srv_handler.write( ("LIST CMD %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') :
             return False
 
-        self.__srv_handler.read_until( ("END LIST CMD %s\n" % ups).encode('ascii') )
+        self.__read_until( ("END LIST CMD %s\n" % ups).encode('ascii') )
         return True
 
     def GetUPSCommands( self, ups="" ) :
@@ -262,13 +257,13 @@ of the command as value
         if self.__debug :
             print( "[DEBUG] GetUPSCommands called..." )
 
-        self.__srv_handler.write( ("LIST CMD %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') :
             raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
         ups_cmds   = {}
-        result     = self.__srv_handler.read_until( ("END LIST CMD %s\n" % ups).encode('ascii') )
+        result     = self.__read_until( ("END LIST CMD %s\n" % ups).encode('ascii') )
         offset     = len( ("CMD %s " % ups).encode('ascii') )
         end_offset = 0 - ( len( ("END LIST CMD %s\n" % ups).encode('ascii') ) + 1 )
 
@@ -277,8 +272,8 @@ of the command as value
 
             # For each var we try to get the available description
             try :
-                self.__srv_handler.write( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') )
-                temp = self.__srv_handler.read_until( b"\n" )
+                self.__srv_handler.send( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') )
+                temp = self.__read_until( b"\n" )
                 if temp[:7] != b"CMDDESC" :
                     raise PyNUTError
                 else :
@@ -299,12 +294,12 @@ The result is presented as a dictionary containing 'key->val' pairs
         if self.__debug :
             print( "[DEBUG] GetUPSVars from '%s'..." % ups )
 
-        self.__srv_handler.write( ("LIST RW %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("LIST RW %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result != ("BEGIN LIST RW %s\n" % ups).encode('ascii') ) :
             raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
-        result     = self.__srv_handler.read_until( ("END LIST RW %s\n" % ups).encode('ascii') )
+        result     = self.__read_until( ("END LIST RW %s\n" % ups).encode('ascii') )
         offset     = len( ("VAR %s" % ups).encode('ascii') )
         end_offset = 0 - ( len( ("END LIST RW %s\n" % ups).encode('ascii') ) + 1 )
         rw_vars    = {}
@@ -327,8 +322,8 @@ The variable must be a writable value (cf GetRWVars) and you must have the prope
 rights to set it (maybe login/password).
         """
 
-        self.__srv_handler.write( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result == b"OK\n" ) :
             return( "OK" )
         else :
@@ -343,8 +338,8 @@ Returns OK on success or raises an error
         if self.__debug :
             print( "[DEBUG] RunUPSCommand called..." )
 
-        self.__srv_handler.write( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result == b"OK\n" ) :
             return( "OK" )
         else :
@@ -369,12 +364,12 @@ of connection.
                 print( "[DEBUG] DeviceLogin: %s is not a valid UPS" % ups )
             raise PyNUTError( "ERR UNKNOWN-UPS" )
 
-        self.__srv_handler.write( ("LOGIN %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("LOGIN %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result.startswith( ("User %s@" % self.__login).encode('ascii')) and result.endswith (("[%s]\n" % ups).encode('ascii')) ):
             # User dummy-user@127.0.0.1 logged into UPS [dummy]
             # Read next line then
-            result = self.__srv_handler.read_until( b"\n" )
+            result = self.__read_until( b"\n" )
         if ( result == b"OK\n" ) :
             return( "OK" )
         else :
@@ -392,13 +387,13 @@ NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
         if self.__debug :
             print( "[DEBUG] PRIMARY called..." )
 
-        self.__srv_handler.write( ("PRIMARY %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("PRIMARY %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result != b"OK PRIMARY-GRANTED\n" ) :
             if self.__debug :
                 print( "[DEBUG] Retrying: MASTER called..." )
-            self.__srv_handler.write( ("MASTER %s\n" % ups).encode('ascii') )
-            result = self.__srv_handler.read_until( b"\n" )
+            self.__srv_handler.send( ("MASTER %s\n" % ups).encode('ascii') )
+            result = self.__read_until( b"\n" )
             if ( result != b"OK MASTER-GRANTED\n" ) :
                 if self.__debug :
                     print( "[DEBUG] Primary level functions are not available" )
@@ -406,8 +401,8 @@ NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
 
         if self.__debug :
             print( "[DEBUG] FSD called..." )
-        self.__srv_handler.write( ("FSD %s\n" % ups).encode('ascii') )
-        result = self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( ("FSD %s\n" % ups).encode('ascii') )
+        result = self.__read_until( b"\n" )
         if ( result == b"OK FSD-SET\n" ) :
             return( "OK" )
         else :
@@ -420,8 +415,8 @@ NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
         if self.__debug :
             print( "[DEBUG] HELP called..." )
 
-        self.__srv_handler.write( b"HELP\n" )
-        return self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( b"HELP\n" )
+        return self.__read_until( b"\n" )
 
     def ver(self) :
         """ Send VER command
@@ -430,8 +425,8 @@ NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY
         if self.__debug :
             print( "[DEBUG] VER called..." )
 
-        self.__srv_handler.write( b"VER\n" )
-        return self.__srv_handler.read_until( b"\n" )
+        self.__srv_handler.send( b"VER\n" )
+        return self.__read_until( b"\n" )
 
     def ListClients( self, ups = None ) :
         """ Returns the list of connected clients from the NUT server
@@ -449,12 +444,12 @@ The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list o
             raise PyNUTError( "ERR UNKNOWN-UPS" )
 
         if ups:
-            self.__srv_handler.write( ("LIST CLIENT %s\n" % ups).encode('ascii') )
+            self.__srv_handler.send( ("LIST CLIENT %s\n" % ups).encode('ascii') )
         else:
             # NOTE: Currently NUT does not support just listing all clients
             # (not providing an "ups" argument) => NUT_ERR_INVALID_ARGUMENT
-            self.__srv_handler.write( b"LIST CLIENT\n" )
-        result = self.__srv_handler.read_until( b"\n" )
+            self.__srv_handler.send( b"LIST CLIENT\n" )
+        result = self.__read_until( b"\n" )
         if ( (ups and result != ("BEGIN LIST CLIENT %s\n" % ups).encode('ascii')) or (ups is None and result != b"BEGIN LIST CLIENT\n") ):
             if ups is None and (result == b"ERR INVALID-ARGUMENT\n") :
                 # For ups==None, list all upses, list their clients
@@ -472,11 +467,11 @@ The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list o
 
             raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') )
 
-        if ups :
-            result = self.__srv_handler.read_until( ("END LIST CLIENT %s\n" % ups).encode('ascii') )
+        if ups:
+            result = self.__read_until( ("END LIST CLIENT %s\n" % ups).encode('ascii') )
         else:
             # Should not get here with current NUT:
-            result = self.__srv_handler.read_until( b"END LIST CLIENT\n" )
+            result = self.__read_until( b"END LIST CLIENT\n" )
         ups_list = {}
 
         for line in result.split( b"\n" ):

From 1209078c62ad4b6138029f59b33dff4008235ad5 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 31 Jan 2025 06:19:16 +0000
Subject: [PATCH 03/16] Switch to socket timeout, fix its init argument

---
 scripts/python/module/PyNUT.py.in | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index 18f43954ca..66e4b6c0d6 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -105,7 +105,7 @@ timeout  : Timeout used to wait for network response
         self.__port     = port
         self.__login    = login
         self.__password = password
-        self.__timeout  = 5
+        self.__timeout  = timeout
 
         self.__connect()
 
@@ -141,6 +141,7 @@ if something goes wrong.
 
         self.__srv_handler = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
         self.__srv_handler.connect( (self.__host, self.__port) )
+        self.__srv_handler.settimeout( self.__timeout )
 
         if self.__login != None :
             self.__srv_handler.send( ("USERNAME %s\n" % self.__login).encode('ascii') )

From 7ee628f920bd11dd5565b0e10cbfa6fd54aa23c8 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Tue, 4 Feb 2025 22:27:01 +0000
Subject: [PATCH 04/16] Remove walrus op for older python compatibility.

---
 scripts/python/module/PyNUT.py.in | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index 66e4b6c0d6..ced5231193 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -119,8 +119,12 @@ timeout  : Timeout used to wait for network response
 
     def __read_until(self, finished_reading_data):
         data = self.__recv_leftover
-        while (data_end_index := data.find(finished_reading_data)) == -1:
-            data += self.__srv_handler.recv(50)  # nut_telnetlib.py uses 50
+        while True:
+            data_end_index = data.find(finished_reading_data)
+            if data_end_index == -1:
+                data += self.__srv_handler.recv(50)  # nut_telnetlib.py uses 50
+            else:
+                break
         data_end_index += len(finished_reading_data)
 
         if data_end_index == len(data):

From 9f81e81af3f8bed3fb1e501b5c0b8f638f28f125 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 7 Feb 2025 08:45:40 +0000
Subject: [PATCH 05/16] Use socket create_connection instead of connect,
 Handles choosing IPv4 and IPv6 automatically.

---
 scripts/python/module/PyNUT.py.in | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index ced5231193..b815c4af73 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -143,9 +143,10 @@ if something goes wrong.
         if self.__debug :
             print( "[DEBUG] Connecting to host" )
 
-        self.__srv_handler = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
-        self.__srv_handler.connect( (self.__host, self.__port) )
-        self.__srv_handler.settimeout( self.__timeout )
+        self.__srv_handler = socket.create_connection(
+            (self.__host, self.__port),
+            self.__timeout
+        )
 
         if self.__login != None :
             self.__srv_handler.send( ("USERNAME %s\n" % self.__login).encode('ascii') )

From cf0ea3e447f3d97237ba8575202437a59355bd3a Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 7 Feb 2025 08:47:38 +0000
Subject: [PATCH 06/16] Update PyNUT changelog, bump version to 1.8.0

---
 scripts/python/module/PyNUT.py.in | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/scripts/python/module/PyNUT.py.in b/scripts/python/module/PyNUT.py.in
index b815c4af73..0e136d3669 100644
--- a/scripts/python/module/PyNUT.py.in
+++ b/scripts/python/module/PyNUT.py.in
@@ -74,8 +82,8 @@ class PyNUTClient :
     __srv_handler = None
     __recv_leftover = b''
 
-    __version     = "1.6.0"
-    __release     = "2023-01-18"
+    __version     = "1.8.0"
+    __release     = "2025-02-07"
 
 
     def __init__( self, host="127.0.0.1", port=3493, login=None, password=None, debug=False, timeout=5 ) :


From 0488ec573943468fb0e0570c396b66c2dfcc35d9 Mon Sep 17 00:00:00 2001
From: cgarz <20268068+cgarz@users.noreply.github.com>
Date: Fri, 7 Feb 2025 08:57:21 +0000
Subject: [PATCH 12/16] Update setup.py.in, remove install_requires lib

---
 scripts/python/module/setup.py.in | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in
index 10ada3ecd6..d520c960f9 100644
--- a/scripts/python/module/setup.py.in
+++ b/scripts/python/module/setup.py.in
@@ -30,7 +30,6 @@ setup(
     #data_files =	[('', ['tox.ini'])],
     #scripts    =	['PyNUTClient/test_nutclient.py', 'PyNUTClient/__init__.py'],
     python_requires =	'>=2.6',
-    # install_requires =	['telnetlib'],	# NOTE: telnetlib.py is part of Python core for tested 2.x and 3.x versions, not something 'pip' can download
     keywords =	['pypi', 'cicd', 'python', 'nut', 'Network UPS Tools'],
     classifiers = [
         "Development Status :: 5 - Production/Stable",

From 6d671b039e6df10091f6219ed9ae7169bf25c6e5 Mon Sep 17 00:00:00 2001
From: Jim Klimov <jimklimov+nut@gmail.com>
Date: Fri, 7 Feb 2025 12:24:14 +0100
Subject: [PATCH 14/16] configure.ac: restore nut_with_pynut_py* checks from
 v2.8.2, but test for "socket" instead of "telnetlib" module [#2183]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
---
 configure.ac | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/configure.ac b/configure.ac
index 07febb3cb8..8d278d8085 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2384,7 +2384,7 @@ if test x"${nut_with_pynut}" != xno \
     if test -n "${PYTHON2}" \
     && (command -v ${PYTHON2} || which ${PYTHON2}) >/dev/null 2>/dev/null \
     ; then
-        if ${PYTHON2} -c "import telnetlib" \
+        if ${PYTHON2} -c "import socket" \
         ; then
             nut_with_pynut_py2="yes"
         fi
@@ -2393,7 +2393,7 @@ if test x"${nut_with_pynut}" != xno \
     if test -n "${PYTHON3}" \
     && (command -v ${PYTHON3} || which ${PYTHON3}) >/dev/null 2>/dev/null \
     ; then
-        if ${PYTHON3} -c "import telnetlib" \
+        if ${PYTHON3} -c "import socket" \
         ; then
             nut_with_pynut_py3="yes"
         fi
@@ -2404,7 +2404,7 @@ if test x"${nut_with_pynut}" != xno \
     && (command -v ${PYTHON} || which ${PYTHON}) >/dev/null 2>/dev/null \
     && test "${PYTHON}" != "${PYTHON2}" -a "${PYTHON}" != "${PYTHON3}" \
     ; then
-        if ${PYTHON} -c "import telnetlib" \
+        if ${PYTHON} -c "import socket" \
         ; then
             nut_with_pynut_py="yes"
         fi

From c5540c43d28d7bfcae9426b92a44a805d7ac27bd Mon Sep 17 00:00:00 2001
From: Jim Klimov <jimklimov+nut@gmail.com>
Date: Fri, 7 Feb 2025 15:32:34 +0100
Subject: [PATCH 16/16] tests/NIT/nit.sh: update comment about use of two
 explicit localhost IPv4/6 addresses, not a name, for upsd.conf

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
---
 tests/NIT/nit.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/NIT/nit.sh b/tests/NIT/nit.sh
index befec52803..cf0a98bb7f 100755
--- a/tests/NIT/nit.sh
+++ b/tests/NIT/nit.sh
@@ -363,8 +363,8 @@ EOF
     fi
 
     # Some systems listining on symbolic "localhost" actually
-    # only bind to IPv6, and Python telnetlib resolves IPv4
-    # and fails its connection tests. Others fare well with
+    # only bind to IPv6, and some (Python) client might resolve
+    # IPv4 and fail its connection tests. Others fare well with
     # both addresses in one command.
     for LH in 127.0.0.1 '::1' ; do
         if (
openSUSE Build Service is sponsored by