From c5c42815ecb560bbf34db99b0e15fe9b604be889 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 27 Apr 2020 23:52:55 +0900 Subject: [PATCH] bpo-40375: Implement imaplib.IMAP4.unselect (GH-19712) --- Doc/library/imaplib.rst | 9 +++++++ Doc/whatsnew/3.9.rst | 7 ++++++ Lib/imaplib.py | 17 +++++++++++++ Lib/test/test_imaplib.py | 25 +++++++++++++++++++ .../2020-04-25-23-14-11.bpo-40375.5GuK2A.rst | 1 + 5 files changed, 59 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 5b8ca7ce68f..7c5b0750161 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -582,6 +582,15 @@ An :class:`IMAP4` instance has the following methods: Unsubscribe from old mailbox. +.. method:: IMAP4.unselect() + + :meth:`imaplib.IMAP4.unselect` frees server's resources associated with the + selected mailbox and returns the server to the authenticated + state. This command performs the same actions as :meth:`imaplib.IMAP4.close`, except + that no messages are permanently removed from the currently + selected mailbox. + + .. versionadded:: 3.9 .. method:: IMAP4.xatom(name[, ...]) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 728e6001daa..0b15ec73641 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -320,6 +320,13 @@ with this change. The overridden methods of :class:`~imaplib.IMAP4_SSL` and :class:`~imaplib.IMAP4_stream` were applied to this change. (Contributed by Dong-hee Na in :issue:`38615`.) +:meth:`imaplib.IMAP4.unselect` is added. +:meth:`imaplib.IMAP4.unselect` frees server's resources associated with the +selected mailbox and returns the server to the authenticated +state. This command performs the same actions as :meth:`imaplib.IMAP4.close`, except +that no messages are permanently removed from the currently +selected mailbox. (Contributed by Dong-hee Na in :issue:`40375`.) + importlib --------- diff --git a/Lib/imaplib.py b/Lib/imaplib.py index abfdd737779..d9720f20c39 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -98,6 +98,7 @@ Commands = { 'THREAD': ('SELECTED',), 'UID': ('SELECTED',), 'UNSUBSCRIBE': ('AUTH', 'SELECTED'), + 'UNSELECT': ('SELECTED',), } # Patterns to match server responses @@ -902,6 +903,22 @@ class IMAP4: return self._simple_command('UNSUBSCRIBE', mailbox) + def unselect(self): + """Free server's resources associated with the selected mailbox + and returns the server to the authenticated state. + This command performs the same actions as CLOSE, except + that no messages are permanently removed from the currently + selected mailbox. + + (typ, [data]) = .unselect() + """ + try: + typ, data = self._simple_command('UNSELECT') + finally: + self.state = 'AUTH' + return typ, data + + def xatom(self, name, *args): """Allow simple extension commands notified by server in CAPABILITY response. diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 76456669517..69ee63b18c3 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -116,6 +116,7 @@ class SimpleIMAPHandler(socketserver.StreamRequestHandler): def setup(self): super().setup() + self.server.is_selected = False self.server.logged = None def _send(self, message): @@ -190,6 +191,18 @@ class SimpleIMAPHandler(socketserver.StreamRequestHandler): self.server.logged = args[0] self._send_tagged(tag, 'OK', 'LOGIN completed') + def cmd_SELECT(self, tag, args): + self.server.is_selected = True + self._send_line(b'* 2 EXISTS') + self._send_tagged(tag, 'OK', '[READ-WRITE] SELECT completed.') + + def cmd_UNSELECT(self, tag, args): + if self.server.is_selected: + self.server.is_selected = False + self._send_tagged(tag, 'OK', 'Returned to authenticated state. (Success)') + else: + self._send_tagged(tag, 'BAD', 'No mailbox selected') + class NewIMAPTestsMixin(): client = None @@ -511,6 +524,18 @@ class NewIMAPTestsMixin(): self.assertEqual(typ, 'OK') self.assertEqual(data[0], b'() "." directoryA') + def test_unselect(self): + client, _ = self._setup(SimpleIMAPHandler) + client.login('user', 'pass') + typ, data = client.select() + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'2') + + typ, data = client.unselect() + self.assertEqual(typ, 'OK') + self.assertEqual(data[0], b'Returned to authenticated state. (Success)') + self.assertEqual(client.state, 'AUTH') + class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase): imap_class = imaplib.IMAP4 diff --git a/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst b/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst new file mode 100644 index 00000000000..eb58e00bcf7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-25-23-14-11.bpo-40375.5GuK2A.rst @@ -0,0 +1 @@ +:meth:`imaplib.IMAP4.unselect` is added. Patch by Dong-hee Na.