[Python-checkins] gh-104773: PEP 594: Remove the telnetlib module (#104778)
vstinner
webhook-mailer at python.org
Tue May 23 03:09:10 EDT 2023
https://github.com/python/cpython/commit/9dc476be2dcfc9bcf53bcb83f4b8d555682d0600
commit: 9dc476be2dcfc9bcf53bcb83f4b8d555682d0600
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2023-05-23T07:09:02Z
summary:
gh-104773: PEP 594: Remove the telnetlib module (#104778)
files:
A Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst
D Doc/library/telnetlib.rst
D Lib/telnetlib.py
D Lib/test/test_telnetlib.py
M Doc/library/superseded.rst
M Doc/tools/.nitignore
M Doc/whatsnew/2.6.rst
M Doc/whatsnew/3.11.rst
M Doc/whatsnew/3.12.rst
M Doc/whatsnew/3.13.rst
M Doc/whatsnew/3.6.rst
M Misc/NEWS.d/3.9.0a1.rst
M Python/stdlib_module_names.h
M Tools/wasm/wasm_assets.py
diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst
index aaf66ea121d3..e4a473f71284 100644
--- a/Doc/library/superseded.rst
+++ b/Doc/library/superseded.rst
@@ -27,6 +27,5 @@ backwards compatibility. They have been superseded by other modules.
sndhdr.rst
spwd.rst
sunau.rst
- telnetlib.rst
uu.rst
xdrlib.rst
diff --git a/Doc/library/telnetlib.rst b/Doc/library/telnetlib.rst
deleted file mode 100644
index 5a993dc42a5a..000000000000
--- a/Doc/library/telnetlib.rst
+++ /dev/null
@@ -1,262 +0,0 @@
-:mod:`telnetlib` --- Telnet client
-==================================
-
-.. module:: telnetlib
- :synopsis: Telnet client class.
- :deprecated:
-
-.. sectionauthor:: Skip Montanaro <skip at pobox.com>
-
-**Source code:** :source:`Lib/telnetlib.py`
-
-.. index:: single: protocol; Telnet
-
-.. deprecated-removed:: 3.11 3.13
- The :mod:`telnetlib` module is deprecated
- (see :pep:`PEP 594 <594#telnetlib>` for details and alternatives).
-
---------------
-
-The :mod:`telnetlib` module provides a :class:`Telnet` class that implements the
-Telnet protocol. See :rfc:`854` for details about the protocol. In addition, it
-provides symbolic constants for the protocol characters (see below), and for the
-telnet options. The symbolic names of the telnet options follow the definitions
-in ``arpa/telnet.h``, with the leading ``TELOPT_`` removed. For symbolic names
-of options which are traditionally not included in ``arpa/telnet.h``, see the
-module source itself.
-
-The symbolic constants for the telnet commands are: IAC, DONT, DO, WONT, WILL,
-SE (Subnegotiation End), NOP (No Operation), DM (Data Mark), BRK (Break), IP
-(Interrupt process), AO (Abort output), AYT (Are You There), EC (Erase
-Character), EL (Erase Line), GA (Go Ahead), SB (Subnegotiation Begin).
-
-.. include:: ../includes/wasm-notavail.rst
-
-.. class:: Telnet(host=None, port=0[, timeout])
-
- :class:`Telnet` represents a connection to a Telnet server. The instance is
- initially not connected by default; the :meth:`~Telnet.open` method must be used to
- establish a connection. Alternatively, the host name and optional port
- number can be passed to the constructor too, in which case the connection to
- the server will be established before the constructor returns. The optional
- *timeout* parameter specifies a timeout in seconds for blocking operations
- like the connection attempt (if not specified, the global default timeout
- setting will be used).
-
- Do not reopen an already connected instance.
-
- This class has many :meth:`read_\*` methods. Note that some of them raise
- :exc:`EOFError` when the end of the connection is read, because they can return
- an empty string for other reasons. See the individual descriptions below.
-
- A :class:`Telnet` object is a context manager and can be used in a
- :keyword:`with` statement. When the :keyword:`!with` block ends, the
- :meth:`close` method is called::
-
- >>> from telnetlib import Telnet
- >>> with Telnet('localhost', 23) as tn:
- ... tn.interact()
- ...
-
- .. versionchanged:: 3.6 Context manager support added
-
-
-.. seealso::
-
- :rfc:`854` - Telnet Protocol Specification
- Definition of the Telnet protocol.
-
-
-.. _telnet-objects:
-
-Telnet Objects
---------------
-
-:class:`Telnet` instances have the following methods:
-
-
-.. method:: Telnet.read_until(expected, timeout=None)
-
- Read until a given byte string, *expected*, is encountered or until *timeout*
- seconds have passed.
-
- When no match is found, return whatever is available instead, possibly empty
- bytes. Raise :exc:`EOFError` if the connection is closed and no cooked data
- is available.
-
-
-.. method:: Telnet.read_all()
-
- Read all data until EOF as bytes; block until connection closed.
-
-
-.. method:: Telnet.read_some()
-
- Read at least one byte of cooked data unless EOF is hit. Return ``b''`` if
- EOF is hit. Block if no data is immediately available.
-
-
-.. method:: Telnet.read_very_eager()
-
- Read everything that can be without blocking in I/O (eager).
-
- Raise :exc:`EOFError` if connection closed and no cooked data available.
- Return ``b''`` if no cooked data available otherwise. Do not block unless in
- the midst of an IAC sequence.
-
-
-.. method:: Telnet.read_eager()
-
- Read readily available data.
-
- Raise :exc:`EOFError` if connection closed and no cooked data available.
- Return ``b''`` if no cooked data available otherwise. Do not block unless in
- the midst of an IAC sequence.
-
-
-.. method:: Telnet.read_lazy()
-
- Process and return data already in the queues (lazy).
-
- Raise :exc:`EOFError` if connection closed and no data available. Return
- ``b''`` if no cooked data available otherwise. Do not block unless in the
- midst of an IAC sequence.
-
-
-.. method:: Telnet.read_very_lazy()
-
- Return any data available in the cooked queue (very lazy).
-
- Raise :exc:`EOFError` if connection closed and no data available. Return
- ``b''`` if no cooked data available otherwise. This method never blocks.
-
-
-.. method:: Telnet.read_sb_data()
-
- Return the data collected between a SB/SE pair (suboption begin/end). The
- callback should access these data when it was invoked with a ``SE`` command.
- This method never blocks.
-
-
-.. method:: Telnet.open(host, port=0[, timeout])
-
- Connect to a host. The optional second argument is the port number, which
- defaults to the standard Telnet port (23). The optional *timeout* parameter
- specifies a timeout in seconds for blocking operations like the connection
- attempt (if not specified, the global default timeout setting will be used).
-
- Do not try to reopen an already connected instance.
-
- .. audit-event:: telnetlib.Telnet.open self,host,port telnetlib.Telnet.open
-
-
-.. method:: Telnet.msg(msg, *args)
-
- Print a debug message when the debug level is ``>`` 0. If extra arguments are
- present, they are substituted in the message using the standard string
- formatting operator.
-
-
-.. method:: Telnet.set_debuglevel(debuglevel)
-
- Set the debug level. The higher the value of *debuglevel*, the more debug
- output you get (on ``sys.stdout``).
-
-
-.. method:: Telnet.close()
-
- Close the connection.
-
-
-.. method:: Telnet.get_socket()
-
- Return the socket object used internally.
-
-
-.. method:: Telnet.fileno()
-
- Return the file descriptor of the socket object used internally.
-
-
-.. method:: Telnet.write(buffer)
-
- Write a byte string to the socket, doubling any IAC characters. This can
- block if the connection is blocked. May raise :exc:`OSError` if the
- connection is closed.
-
- .. audit-event:: telnetlib.Telnet.write self,buffer telnetlib.Telnet.write
-
- .. versionchanged:: 3.3
- This method used to raise :exc:`socket.error`, which is now an alias
- of :exc:`OSError`.
-
-
-.. method:: Telnet.interact()
-
- Interaction function, emulates a very dumb Telnet client.
-
-
-.. method:: Telnet.mt_interact()
-
- Multithreaded version of :meth:`interact`.
-
-
-.. method:: Telnet.expect(list, timeout=None)
-
- Read until one from a list of a regular expressions matches.
-
- The first argument is a list of regular expressions, either compiled
- (:ref:`regex objects <re-objects>`) or uncompiled (byte strings). The
- optional second argument is a timeout, in seconds; the default is to block
- indefinitely.
-
- Return a tuple of three items: the index in the list of the first regular
- expression that matches; the match object returned; and the bytes read up
- till and including the match.
-
- If end of file is found and no bytes were read, raise :exc:`EOFError`.
- Otherwise, when nothing matches, return ``(-1, None, data)`` where *data* is
- the bytes received so far (may be empty bytes if a timeout happened).
-
- If a regular expression ends with a greedy match (such as ``.*``) or if more
- than one expression can match the same input, the results are
- non-deterministic, and may depend on the I/O timing.
-
-
-.. method:: Telnet.set_option_negotiation_callback(callback)
-
- Each time a telnet option is read on the input flow, this *callback* (if set) is
- called with the following parameters: callback(telnet socket, command
- (DO/DONT/WILL/WONT), option). No other action is done afterwards by telnetlib.
-
-
-.. _telnet-example:
-
-Telnet Example
---------------
-
-.. sectionauthor:: Peter Funk <pf at artcom-gmbh.de>
-
-
-A simple example illustrating typical use::
-
- import getpass
- import telnetlib
-
- HOST = "localhost"
- user = input("Enter your remote account: ")
- password = getpass.getpass()
-
- tn = telnetlib.Telnet(HOST)
-
- tn.read_until(b"login: ")
- tn.write(user.encode('ascii') + b"\n")
- if password:
- tn.read_until(b"Password: ")
- tn.write(password.encode('ascii') + b"\n")
-
- tn.write(b"ls\n")
- tn.write(b"exit\n")
-
- print(tn.read_all().decode('ascii'))
-
diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore
index 1d3503bf06f0..554e31ff51dd 100644
--- a/Doc/tools/.nitignore
+++ b/Doc/tools/.nitignore
@@ -215,7 +215,6 @@ Doc/library/sys_path_init.rst
Doc/library/sysconfig.rst
Doc/library/syslog.rst
Doc/library/tarfile.rst
-Doc/library/telnetlib.rst
Doc/library/tempfile.rst
Doc/library/termios.rst
Doc/library/test.rst
diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst
index 84bb651e68ee..7236e1cad7c8 100644
--- a/Doc/whatsnew/2.6.rst
+++ b/Doc/whatsnew/2.6.rst
@@ -2465,7 +2465,7 @@ changes, or look through the Subversion logs for all the details.
(All changes contributed by Lars Gustäbel).
* An optional ``timeout`` parameter was added to the
- :class:`telnetlib.Telnet` class constructor, specifying a timeout
+ :class:`!telnetlib.Telnet` class constructor, specifying a timeout
measured in seconds. (Added by Facundo Batista.)
* The :class:`tempfile.NamedTemporaryFile` class usually deletes
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 7a479c6e56a9..1a4a9936aca6 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -1731,7 +1731,7 @@ Modules
slated for removal in Python 3.13:
+---------------------+---------------------+---------------------+---------------------+---------------------+
- | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`telnetlib` |
+ | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`!telnetlib` |
+---------------------+---------------------+---------------------+---------------------+---------------------+
| :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` |
+---------------------+---------------------+---------------------+---------------------+---------------------+
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 4ff90664bb79..5e07a4caeb9e 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -819,7 +819,7 @@ Modules (see :pep:`594`):
* :mod:`sndhdr`
* :mod:`spwd`
* :mod:`sunau`
-* :mod:`telnetlib`
+* :mod:`!telnetlib`
* :mod:`uu`
* :mod:`xdrlib`
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index af331c46f1c0..8256f429183a 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -102,6 +102,10 @@ Deprecated
Removed
=======
+* :pep:`594`: Remove the :mod:`!telnetlib` module, deprecated in Python 3.11:
+ use the projects `telnetlib3 <https://pypi.org/project/telnetlib3/>`_ or
+ `Exscript <https://pypi.org/project/Exscript/>`_ instead.
+ (Contributed by Victor Stinner in :gh:`104773`.)
Porting to Python 3.13
diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
index 3a681754e25d..1cd33dfb6042 100644
--- a/Doc/whatsnew/3.6.rst
+++ b/Doc/whatsnew/3.6.rst
@@ -1520,7 +1520,7 @@ rather than the version that is being emulated for the process
telnetlib
---------
-:class:`~telnetlib.Telnet` is now a context manager (contributed by
+:class:`!telnetlib.Telnet` is now a context manager (contributed by
Stéphane Wirtel in :issue:`25485`).
diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py
deleted file mode 100644
index 62d636129853..000000000000
--- a/Lib/telnetlib.py
+++ /dev/null
@@ -1,679 +0,0 @@
-r"""TELNET client class.
-
-Based on RFC 854: TELNET Protocol Specification, by J. Postel and
-J. Reynolds
-
-Example:
-
->>> from telnetlib import Telnet
->>> tn = Telnet('www.python.org', 79) # connect to finger port
->>> tn.write(b'guido\r\n')
->>> print(tn.read_all())
-Login Name TTY Idle When Where
-guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston..
-
->>>
-
-Note that read_all() won't read until eof -- it just reads some data
--- but it guarantees to read at least one byte unless EOF is hit.
-
-It is possible to pass a Telnet object to a selector in order to wait until
-more data is available. Note that in this case, read_eager() may return b''
-even if there was data on the socket, because the protocol negotiation may have
-eaten the data. This is why EOFError is needed in some cases to distinguish
-between "no data" and "connection closed" (since the socket also appears ready
-for reading when it is closed).
-
-To do:
-- option negotiation
-- timeout should be intrinsic to the connection object instead of an
- option on one of the read calls only
-
-"""
-
-
-# Imported modules
-import sys
-import socket
-import selectors
-from time import monotonic as _time
-import warnings
-
-warnings._deprecated(__name__, remove=(3, 13))
-
-__all__ = ["Telnet"]
-
-# Tunable parameters
-DEBUGLEVEL = 0
-
-# Telnet protocol defaults
-TELNET_PORT = 23
-
-# Telnet protocol characters (don't change)
-IAC = bytes([255]) # "Interpret As Command"
-DONT = bytes([254])
-DO = bytes([253])
-WONT = bytes([252])
-WILL = bytes([251])
-theNULL = bytes([0])
-
-SE = bytes([240]) # Subnegotiation End
-NOP = bytes([241]) # No Operation
-DM = bytes([242]) # Data Mark
-BRK = bytes([243]) # Break
-IP = bytes([244]) # Interrupt process
-AO = bytes([245]) # Abort output
-AYT = bytes([246]) # Are You There
-EC = bytes([247]) # Erase Character
-EL = bytes([248]) # Erase Line
-GA = bytes([249]) # Go Ahead
-SB = bytes([250]) # Subnegotiation Begin
-
-
-# Telnet protocol options code (don't change)
-# These ones all come from arpa/telnet.h
-BINARY = bytes([0]) # 8-bit data path
-ECHO = bytes([1]) # echo
-RCP = bytes([2]) # prepare to reconnect
-SGA = bytes([3]) # suppress go ahead
-NAMS = bytes([4]) # approximate message size
-STATUS = bytes([5]) # give status
-TM = bytes([6]) # timing mark
-RCTE = bytes([7]) # remote controlled transmission and echo
-NAOL = bytes([8]) # negotiate about output line width
-NAOP = bytes([9]) # negotiate about output page size
-NAOCRD = bytes([10]) # negotiate about CR disposition
-NAOHTS = bytes([11]) # negotiate about horizontal tabstops
-NAOHTD = bytes([12]) # negotiate about horizontal tab disposition
-NAOFFD = bytes([13]) # negotiate about formfeed disposition
-NAOVTS = bytes([14]) # negotiate about vertical tab stops
-NAOVTD = bytes([15]) # negotiate about vertical tab disposition
-NAOLFD = bytes([16]) # negotiate about output LF disposition
-XASCII = bytes([17]) # extended ascii character set
-LOGOUT = bytes([18]) # force logout
-BM = bytes([19]) # byte macro
-DET = bytes([20]) # data entry terminal
-SUPDUP = bytes([21]) # supdup protocol
-SUPDUPOUTPUT = bytes([22]) # supdup output
-SNDLOC = bytes([23]) # send location
-TTYPE = bytes([24]) # terminal type
-EOR = bytes([25]) # end or record
-TUID = bytes([26]) # TACACS user identification
-OUTMRK = bytes([27]) # output marking
-TTYLOC = bytes([28]) # terminal location number
-VT3270REGIME = bytes([29]) # 3270 regime
-X3PAD = bytes([30]) # X.3 PAD
-NAWS = bytes([31]) # window size
-TSPEED = bytes([32]) # terminal speed
-LFLOW = bytes([33]) # remote flow control
-LINEMODE = bytes([34]) # Linemode option
-XDISPLOC = bytes([35]) # X Display Location
-OLD_ENVIRON = bytes([36]) # Old - Environment variables
-AUTHENTICATION = bytes([37]) # Authenticate
-ENCRYPT = bytes([38]) # Encryption option
-NEW_ENVIRON = bytes([39]) # New - Environment variables
-# the following ones come from
-# http://www.iana.org/assignments/telnet-options
-# Unfortunately, that document does not assign identifiers
-# to all of them, so we are making them up
-TN3270E = bytes([40]) # TN3270E
-XAUTH = bytes([41]) # XAUTH
-CHARSET = bytes([42]) # CHARSET
-RSP = bytes([43]) # Telnet Remote Serial Port
-COM_PORT_OPTION = bytes([44]) # Com Port Control Option
-SUPPRESS_LOCAL_ECHO = bytes([45]) # Telnet Suppress Local Echo
-TLS = bytes([46]) # Telnet Start TLS
-KERMIT = bytes([47]) # KERMIT
-SEND_URL = bytes([48]) # SEND-URL
-FORWARD_X = bytes([49]) # FORWARD_X
-PRAGMA_LOGON = bytes([138]) # TELOPT PRAGMA LOGON
-SSPI_LOGON = bytes([139]) # TELOPT SSPI LOGON
-PRAGMA_HEARTBEAT = bytes([140]) # TELOPT PRAGMA HEARTBEAT
-EXOPL = bytes([255]) # Extended-Options-List
-NOOPT = bytes([0])
-
-
-# poll/select have the advantage of not requiring any extra file descriptor,
-# contrarily to epoll/kqueue (also, they require a single syscall).
-if hasattr(selectors, 'PollSelector'):
- _TelnetSelector = selectors.PollSelector
-else:
- _TelnetSelector = selectors.SelectSelector
-
-
-class Telnet:
-
- """Telnet interface class.
-
- An instance of this class represents a connection to a telnet
- server. The instance is initially not connected; the open()
- method must be used to establish a connection. Alternatively, the
- host name and optional port number can be passed to the
- constructor, too.
-
- Don't try to reopen an already connected instance.
-
- This class has many read_*() methods. Note that some of them
- raise EOFError when the end of the connection is read, because
- they can return an empty string for other reasons. See the
- individual doc strings.
-
- read_until(expected, [timeout])
- Read until the expected string has been seen, or a timeout is
- hit (default is no timeout); may block.
-
- read_all()
- Read all data until EOF; may block.
-
- read_some()
- Read at least one byte or EOF; may block.
-
- read_very_eager()
- Read all data available already queued or on the socket,
- without blocking.
-
- read_eager()
- Read either data already queued or some data available on the
- socket, without blocking.
-
- read_lazy()
- Read all data in the raw queue (processing it first), without
- doing any socket I/O.
-
- read_very_lazy()
- Reads all data in the cooked queue, without doing any socket
- I/O.
-
- read_sb_data()
- Reads available data between SB ... SE sequence. Don't block.
-
- set_option_negotiation_callback(callback)
- Each time a telnet option is read on the input flow, this callback
- (if set) is called with the following parameters :
- callback(telnet socket, command, option)
- option will be chr(0) when there is no option.
- No other action is done afterwards by telnetlib.
-
- """
-
- def __init__(self, host=None, port=0,
- timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
- """Constructor.
-
- When called without arguments, create an unconnected instance.
- With a hostname argument, it connects the instance; port number
- and timeout are optional.
- """
- self.debuglevel = DEBUGLEVEL
- self.host = host
- self.port = port
- self.timeout = timeout
- self.sock = None
- self.rawq = b''
- self.irawq = 0
- self.cookedq = b''
- self.eof = 0
- self.iacseq = b'' # Buffer for IAC sequence.
- self.sb = 0 # flag for SB and SE sequence.
- self.sbdataq = b''
- self.option_callback = None
- if host is not None:
- self.open(host, port, timeout)
-
- def open(self, host, port=0, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
- """Connect to a host.
-
- The optional second argument is the port number, which
- defaults to the standard telnet port (23).
-
- Don't try to reopen an already connected instance.
- """
- self.eof = 0
- if not port:
- port = TELNET_PORT
- self.host = host
- self.port = port
- self.timeout = timeout
- sys.audit("telnetlib.Telnet.open", self, host, port)
- self.sock = socket.create_connection((host, port), timeout)
-
- def __del__(self):
- """Destructor -- close the connection."""
- self.close()
-
- def msg(self, msg, *args):
- """Print a debug message, when the debug level is > 0.
-
- If extra arguments are present, they are substituted in the
- message using the standard string formatting operator.
-
- """
- if self.debuglevel > 0:
- print('Telnet(%s,%s):' % (self.host, self.port), end=' ')
- if args:
- print(msg % args)
- else:
- print(msg)
-
- def set_debuglevel(self, debuglevel):
- """Set the debug level.
-
- The higher it is, the more debug output you get (on sys.stdout).
-
- """
- self.debuglevel = debuglevel
-
- def close(self):
- """Close the connection."""
- sock = self.sock
- self.sock = None
- self.eof = True
- self.iacseq = b''
- self.sb = 0
- if sock:
- sock.close()
-
- def get_socket(self):
- """Return the socket object used internally."""
- return self.sock
-
- def fileno(self):
- """Return the fileno() of the socket object used internally."""
- return self.sock.fileno()
-
- def write(self, buffer):
- """Write a string to the socket, doubling any IAC characters.
-
- Can block if the connection is blocked. May raise
- OSError if the connection is closed.
-
- """
- if IAC in buffer:
- buffer = buffer.replace(IAC, IAC+IAC)
- sys.audit("telnetlib.Telnet.write", self, buffer)
- self.msg("send %r", buffer)
- self.sock.sendall(buffer)
-
- def read_until(self, match, timeout=None):
- """Read until a given string is encountered or until timeout.
-
- When no match is found, return whatever is available instead,
- possibly the empty string. Raise EOFError if the connection
- is closed and no cooked data is available.
-
- """
- n = len(match)
- self.process_rawq()
- i = self.cookedq.find(match)
- if i >= 0:
- i = i+n
- buf = self.cookedq[:i]
- self.cookedq = self.cookedq[i:]
- return buf
- if timeout is not None:
- deadline = _time() + timeout
- with _TelnetSelector() as selector:
- selector.register(self, selectors.EVENT_READ)
- while not self.eof:
- if selector.select(timeout):
- i = max(0, len(self.cookedq)-n)
- self.fill_rawq()
- self.process_rawq()
- i = self.cookedq.find(match, i)
- if i >= 0:
- i = i+n
- buf = self.cookedq[:i]
- self.cookedq = self.cookedq[i:]
- return buf
- if timeout is not None:
- timeout = deadline - _time()
- if timeout < 0:
- break
- return self.read_very_lazy()
-
- def read_all(self):
- """Read all data until EOF; block until connection closed."""
- self.process_rawq()
- while not self.eof:
- self.fill_rawq()
- self.process_rawq()
- buf = self.cookedq
- self.cookedq = b''
- return buf
-
- def read_some(self):
- """Read at least one byte of cooked data unless EOF is hit.
-
- Return b'' if EOF is hit. Block if no data is immediately
- available.
-
- """
- self.process_rawq()
- while not self.cookedq and not self.eof:
- self.fill_rawq()
- self.process_rawq()
- buf = self.cookedq
- self.cookedq = b''
- return buf
-
- def read_very_eager(self):
- """Read everything that's possible without blocking in I/O (eager).
-
- Raise EOFError if connection closed and no cooked data
- available. Return b'' if no cooked data available otherwise.
- Don't block unless in the midst of an IAC sequence.
-
- """
- self.process_rawq()
- while not self.eof and self.sock_avail():
- self.fill_rawq()
- self.process_rawq()
- return self.read_very_lazy()
-
- def read_eager(self):
- """Read readily available data.
-
- Raise EOFError if connection closed and no cooked data
- available. Return b'' if no cooked data available otherwise.
- Don't block unless in the midst of an IAC sequence.
-
- """
- self.process_rawq()
- while not self.cookedq and not self.eof and self.sock_avail():
- self.fill_rawq()
- self.process_rawq()
- return self.read_very_lazy()
-
- def read_lazy(self):
- """Process and return data that's already in the queues (lazy).
-
- Raise EOFError if connection closed and no data available.
- Return b'' if no cooked data available otherwise. Don't block
- unless in the midst of an IAC sequence.
-
- """
- self.process_rawq()
- return self.read_very_lazy()
-
- def read_very_lazy(self):
- """Return any data available in the cooked queue (very lazy).
-
- Raise EOFError if connection closed and no data available.
- Return b'' if no cooked data available otherwise. Don't block.
-
- """
- buf = self.cookedq
- self.cookedq = b''
- if not buf and self.eof and not self.rawq:
- raise EOFError('telnet connection closed')
- return buf
-
- def read_sb_data(self):
- """Return any data available in the SB ... SE queue.
-
- Return b'' if no SB ... SE available. Should only be called
- after seeing a SB or SE command. When a new SB command is
- found, old unread SB data will be discarded. Don't block.
-
- """
- buf = self.sbdataq
- self.sbdataq = b''
- return buf
-
- def set_option_negotiation_callback(self, callback):
- """Provide a callback function called after each receipt of a telnet option."""
- self.option_callback = callback
-
- def process_rawq(self):
- """Transfer from raw queue to cooked queue.
-
- Set self.eof when connection is closed. Don't block unless in
- the midst of an IAC sequence.
-
- """
- buf = [b'', b'']
- try:
- while self.rawq:
- c = self.rawq_getchar()
- if not self.iacseq:
- if c == theNULL:
- continue
- if c == b"\021":
- continue
- if c != IAC:
- buf[self.sb] = buf[self.sb] + c
- continue
- else:
- self.iacseq += c
- elif len(self.iacseq) == 1:
- # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]'
- if c in (DO, DONT, WILL, WONT):
- self.iacseq += c
- continue
-
- self.iacseq = b''
- if c == IAC:
- buf[self.sb] = buf[self.sb] + c
- else:
- if c == SB: # SB ... SE start.
- self.sb = 1
- self.sbdataq = b''
- elif c == SE:
- self.sb = 0
- self.sbdataq = self.sbdataq + buf[1]
- buf[1] = b''
- if self.option_callback:
- # Callback is supposed to look into
- # the sbdataq
- self.option_callback(self.sock, c, NOOPT)
- else:
- # We can't offer automatic processing of
- # suboptions. Alas, we should not get any
- # unless we did a WILL/DO before.
- self.msg('IAC %d not recognized' % ord(c))
- elif len(self.iacseq) == 2:
- cmd = self.iacseq[1:2]
- self.iacseq = b''
- opt = c
- if cmd in (DO, DONT):
- self.msg('IAC %s %d',
- cmd == DO and 'DO' or 'DONT', ord(opt))
- if self.option_callback:
- self.option_callback(self.sock, cmd, opt)
- else:
- self.sock.sendall(IAC + WONT + opt)
- elif cmd in (WILL, WONT):
- self.msg('IAC %s %d',
- cmd == WILL and 'WILL' or 'WONT', ord(opt))
- if self.option_callback:
- self.option_callback(self.sock, cmd, opt)
- else:
- self.sock.sendall(IAC + DONT + opt)
- except EOFError: # raised by self.rawq_getchar()
- self.iacseq = b'' # Reset on EOF
- self.sb = 0
- self.cookedq = self.cookedq + buf[0]
- self.sbdataq = self.sbdataq + buf[1]
-
- def rawq_getchar(self):
- """Get next char from raw queue.
-
- Block if no data is immediately available. Raise EOFError
- when connection is closed.
-
- """
- if not self.rawq:
- self.fill_rawq()
- if self.eof:
- raise EOFError
- c = self.rawq[self.irawq:self.irawq+1]
- self.irawq = self.irawq + 1
- if self.irawq >= len(self.rawq):
- self.rawq = b''
- self.irawq = 0
- return c
-
- def fill_rawq(self):
- """Fill raw queue from exactly one recv() system call.
-
- Block if no data is immediately available. Set self.eof when
- connection is closed.
-
- """
- if self.irawq >= len(self.rawq):
- self.rawq = b''
- self.irawq = 0
- # The buffer size should be fairly small so as to avoid quadratic
- # behavior in process_rawq() above
- buf = self.sock.recv(50)
- self.msg("recv %r", buf)
- self.eof = (not buf)
- self.rawq = self.rawq + buf
-
- def sock_avail(self):
- """Test whether data is available on the socket."""
- with _TelnetSelector() as selector:
- selector.register(self, selectors.EVENT_READ)
- return bool(selector.select(0))
-
- def interact(self):
- """Interaction function, emulates a very dumb telnet client."""
- if sys.platform == "win32":
- self.mt_interact()
- return
- with _TelnetSelector() as selector:
- selector.register(self, selectors.EVENT_READ)
- selector.register(sys.stdin, selectors.EVENT_READ)
-
- while True:
- for key, events in selector.select():
- if key.fileobj is self:
- try:
- text = self.read_eager()
- except EOFError:
- print('*** Connection closed by remote host ***')
- return
- if text:
- sys.stdout.write(text.decode('ascii'))
- sys.stdout.flush()
- elif key.fileobj is sys.stdin:
- line = sys.stdin.readline().encode('ascii')
- if not line:
- return
- self.write(line)
-
- def mt_interact(self):
- """Multithreaded version of interact()."""
- import _thread
- _thread.start_new_thread(self.listener, ())
- while 1:
- line = sys.stdin.readline()
- if not line:
- break
- self.write(line.encode('ascii'))
-
- def listener(self):
- """Helper for mt_interact() -- this executes in the other thread."""
- while 1:
- try:
- data = self.read_eager()
- except EOFError:
- print('*** Connection closed by remote host ***')
- return
- if data:
- sys.stdout.write(data.decode('ascii'))
- else:
- sys.stdout.flush()
-
- def expect(self, list, timeout=None):
- """Read until one from a list of a regular expressions matches.
-
- The first argument is a list of regular expressions, either
- compiled (re.Pattern instances) or uncompiled (strings).
- The optional second argument is a timeout, in seconds; default
- is no timeout.
-
- Return a tuple of three items: the index in the list of the
- first regular expression that matches; the re.Match object
- returned; and the text read up till and including the match.
-
- If EOF is read and no text was read, raise EOFError.
- Otherwise, when nothing matches, return (-1, None, text) where
- text is the text received so far (may be the empty string if a
- timeout happened).
-
- If a regular expression ends with a greedy match (e.g. '.*')
- or if more than one expression can match the same input, the
- results are undeterministic, and may depend on the I/O timing.
-
- """
- re = None
- list = list[:]
- indices = range(len(list))
- for i in indices:
- if not hasattr(list[i], "search"):
- if not re: import re
- list[i] = re.compile(list[i])
- if timeout is not None:
- deadline = _time() + timeout
- with _TelnetSelector() as selector:
- selector.register(self, selectors.EVENT_READ)
- while not self.eof:
- self.process_rawq()
- for i in indices:
- m = list[i].search(self.cookedq)
- if m:
- e = m.end()
- text = self.cookedq[:e]
- self.cookedq = self.cookedq[e:]
- return (i, m, text)
- if timeout is not None:
- ready = selector.select(timeout)
- timeout = deadline - _time()
- if not ready:
- if timeout < 0:
- break
- else:
- continue
- self.fill_rawq()
- text = self.read_very_lazy()
- if not text and self.eof:
- raise EOFError
- return (-1, None, text)
-
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- self.close()
-
-
-def test():
- """Test program for telnetlib.
-
- Usage: python telnetlib.py [-d] ... [host [port]]
-
- Default host is localhost; default port is 23.
-
- """
- debuglevel = 0
- while sys.argv[1:] and sys.argv[1] == '-d':
- debuglevel = debuglevel+1
- del sys.argv[1]
- host = 'localhost'
- if sys.argv[1:]:
- host = sys.argv[1]
- port = 0
- if sys.argv[2:]:
- portstr = sys.argv[2]
- try:
- port = int(portstr)
- except ValueError:
- port = socket.getservbyname(portstr, 'tcp')
- with Telnet() as tn:
- tn.set_debuglevel(debuglevel)
- tn.open(host, port, timeout=0.5)
- tn.interact()
-
-if __name__ == '__main__':
- test()
diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py
deleted file mode 100644
index a9cade2ee466..000000000000
--- a/Lib/test/test_telnetlib.py
+++ /dev/null
@@ -1,405 +0,0 @@
-import socket
-import selectors
-import threading
-import contextlib
-
-from test import support
-from test.support import socket_helper, warnings_helper
-import unittest
-
-support.requires_working_socket(module=True)
-
-telnetlib = warnings_helper.import_deprecated('telnetlib')
-
-HOST = socket_helper.HOST
-
-def server(evt, serv):
- serv.listen()
- evt.set()
- try:
- conn, addr = serv.accept()
- conn.close()
- except TimeoutError:
- pass
- finally:
- serv.close()
-
-class GeneralTests(unittest.TestCase):
-
- def setUp(self):
- self.evt = threading.Event()
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.settimeout(60) # Safety net. Look issue 11812
- self.port = socket_helper.bind_port(self.sock)
- self.thread = threading.Thread(target=server, args=(self.evt,self.sock))
- self.thread.daemon = True
- self.thread.start()
- self.evt.wait()
-
- def tearDown(self):
- self.thread.join()
- del self.thread # Clear out any dangling Thread objects.
-
- def testBasic(self):
- # connects
- telnet = telnetlib.Telnet(HOST, self.port)
- telnet.sock.close()
-
- def testContextManager(self):
- with telnetlib.Telnet(HOST, self.port) as tn:
- self.assertIsNotNone(tn.get_socket())
- self.assertIsNone(tn.get_socket())
-
- def testTimeoutDefault(self):
- self.assertTrue(socket.getdefaulttimeout() is None)
- socket.setdefaulttimeout(30)
- try:
- telnet = telnetlib.Telnet(HOST, self.port)
- finally:
- socket.setdefaulttimeout(None)
- self.assertEqual(telnet.sock.gettimeout(), 30)
- telnet.sock.close()
-
- def testTimeoutNone(self):
- # None, having other default
- self.assertTrue(socket.getdefaulttimeout() is None)
- socket.setdefaulttimeout(30)
- try:
- telnet = telnetlib.Telnet(HOST, self.port, timeout=None)
- finally:
- socket.setdefaulttimeout(None)
- self.assertTrue(telnet.sock.gettimeout() is None)
- telnet.sock.close()
-
- def testTimeoutValue(self):
- telnet = telnetlib.Telnet(HOST, self.port, timeout=30)
- self.assertEqual(telnet.sock.gettimeout(), 30)
- telnet.sock.close()
-
- def testTimeoutOpen(self):
- telnet = telnetlib.Telnet()
- telnet.open(HOST, self.port, timeout=30)
- self.assertEqual(telnet.sock.gettimeout(), 30)
- telnet.sock.close()
-
- def testGetters(self):
- # Test telnet getter methods
- telnet = telnetlib.Telnet(HOST, self.port, timeout=30)
- t_sock = telnet.sock
- self.assertEqual(telnet.get_socket(), t_sock)
- self.assertEqual(telnet.fileno(), t_sock.fileno())
- telnet.sock.close()
-
-class SocketStub(object):
- ''' a socket proxy that re-defines sendall() '''
- def __init__(self, reads=()):
- self.reads = list(reads) # Intentionally make a copy.
- self.writes = []
- self.block = False
- def sendall(self, data):
- self.writes.append(data)
- def recv(self, size):
- out = b''
- while self.reads and len(out) < size:
- out += self.reads.pop(0)
- if len(out) > size:
- self.reads.insert(0, out[size:])
- out = out[:size]
- return out
-
-class TelnetAlike(telnetlib.Telnet):
- def fileno(self):
- raise NotImplementedError()
- def close(self): pass
- def sock_avail(self):
- return (not self.sock.block)
- def msg(self, msg, *args):
- with support.captured_stdout() as out:
- telnetlib.Telnet.msg(self, msg, *args)
- self._messages += out.getvalue()
- return
-
-class MockSelector(selectors.BaseSelector):
-
- def __init__(self):
- self.keys = {}
-
- @property
- def resolution(self):
- return 1e-3
-
- def register(self, fileobj, events, data=None):
- key = selectors.SelectorKey(fileobj, 0, events, data)
- self.keys[fileobj] = key
- return key
-
- def unregister(self, fileobj):
- return self.keys.pop(fileobj)
-
- def select(self, timeout=None):
- block = False
- for fileobj in self.keys:
- if isinstance(fileobj, TelnetAlike):
- block = fileobj.sock.block
- break
- if block:
- return []
- else:
- return [(key, key.events) for key in self.keys.values()]
-
- def get_map(self):
- return self.keys
-
-
- at contextlib.contextmanager
-def test_socket(reads):
- def new_conn(*ignored):
- return SocketStub(reads)
- try:
- old_conn = socket.create_connection
- socket.create_connection = new_conn
- yield None
- finally:
- socket.create_connection = old_conn
- return
-
-def test_telnet(reads=(), cls=TelnetAlike):
- ''' return a telnetlib.Telnet object that uses a SocketStub with
- reads queued up to be read '''
- for x in reads:
- assert type(x) is bytes, x
- with test_socket(reads):
- telnet = cls('dummy', 0)
- telnet._messages = '' # debuglevel output
- return telnet
-
-class ExpectAndReadTestCase(unittest.TestCase):
- def setUp(self):
- self.old_selector = telnetlib._TelnetSelector
- telnetlib._TelnetSelector = MockSelector
- def tearDown(self):
- telnetlib._TelnetSelector = self.old_selector
-
-class ReadTests(ExpectAndReadTestCase):
- def test_read_until(self):
- """
- read_until(expected, timeout=None)
- test the blocking version of read_util
- """
- want = [b'xxxmatchyyy']
- telnet = test_telnet(want)
- data = telnet.read_until(b'match')
- self.assertEqual(data, b'xxxmatch', msg=(telnet.cookedq, telnet.rawq, telnet.sock.reads))
-
- reads = [b'x' * 50, b'match', b'y' * 50]
- expect = b''.join(reads[:-1])
- telnet = test_telnet(reads)
- data = telnet.read_until(b'match')
- self.assertEqual(data, expect)
-
-
- def test_read_all(self):
- """
- read_all()
- Read all data until EOF; may block.
- """
- reads = [b'x' * 500, b'y' * 500, b'z' * 500]
- expect = b''.join(reads)
- telnet = test_telnet(reads)
- data = telnet.read_all()
- self.assertEqual(data, expect)
- return
-
- def test_read_some(self):
- """
- read_some()
- Read at least one byte or EOF; may block.
- """
- # test 'at least one byte'
- telnet = test_telnet([b'x' * 500])
- data = telnet.read_some()
- self.assertTrue(len(data) >= 1)
- # test EOF
- telnet = test_telnet()
- data = telnet.read_some()
- self.assertEqual(b'', data)
-
- def _read_eager(self, func_name):
- """
- read_*_eager()
- Read all data available already queued or on the socket,
- without blocking.
- """
- want = b'x' * 100
- telnet = test_telnet([want])
- func = getattr(telnet, func_name)
- telnet.sock.block = True
- self.assertEqual(b'', func())
- telnet.sock.block = False
- data = b''
- while True:
- try:
- data += func()
- except EOFError:
- break
- self.assertEqual(data, want)
-
- def test_read_eager(self):
- # read_eager and read_very_eager make the same guarantees
- # (they behave differently but we only test the guarantees)
- self._read_eager('read_eager')
- self._read_eager('read_very_eager')
- # NB -- we need to test the IAC block which is mentioned in the
- # docstring but not in the module docs
-
- def read_very_lazy(self):
- want = b'x' * 100
- telnet = test_telnet([want])
- self.assertEqual(b'', telnet.read_very_lazy())
- while telnet.sock.reads:
- telnet.fill_rawq()
- data = telnet.read_very_lazy()
- self.assertEqual(want, data)
- self.assertRaises(EOFError, telnet.read_very_lazy)
-
- def test_read_lazy(self):
- want = b'x' * 100
- telnet = test_telnet([want])
- self.assertEqual(b'', telnet.read_lazy())
- data = b''
- while True:
- try:
- read_data = telnet.read_lazy()
- data += read_data
- if not read_data:
- telnet.fill_rawq()
- except EOFError:
- break
- self.assertTrue(want.startswith(data))
- self.assertEqual(data, want)
-
-class nego_collector(object):
- def __init__(self, sb_getter=None):
- self.seen = b''
- self.sb_getter = sb_getter
- self.sb_seen = b''
-
- def do_nego(self, sock, cmd, opt):
- self.seen += cmd + opt
- if cmd == tl.SE and self.sb_getter:
- sb_data = self.sb_getter()
- self.sb_seen += sb_data
-
-tl = telnetlib
-
-class WriteTests(unittest.TestCase):
- '''The only thing that write does is replace each tl.IAC for
- tl.IAC+tl.IAC'''
-
- def test_write(self):
- data_sample = [b'data sample without IAC',
- b'data sample with' + tl.IAC + b' one IAC',
- b'a few' + tl.IAC + tl.IAC + b' iacs' + tl.IAC,
- tl.IAC,
- b'']
- for data in data_sample:
- telnet = test_telnet()
- telnet.write(data)
- written = b''.join(telnet.sock.writes)
- self.assertEqual(data.replace(tl.IAC,tl.IAC+tl.IAC), written)
-
-class OptionTests(unittest.TestCase):
- # RFC 854 commands
- cmds = [tl.AO, tl.AYT, tl.BRK, tl.EC, tl.EL, tl.GA, tl.IP, tl.NOP]
-
- def _test_command(self, data):
- """ helper for testing IAC + cmd """
- telnet = test_telnet(data)
- data_len = len(b''.join(data))
- nego = nego_collector()
- telnet.set_option_negotiation_callback(nego.do_nego)
- txt = telnet.read_all()
- cmd = nego.seen
- self.assertTrue(len(cmd) > 0) # we expect at least one command
- self.assertIn(cmd[:1], self.cmds)
- self.assertEqual(cmd[1:2], tl.NOOPT)
- self.assertEqual(data_len, len(txt + cmd))
- nego.sb_getter = None # break the nego => telnet cycle
-
- def test_IAC_commands(self):
- for cmd in self.cmds:
- self._test_command([tl.IAC, cmd])
- self._test_command([b'x' * 100, tl.IAC, cmd, b'y'*100])
- self._test_command([b'x' * 10, tl.IAC, cmd, b'y'*10])
- # all at once
- self._test_command([tl.IAC + cmd for (cmd) in self.cmds])
-
- def test_SB_commands(self):
- # RFC 855, subnegotiations portion
- send = [tl.IAC + tl.SB + tl.IAC + tl.SE,
- tl.IAC + tl.SB + tl.IAC + tl.IAC + tl.IAC + tl.SE,
- tl.IAC + tl.SB + tl.IAC + tl.IAC + b'aa' + tl.IAC + tl.SE,
- tl.IAC + tl.SB + b'bb' + tl.IAC + tl.IAC + tl.IAC + tl.SE,
- tl.IAC + tl.SB + b'cc' + tl.IAC + tl.IAC + b'dd' + tl.IAC + tl.SE,
- ]
- telnet = test_telnet(send)
- nego = nego_collector(telnet.read_sb_data)
- telnet.set_option_negotiation_callback(nego.do_nego)
- txt = telnet.read_all()
- self.assertEqual(txt, b'')
- want_sb_data = tl.IAC + tl.IAC + b'aabb' + tl.IAC + b'cc' + tl.IAC + b'dd'
- self.assertEqual(nego.sb_seen, want_sb_data)
- self.assertEqual(b'', telnet.read_sb_data())
- nego.sb_getter = None # break the nego => telnet cycle
-
- def test_debuglevel_reads(self):
- # test all the various places that self.msg(...) is called
- given_a_expect_b = [
- # Telnet.fill_rawq
- (b'a', ": recv b''\n"),
- # Telnet.process_rawq
- (tl.IAC + bytes([88]), ": IAC 88 not recognized\n"),
- (tl.IAC + tl.DO + bytes([1]), ": IAC DO 1\n"),
- (tl.IAC + tl.DONT + bytes([1]), ": IAC DONT 1\n"),
- (tl.IAC + tl.WILL + bytes([1]), ": IAC WILL 1\n"),
- (tl.IAC + tl.WONT + bytes([1]), ": IAC WONT 1\n"),
- ]
- for a, b in given_a_expect_b:
- telnet = test_telnet([a])
- telnet.set_debuglevel(1)
- txt = telnet.read_all()
- self.assertIn(b, telnet._messages)
- return
-
- def test_debuglevel_write(self):
- telnet = test_telnet()
- telnet.set_debuglevel(1)
- telnet.write(b'xxx')
- expected = "send b'xxx'\n"
- self.assertIn(expected, telnet._messages)
-
- def test_debug_accepts_str_port(self):
- # Issue 10695
- with test_socket([]):
- telnet = TelnetAlike('dummy', '0')
- telnet._messages = ''
- telnet.set_debuglevel(1)
- telnet.msg('test')
- self.assertRegex(telnet._messages, r'0.*test')
-
-
-class ExpectTests(ExpectAndReadTestCase):
- def test_expect(self):
- """
- expect(expected, [timeout])
- Read until the expected string has been seen, or a timeout is
- hit (default is no timeout); may block.
- """
- want = [b'x' * 10, b'match', b'y' * 10]
- telnet = test_telnet(want)
- (_,_,data) = telnet.expect([b'match'])
- self.assertEqual(data, b''.join(want[:-1]))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst
index 0888a5c43087..7da438597318 100644
--- a/Misc/NEWS.d/3.9.0a1.rst
+++ b/Misc/NEWS.d/3.9.0a1.rst
@@ -99,7 +99,7 @@ after whitespace, e.g. '127.0.0.1 whatever'.
Adds audit events for :mod:`ensurepip`, :mod:`ftplib`, :mod:`glob`,
:mod:`imaplib`, :mod:`nntplib`, :mod:`pdb`, :mod:`poplib`, :mod:`shutil`,
-:mod:`smtplib`, :mod:`sqlite3`, :mod:`subprocess`, :mod:`telnetlib`,
+:mod:`smtplib`, :mod:`sqlite3`, :mod:`subprocess`, :mod:`!telnetlib`,
:mod:`tempfile` and :mod:`webbrowser`, as well as :func:`os.listdir`,
:func:`os.scandir` and :func:`breakpoint`.
diff --git a/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst b/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst
new file mode 100644
index 000000000000..0f3162ef509a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst
@@ -0,0 +1,2 @@
+:pep:`594`: Remove the :mod:`!telnetlib` module, deprecated in Python 3.11.
+Patch by Victor Stinner.
diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h
index ed4a0ac2dd32..4b0580557fb7 100644
--- a/Python/stdlib_module_names.h
+++ b/Python/stdlib_module_names.h
@@ -261,7 +261,6 @@ static const char* _Py_stdlib_module_names[] = {
"syslog",
"tabnanny",
"tarfile",
-"telnetlib",
"tempfile",
"termios",
"textwrap",
diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py
index 1fc97fd5e70a..22bf9eabdcd6 100755
--- a/Tools/wasm/wasm_assets.py
+++ b/Tools/wasm/wasm_assets.py
@@ -78,7 +78,6 @@
"poplib.py",
"smtplib.py",
"socketserver.py",
- "telnetlib.py",
# keep urllib.parse for pydoc
"urllib/error.py",
"urllib/request.py",
More information about the Python-checkins
mailing list