From e5b96978d3b198824149cf0b384519e74a685eea Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 17 Nov 2019 17:41:07 +0900 Subject: [PATCH] bpo-38615: Add timeout parameter for IMAP4 and IMAP4_SSL constructor --- Doc/library/imaplib.rst | 19 ++++++++--- Doc/whatsnew/3.9.rst | 7 ++++ Lib/imaplib.py | 33 +++++++++++-------- .../2019-11-17-17-32-35.bpo-38615.OVyaNX.rst | 2 ++ 4 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-11-17-17-32-35.bpo-38615.OVyaNX.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index df63d820cfe043..d4dc1eac97b53c 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -30,12 +30,14 @@ Three classes are provided by the :mod:`imaplib` module, :class:`IMAP4` is the base class: -.. class:: IMAP4(host='', port=IMAP4_PORT) +.. class:: IMAP4(host='', port=IMAP4_PORT[, timeout]) This class implements the actual IMAP4 protocol. The connection is created and protocol version (IMAP4 or IMAP4rev1) is determined when the instance is initialized. If *host* is not specified, ``''`` (the local host) is used. If - *port* is omitted, the standard IMAP4 port (143) is used. + *port* is omitted, the standard IMAP4 port (143) is used. The optional *timeout* + parameter specifies a timeout in seconds for the connection attempt + (if not specified, the global default timeout setting will be used). The :class:`IMAP4` class supports the :keyword:`with` statement. When used like this, the IMAP4 ``LOGOUT`` command is issued automatically when the @@ -50,6 +52,9 @@ base class: .. versionchanged:: 3.5 Support for the :keyword:`with` statement was added. + .. versionchanged:: 3.9 + The optional *timeout* parameter was added. + Three exceptions are defined as attributes of the :class:`IMAP4` class: @@ -78,7 +83,7 @@ There's also a subclass for secure connections: .. class:: IMAP4_SSL(host='', port=IMAP4_SSL_PORT, keyfile=None, \ - certfile=None, ssl_context=None) + certfile=None, ssl_context=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT) This is a subclass derived from :class:`IMAP4` that connects over an SSL encrypted socket (to use this class you need a socket module that was compiled @@ -96,7 +101,7 @@ There's also a subclass for secure connections: if *keyfile*/*certfile* is provided along with *ssl_context*. .. versionchanged:: 3.3 - *ssl_context* parameter added. + *ssl_context* parameter was added. .. versionchanged:: 3.4 The class now supports hostname check with @@ -110,6 +115,8 @@ There's also a subclass for secure connections: :func:`ssl.create_default_context` select the system's trusted CA certificates for you. + .. versionchanged:: 3.9 + The optional *timeout* parameter was added. The second subclass allows for connections created by a child process: @@ -353,7 +360,7 @@ An :class:`IMAP4` instance has the following methods: Send ``NOOP`` to server. -.. method:: IMAP4.open(host, port) +.. method:: IMAP4.open(host, port, timeout) Opens socket to *port* at *host*. This method is implicitly called by the :class:`IMAP4` constructor. The connection objects established by this @@ -363,6 +370,8 @@ An :class:`IMAP4` instance has the following methods: .. audit-event:: imaplib.open self,host,port imaplib.IMAP4.open + .. versionchanged:: 3.9 + The *timeout* parameter was added. .. method:: IMAP4.partial(message_num, message_part, start, length) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index b1beb0be090cfa..e8844a9672de7b 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -147,6 +147,13 @@ Added constants :data:`~fcntl.F_OFD_GETLK`, :data:`~fcntl.F_OFD_SETLK` and :data:`~fcntl.F_OFD_SETLKW`. (Contributed by Dong-hee Na in :issue:`38602`.) +imaplib +------- + +The :class:`~imaplib.IMAP4` and :class:`~imaplib.IMAP4_SSL` now has +optional *timeout* parameter for constructor. +(Contributed by Dong-hee Na in :issue:`38615`.) + os -- diff --git a/Lib/imaplib.py b/Lib/imaplib.py index a4f499383efaeb..be0de08e72b4d5 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -135,10 +135,11 @@ class IMAP4: r"""IMAP4 client class. - Instantiate with: IMAP4([host[, port]]) + Instantiate with: IMAP4([host[, port[, timeout]]]) host - host's name (default: localhost); port - port number (default: standard IMAP4 port). + timeout - socket timeout (default: socket._GLOBAL_DEFAULT_TIMEOUT)) All IMAP4rev1 commands are supported by methods of the same name (in lower-case). @@ -181,7 +182,8 @@ class error(Exception): pass # Logical errors - debug required class abort(error): pass # Service errors - close and retry class readonly(abort): pass # Mailbox status changed to READ-ONLY - def __init__(self, host='', port=IMAP4_PORT): + def __init__(self, host='', port=IMAP4_PORT, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT): self.debug = Debug self.state = 'LOGOUT' self.literal = None # A literal argument to a command @@ -195,7 +197,7 @@ def __init__(self, host='', port=IMAP4_PORT): # Open socket to server. - self.open(host, port) + self.open(host, port, timeout) try: self._connect() @@ -284,15 +286,16 @@ def __exit__(self, *args): # Overridable methods - def _create_socket(self): + def _create_socket(self, timeout): # Default value of IMAP4.host is '', but socket.getaddrinfo() # (which is used by socket.create_connection()) expects None # as a default value for host. host = None if not self.host else self.host sys.audit("imaplib.open", self, self.host, self.port) - return socket.create_connection((host, self.port)) + return socket.create_connection((host, self.port), timeout) - def open(self, host = '', port = IMAP4_PORT): + def open(self, host = '', port = IMAP4_PORT, + timeout = socket._GLOBAL_DEFAULT_TIMEOUT): """Setup connection to remote server on "host:port" (default: localhost:standard IMAP4 port). This connection will be used by the routines: @@ -300,7 +303,7 @@ def open(self, host = '', port = IMAP4_PORT): """ self.host = host self.port = port - self.sock = self._create_socket() + self.sock = self._create_socket(timeout) self.file = self.sock.makefile('rb') @@ -1261,7 +1264,7 @@ class IMAP4_SSL(IMAP4): """IMAP4 client class over SSL connection - Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile[, ssl_context]]]]]) + Instantiate with: IMAP4_SSL([host[, port[, keyfile[, certfile[, ssl_context[, timeout]]]]]]) host - host's name (default: localhost); port - port number (default: standard IMAP4 SSL port); @@ -1271,13 +1274,14 @@ class IMAP4_SSL(IMAP4): and private key (default: None) Note: if ssl_context is provided, then parameters keyfile or certfile should not be set otherwise ValueError is raised. + timeout - socket timeout (default: socket._GLOBAL_DEFAULT_TIMEOUT) for more documentation see the docstring of the parent class IMAP4. """ def __init__(self, host='', port=IMAP4_SSL_PORT, keyfile=None, - certfile=None, ssl_context=None): + certfile=None, ssl_context=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): if ssl_context is not None and keyfile is not None: raise ValueError("ssl_context and keyfile arguments are mutually " "exclusive") @@ -1294,20 +1298,21 @@ def __init__(self, host='', port=IMAP4_SSL_PORT, keyfile=None, ssl_context = ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile) self.ssl_context = ssl_context - IMAP4.__init__(self, host, port) + IMAP4.__init__(self, host, port, timeout) - def _create_socket(self): - sock = IMAP4._create_socket(self) + def _create_socket(self, timeout): + sock = IMAP4._create_socket(self, timeout) return self.ssl_context.wrap_socket(sock, server_hostname=self.host) - def open(self, host='', port=IMAP4_SSL_PORT): + def open(self, host='', port=IMAP4_SSL_PORT, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT): """Setup connection to remote server on "host:port". (default: localhost:standard IMAP4 SSL port). This connection will be used by the routines: read, readline, send, shutdown. """ - IMAP4.open(self, host, port) + IMAP4.open(self, host, port, timeout) __all__.append("IMAP4_SSL") diff --git a/Misc/NEWS.d/next/Library/2019-11-17-17-32-35.bpo-38615.OVyaNX.rst b/Misc/NEWS.d/next/Library/2019-11-17-17-32-35.bpo-38615.OVyaNX.rst new file mode 100644 index 00000000000000..157943c26d6055 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-11-17-17-32-35.bpo-38615.OVyaNX.rst @@ -0,0 +1,2 @@ +The :class:`~imaplib.IMAP4` and :class:`~imaplib.IMAP4_SSL` now has optional +*timeout* parameter for constructor. Patch by Dong-hee Na.