From 25d0036a57ee9823221a48e58367e92c4378caac Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Tue, 28 Jan 2020 11:02:48 +0100 Subject: [PATCH 1/5] Improve imaplib return types Mark CommandResults as obsolete. Also fix types of tagged_commands and untagged_responses. Based on a discussion in #3655. --- stdlib/2and3/imaplib.pyi | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/stdlib/2and3/imaplib.pyi b/stdlib/2and3/imaplib.pyi index 07f770dfb3ce..2d54d5cd3a6e 100644 --- a/stdlib/2and3/imaplib.pyi +++ b/stdlib/2and3/imaplib.pyi @@ -1,5 +1,3 @@ -# Stubs for imaplib (Python 2) - import imaplib import subprocess import sys @@ -8,8 +6,16 @@ from socket import socket as _socket from ssl import SSLSocket, SSLContext from typing import Any, Callable, Dict, IO, List, Optional, Pattern, Text, Tuple, Type, Union +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +# TODO: Commands should use their actual return types, not this type alias. +# E.g. Tuple[Literal["OK"], List[bytes]] CommandResults = Tuple[str, List[Any]] +_AnyResponseData = Union[List[None], List[Union[bytes, Tuple[bytes, bytes]]]] class IMAP4: error: Type[Exception] = ... @@ -19,8 +25,8 @@ class IMAP4: debug: int = ... state: str = ... literal: Optional[Text] = ... - tagged_commands: Dict[str, str] = ... - untagged_responses: Dict[str, str] = ... + tagged_commands: Dict[str, Optional[bytes]] + untagged_responses: Dict[str, List[Union[bytes, Tuple[bytes, bytes]]]] continuation_response: str = ... is_readonly: bool = ... tagnum: int = ... @@ -57,30 +63,30 @@ class IMAP4: def __enter__(self) -> IMAP4: ... def __exit__(self, *args) -> None: ... def expunge(self) -> CommandResults: ... - def fetch(self, message_set: str, message_parts: str) -> CommandResults: ... + def fetch(self, message_set: str, message_parts: str) -> Tuple[str, _AnyResponseData]: ... def getacl(self, mailbox: str) -> CommandResults: ... def getannotation(self, mailbox: str, entry: str, attribute: str) -> CommandResults: ... def getquota(self, root: str) -> CommandResults: ... def getquotaroot(self, mailbox: str) -> CommandResults: ... - def list(self, directory: str = ..., pattern: str = ...) -> CommandResults: ... - def login(self, user: str, password: str) -> CommandResults: ... + def list(self, directory: str = ..., pattern: str = ...) -> Tuple[str, _AnyResponseData]: ... + def login(self, user: str, password: str) -> Tuple[Literal["OK"], List[bytes]]: ... def login_cram_md5(self, user: str, password: str) -> CommandResults: ... - def logout(self) -> CommandResults: ... + def logout(self) -> Tuple[str, _AnyResponseData]: ... def lsub(self, directory: str = ..., pattern: str = ...) -> CommandResults: ... def myrights(self, mailbox: str) -> CommandResults: ... def namespace(self) -> CommandResults: ... - def noop(self) -> CommandResults: ... + def noop(self) -> Tuple[str, List[bytes]]: ... def partial(self, message_num: str, message_part: str, start: str, length: str) -> CommandResults: ... def proxyauth(self, user: str) -> CommandResults: ... def rename(self, oldmailbox: str, newmailbox: str) -> CommandResults: ... def search(self, charset: Optional[str], *criteria: str) -> CommandResults: ... - def select(self, mailbox: str = ..., readonly: bool = ...) -> CommandResults: ... + def select(self, mailbox: str = ..., readonly: bool = ...) -> Tuple[str, List[Optional[bytes]]]: ... def setacl(self, mailbox: str, who: str, what: str) -> CommandResults: ... def setannotation(self, *args: str) -> CommandResults: ... def setquota(self, root: str, limits: str) -> CommandResults: ... def sort(self, sort_criteria: str, charset: str, *search_criteria: str) -> CommandResults: ... if sys.version_info >= (3,): - def starttls(self, ssl_context: Optional[Any] = ...) -> CommandResults: ... + def starttls(self, ssl_context: Optional[Any] = ...) -> Tuple[Literal["OK"], List[None]]: ... def status(self, mailbox: str, names: str) -> CommandResults: ... def store(self, message_set: str, command: str, flags: str) -> CommandResults: ... def subscribe(self, mailbox: str) -> CommandResults: ... From 460e89f20bcb787d831307afcb8be8efcbefc307 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Fri, 31 Jan 2020 16:34:58 +0100 Subject: [PATCH 2/5] Fix type of tagged_commands --- stdlib/2and3/imaplib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/2and3/imaplib.pyi b/stdlib/2and3/imaplib.pyi index 2d54d5cd3a6e..d6409a85f8a8 100644 --- a/stdlib/2and3/imaplib.pyi +++ b/stdlib/2and3/imaplib.pyi @@ -25,7 +25,7 @@ class IMAP4: debug: int = ... state: str = ... literal: Optional[Text] = ... - tagged_commands: Dict[str, Optional[bytes]] + tagged_commands: Dict[bytes, Optional[bytes]] untagged_responses: Dict[str, List[Union[bytes, Tuple[bytes, bytes]]]] continuation_response: str = ... is_readonly: bool = ... From 00636def6418a40ceb791e0d11aafe1a25692e72 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Sat, 22 Feb 2020 16:50:56 +0100 Subject: [PATCH 3/5] Fix IMAP4.tagged_commands type --- stdlib/2and3/imaplib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/2and3/imaplib.pyi b/stdlib/2and3/imaplib.pyi index d6409a85f8a8..5123e89984b5 100644 --- a/stdlib/2and3/imaplib.pyi +++ b/stdlib/2and3/imaplib.pyi @@ -25,7 +25,7 @@ class IMAP4: debug: int = ... state: str = ... literal: Optional[Text] = ... - tagged_commands: Dict[bytes, Optional[bytes]] + tagged_commands: Dict[bytes, Optional[List[bytes]]] untagged_responses: Dict[str, List[Union[bytes, Tuple[bytes, bytes]]]] continuation_response: str = ... is_readonly: bool = ... From 0caa84ab95da4e9173f3fb1443512acac94b3e2c Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Sat, 22 Feb 2020 16:52:34 +0100 Subject: [PATCH 4/5] Mark CommandResults as private --- stdlib/2and3/imaplib.pyi | 70 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/stdlib/2and3/imaplib.pyi b/stdlib/2and3/imaplib.pyi index 5123e89984b5..109deeaed59b 100644 --- a/stdlib/2and3/imaplib.pyi +++ b/stdlib/2and3/imaplib.pyi @@ -13,7 +13,7 @@ else: # TODO: Commands should use their actual return types, not this type alias. # E.g. Tuple[Literal["OK"], List[bytes]] -CommandResults = Tuple[str, List[Any]] +_CommandResults = Tuple[str, List[Any]] _AnyResponseData = Union[List[None], List[Union[bytes, Tuple[bytes, bytes]]]] @@ -47,53 +47,53 @@ class IMAP4: def send(self, data: bytes) -> None: ... def shutdown(self) -> None: ... def socket(self) -> _socket: ... - def recent(self) -> CommandResults: ... - def response(self, code: str) -> CommandResults: ... + def recent(self) -> _CommandResults: ... + def response(self, code: str) -> _CommandResults: ... def append(self, mailbox: str, flags: str, date_time: str, message: str) -> str: ... def authenticate(self, mechanism: str, authobject: Callable[[bytes], Optional[bytes]]) -> Tuple[str, str]: ... - def capability(self) -> CommandResults: ... - def check(self) -> CommandResults: ... - def close(self) -> CommandResults: ... - def copy(self, message_set: str, new_mailbox: str) -> CommandResults: ... - def create(self, mailbox: str) -> CommandResults: ... - def delete(self, mailbox: str) -> CommandResults: ... - def deleteacl(self, mailbox: str, who: str) -> CommandResults: ... + def capability(self) -> _CommandResults: ... + def check(self) -> _CommandResults: ... + def close(self) -> _CommandResults: ... + def copy(self, message_set: str, new_mailbox: str) -> _CommandResults: ... + def create(self, mailbox: str) -> _CommandResults: ... + def delete(self, mailbox: str) -> _CommandResults: ... + def deleteacl(self, mailbox: str, who: str) -> _CommandResults: ... if sys.version_info >= (3, 5): - def enable(self, capability: str) -> CommandResults: ... + def enable(self, capability: str) -> _CommandResults: ... def __enter__(self) -> IMAP4: ... def __exit__(self, *args) -> None: ... - def expunge(self) -> CommandResults: ... + def expunge(self) -> _CommandResults: ... def fetch(self, message_set: str, message_parts: str) -> Tuple[str, _AnyResponseData]: ... - def getacl(self, mailbox: str) -> CommandResults: ... - def getannotation(self, mailbox: str, entry: str, attribute: str) -> CommandResults: ... - def getquota(self, root: str) -> CommandResults: ... - def getquotaroot(self, mailbox: str) -> CommandResults: ... + def getacl(self, mailbox: str) -> _CommandResults: ... + def getannotation(self, mailbox: str, entry: str, attribute: str) -> _CommandResults: ... + def getquota(self, root: str) -> _CommandResults: ... + def getquotaroot(self, mailbox: str) -> _CommandResults: ... def list(self, directory: str = ..., pattern: str = ...) -> Tuple[str, _AnyResponseData]: ... def login(self, user: str, password: str) -> Tuple[Literal["OK"], List[bytes]]: ... - def login_cram_md5(self, user: str, password: str) -> CommandResults: ... + def login_cram_md5(self, user: str, password: str) -> _CommandResults: ... def logout(self) -> Tuple[str, _AnyResponseData]: ... - def lsub(self, directory: str = ..., pattern: str = ...) -> CommandResults: ... - def myrights(self, mailbox: str) -> CommandResults: ... - def namespace(self) -> CommandResults: ... + def lsub(self, directory: str = ..., pattern: str = ...) -> _CommandResults: ... + def myrights(self, mailbox: str) -> _CommandResults: ... + def namespace(self) -> _CommandResults: ... def noop(self) -> Tuple[str, List[bytes]]: ... - def partial(self, message_num: str, message_part: str, start: str, length: str) -> CommandResults: ... - def proxyauth(self, user: str) -> CommandResults: ... - def rename(self, oldmailbox: str, newmailbox: str) -> CommandResults: ... - def search(self, charset: Optional[str], *criteria: str) -> CommandResults: ... + def partial(self, message_num: str, message_part: str, start: str, length: str) -> _CommandResults: ... + def proxyauth(self, user: str) -> _CommandResults: ... + def rename(self, oldmailbox: str, newmailbox: str) -> _CommandResults: ... + def search(self, charset: Optional[str], *criteria: str) -> _CommandResults: ... def select(self, mailbox: str = ..., readonly: bool = ...) -> Tuple[str, List[Optional[bytes]]]: ... - def setacl(self, mailbox: str, who: str, what: str) -> CommandResults: ... - def setannotation(self, *args: str) -> CommandResults: ... - def setquota(self, root: str, limits: str) -> CommandResults: ... - def sort(self, sort_criteria: str, charset: str, *search_criteria: str) -> CommandResults: ... + def setacl(self, mailbox: str, who: str, what: str) -> _CommandResults: ... + def setannotation(self, *args: str) -> _CommandResults: ... + def setquota(self, root: str, limits: str) -> _CommandResults: ... + def sort(self, sort_criteria: str, charset: str, *search_criteria: str) -> _CommandResults: ... if sys.version_info >= (3,): def starttls(self, ssl_context: Optional[Any] = ...) -> Tuple[Literal["OK"], List[None]]: ... - def status(self, mailbox: str, names: str) -> CommandResults: ... - def store(self, message_set: str, command: str, flags: str) -> CommandResults: ... - def subscribe(self, mailbox: str) -> CommandResults: ... - def thread(self, threading_algorithm: str, charset: str, *search_criteria: str) -> CommandResults: ... - def uid(self, command: str, *args: str) -> CommandResults: ... - def unsubscribe(self, mailbox: str) -> CommandResults: ... - def xatom(self, name: str, *args: str) -> CommandResults: ... + def status(self, mailbox: str, names: str) -> _CommandResults: ... + def store(self, message_set: str, command: str, flags: str) -> _CommandResults: ... + def subscribe(self, mailbox: str) -> _CommandResults: ... + def thread(self, threading_algorithm: str, charset: str, *search_criteria: str) -> __CommandResults: ... + def uid(self, command: str, *args: str) -> _CommandResults: ... + def unsubscribe(self, mailbox: str) -> _CommandResults: ... + def xatom(self, name: str, *args: str) -> _CommandResults: ... def print_log(self) -> None: ... class IMAP4_SSL(IMAP4): From f2f948d5f0e3725bef0e1e8eee9a0063dc68927c Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Sat, 22 Feb 2020 17:14:49 +0100 Subject: [PATCH 5/5] Fix --- stdlib/2and3/imaplib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/2and3/imaplib.pyi b/stdlib/2and3/imaplib.pyi index 109deeaed59b..8a58846ee986 100644 --- a/stdlib/2and3/imaplib.pyi +++ b/stdlib/2and3/imaplib.pyi @@ -90,7 +90,7 @@ class IMAP4: def status(self, mailbox: str, names: str) -> _CommandResults: ... def store(self, message_set: str, command: str, flags: str) -> _CommandResults: ... def subscribe(self, mailbox: str) -> _CommandResults: ... - def thread(self, threading_algorithm: str, charset: str, *search_criteria: str) -> __CommandResults: ... + def thread(self, threading_algorithm: str, charset: str, *search_criteria: str) -> _CommandResults: ... def uid(self, command: str, *args: str) -> _CommandResults: ... def unsubscribe(self, mailbox: str) -> _CommandResults: ... def xatom(self, name: str, *args: str) -> _CommandResults: ...