Repository: pymeasure/pymeasure

Issue:
Deprecated telnetlib flagged by Python 3.11+
In #835 (discussion in #668 ) the telnetAdapter has been deprecated, as the telnetlib library is deprecated.
The deprecation note suggests to use the VISAAdapter.

Having added codecov, it flags deprecated telnetlib in every PR.

I see two courses of action:
1. We mark that import somehow (maybe `pragma: no cover`?), such that it is not mentioned anymore.
2. We remove telnetAdapter from pymeasure altogether.


Discussion:
A 3rd option might be to use pyvisa-py and pyserial with socket:// style URL-formatted resources.. Robert On Feb 8, 2024, at 19:15, Benedikt Burger ***@***.***> wrote:﻿
In #744 the telnetAdapter has been deprecated, as the telnetlib library is deprecated.
Having added codecov, it flags deprecated telnetlib in every PR.
I see two courses of action:

We mark that import somehow (maybe pragma: no cover?), such that it is not mentioned anymore.
We remove telnetAdapter from pymeasure altogether.


—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
> A 3rd option might be to use pyvisa-py and pyserial with socket:// style URL-formatted resources

That is suggested by the deprecation notice.

I see, we should base the telnetlib adapter on the VISAAdapter.

The question is, whether it is worth the work.
> Having added codecov, it flags deprecated telnetlib in every PR.

I don't think it's codecov that is flagging this import, because it also appears in the py3.11 run -- it's the Python interpreter I think (and it's correct in flagging it): https://github.com/pymeasure/pymeasure/actions/runs/7899943459/job/21560420178#step:7:205

Our deprecation of `TelnetAdapter` has been released for more than 6 months now (0.12.0). 
If the alternative would be significant maintenance work to avoid that warning on our CI, I'd be in favour of removing `telnetlib` with the next release. If we e.g. make instantiating `TelnetAdapter` throw an exception with clear instructions (i.e. the text of the current deprecation warning or the changelog entry), this will surface for any remaining users in a more actionable way than just an `ImportError`, which sounds good enough for me.

Resolving patch:
diff --git a/pymeasure/adapters/telnet.py b/pymeasure/adapters/telnet.py
--- a/pymeasure/adapters/telnet.py
+++ b/pymeasure/adapters/telnet.py
@@ -22,10 +22,6 @@
 # THE SOFTWARE.
 #
 
-import telnetlib
-import time
-from warnings import warn
-
 from .adapter import Adapter
 
 
@@ -33,6 +29,8 @@ class TelnetAdapter(Adapter):
     """ Adapter class for using the Python telnetlib package to allow
     communication to instruments
 
+    This Adapter has been removed from service as the underlying library is missing!
+
     .. deprecated:: 0.11.2
         The Python telnetlib module is deprecated since Python 3.11 and will be removed
         in Python 3.13 release.
@@ -40,79 +38,16 @@ class TelnetAdapter(Adapter):
         The VISAAdapter supports TCPIP socket connections. When using the VISAAdapter,
         the `resource_name` argument should be `TCPIP[board]::<host>::<port>::SOCKET`.
         see here, <https://pyvisa.readthedocs.io/en/latest/introduction/names.html>
-
-    :param host: host address of the instrument
-    :param port: TCPIP port
-    :param query_delay: delay in seconds between write and read in the ask
-        method
-    :param preprocess_reply: An optional callable used to preprocess
-        strings received from the instrument. The callable returns the
-        processed string.
-
-        .. deprecated:: 0.11
-            Implement it in the instrument's `read` method instead.
-
-    :param kwargs: Valid keyword arguments for telnetlib.Telnet, currently
-        this is only 'timeout'
     """
 
     def __init__(self, host, port=0, query_delay=0, preprocess_reply=None,
                  **kwargs):
-        warn("TelnetAdapter is deprecated, use VISAAdapter instead.", FutureWarning)
-        super().__init__(preprocess_reply=preprocess_reply)
-        self.query_delay = query_delay
-        if query_delay:
-            warn("Use Instrument.ask with query_delay argument instead of Adapter.ask.",
-                 FutureWarning)
-        self.write_termination = kwargs.pop('write_termination', "")
-        self.read_termination = kwargs.pop('read_termination', "")
-        safe_keywords = ['timeout']
-        for kw in kwargs:
-            if kw not in safe_keywords:
-                raise TypeError(
-                    f"TelnetAdapter: unexpected keyword argument '{kw}', "
-                    f"allowed are: {str(safe_keywords)}")
-        self.connection = telnetlib.Telnet(host, port, **kwargs)
-
-    def _write(self, command, **kwargs):
-        """Write a string command to the instrument appending `write_termination`.
-
-        :param str command: Command string to be sent to the instrument
-            (without termination).
-        :param kwargs: Keyword arguments for the connection itself.
-        """
-        self.connection.write((command + self.write_termination).encode(), **kwargs)
-
-    def _read(self, **kwargs):
-        """ Read something even with blocking the I/O. After something is
-        received check again to obtain a full reply.
-
-        :param kwargs: Keyword arguments for the connection itself.
-        :returns str: ASCII response of the instrument (excluding read_termination).
-        """
-        read = self.connection.read_some(**kwargs).decode() + \
-            self.connection.read_very_eager(**kwargs).decode()
-        # Python>3.8 return read.removesuffix(self.read_termination)
-        if self.read_termination:
-            return read.split(self.read_termination)[0]
-        else:
-            return read
-
-    def ask(self, command):
-        """ Writes a command to the instrument and returns the resulting ASCII
-        response
-
-        .. deprecated:: 0.11
-           Call `Instrument.ask` instead.
-
-        :param command: command string to be sent to the instrument
-        :returns: String ASCII response of the instrument
-        """
-        warn("Do not call `Adapter.ask`, but `Instrument.ask` instead.",
-             FutureWarning)
-        self.write(command)
-        time.sleep(self.query_delay)
-        return self.read()
+        raise NotImplementedError(
+            "The TelnetAdapter has been removed, as the telnetlib module is deprecated. "
+            "Use the VISAAdapter instead. The VISAAdapter supports TCPIP socket connections. "
+            "When using the VISAAdapter, the `resource_name` argument should be "
+            "`TCPIP[board]::<host>::<port>::SOCKET`. "
+            "see here, <https://pyvisa.readthedocs.io/en/latest/introduction/names.html>")
 
     def __repr__(self):
-        return "<TelnetAdapter(host=%s, port=%d)>" % (self.connection.host, self.connection.port)
+        return "<TelnetAdapter()>"


Test patch: