From 46f2965d3b9ad56be27df4646792c014253eb954 Mon Sep 17 00:00:00 2001 From: donbarbos Date: Sun, 11 Jan 2026 17:48:49 +0400 Subject: [PATCH 1/4] [stdlib] Deprecate keyfile, certfile and check_hostname parameters Source: https://github.com/python/cpython/pull/94173 --- stdlib/ftplib.pyi | 28 +++++++++++++++++++++++----- stdlib/http/client.pyi | 18 ++++++++++++++++++ stdlib/imaplib.pyi | 11 ++++++++++- stdlib/poplib.pyi | 11 ++++++++++- stdlib/smtplib.pyi | 29 ++++++++++++++++++++++++++--- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/stdlib/ftplib.pyi b/stdlib/ftplib.pyi index 44bc2165fe0e..df6d22f0e216 100644 --- a/stdlib/ftplib.pyi +++ b/stdlib/ftplib.pyi @@ -4,8 +4,8 @@ from collections.abc import Callable, Iterable, Iterator from socket import socket from ssl import SSLContext from types import TracebackType -from typing import Any, Final, Literal, TextIO -from typing_extensions import Self +from typing import Any, Final, Literal, TextIO, overload +from typing_extensions import Self, deprecated __all__ = ["FTP", "error_reply", "error_temp", "error_perm", "error_proto", "all_errors", "FTP_TLS"] @@ -120,6 +120,24 @@ class FTP_TLS(FTP): encoding: str = "utf-8", ) -> None: ... else: + @overload + def __init__( + self, + host: str = "", + user: str = "", + passwd: str = "", + acct: str = "", + *, + context: SSLContext | None = None, + timeout: float | None = ..., + source_address: tuple[str, int] | None = None, + encoding: str = "utf-8", + ) -> None: ... + @overload + @deprecated( + "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `context` parameter instead." + ) def __init__( self, host: str = "", @@ -134,9 +152,9 @@ class FTP_TLS(FTP): *, encoding: str = "utf-8", ) -> None: ... - ssl_version: int - keyfile: str | None - certfile: str | None + ssl_version: int + keyfile: str | None + certfile: str | None context: SSLContext def login(self, user: str = "", passwd: str = "", acct: str = "", secure: bool = True) -> str: ... def auth(self) -> str: ... diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index 1ae63c76bf3a..54a188d0dd14 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -223,6 +223,22 @@ class HTTPSConnection(HTTPConnection): blocksize: int = 8192, ) -> None: ... else: + @overload + def __init__( + self, + host: str, + port: int | None = None, + timeout: float | None = ..., + source_address: tuple[str, int] | None = None, + *, + context: ssl.SSLContext | None = None, + blocksize: int = 8192, + ) -> None: ... + @overload + @deprecated( + "The `key_file`, `cert_file`, `check_hostname` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `context` parameter instead." + ) def __init__( self, host: str, @@ -236,6 +252,8 @@ class HTTPSConnection(HTTPConnection): check_hostname: bool | None = None, blocksize: int = 8192, ) -> None: ... + key_file: str | None + cert_file: str | None class HTTPException(Exception): ... diff --git a/stdlib/imaplib.pyi b/stdlib/imaplib.pyi index 1f0e0106006b..6fe123519d63 100644 --- a/stdlib/imaplib.pyi +++ b/stdlib/imaplib.pyi @@ -9,7 +9,7 @@ from re import Pattern from socket import socket as _socket from ssl import SSLContext, SSLSocket from types import TracebackType -from typing import IO, Any, Literal, SupportsAbs, SupportsInt +from typing import IO, Any, Literal, SupportsAbs, SupportsInt, overload from typing_extensions import Self, TypeAlias, deprecated __all__ = ["IMAP4", "IMAP4_stream", "Internaldate2tuple", "Int2AP", "ParseFlags", "Time2Internaldate", "IMAP4_SSL"] @@ -128,6 +128,15 @@ class IMAP4_SSL(IMAP4): self, host: str = "", port: int = 993, *, ssl_context: SSLContext | None = None, timeout: float | None = None ) -> None: ... else: + @overload + def __init__( + self, host: str = "", port: int = 993, *, ssl_context: SSLContext | None = None, timeout: float | None = None + ) -> None: ... + @overload + @deprecated( + "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `ssl_context` parameter instead." + ) def __init__( self, host: str = "", diff --git a/stdlib/poplib.pyi b/stdlib/poplib.pyi index 9ff2b764aeb6..658ff57e6040 100644 --- a/stdlib/poplib.pyi +++ b/stdlib/poplib.pyi @@ -4,7 +4,7 @@ import sys from builtins import list as _list # conflicts with a method named "list" from re import Pattern from typing import Any, BinaryIO, Final, NoReturn, overload -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, deprecated __all__ = ["POP3", "error_proto", "POP3_SSL"] @@ -58,6 +58,15 @@ class POP3_SSL(POP3): ) -> None: ... def stls(self, context: Any = None) -> NoReturn: ... else: + @overload + def __init__( + self, host: str, port: int = 995, *, timeout: float = ..., context: ssl.SSLContext | None = None + ) -> None: ... + @overload + @deprecated( + "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `context` parameter instead." + ) def __init__( self, host: str, diff --git a/stdlib/smtplib.pyi b/stdlib/smtplib.pyi index 6a8467689367..431e8c8eea8a 100644 --- a/stdlib/smtplib.pyi +++ b/stdlib/smtplib.pyi @@ -8,7 +8,7 @@ from socket import socket from ssl import SSLContext from types import TracebackType from typing import Any, Final, Protocol, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, deprecated __all__ = [ "SMTPException", @@ -131,6 +131,13 @@ class SMTP: if sys.version_info >= (3, 12): def starttls(self, *, context: SSLContext | None = None) -> _Reply: ... else: + @overload + def starttls(self, *, context: SSLContext | None = None) -> _Reply: ... + @overload + @deprecated( + "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `context` parameter instead." + ) def starttls( self, keyfile: str | None = None, certfile: str | None = None, context: SSLContext | None = None ) -> _Reply: ... @@ -155,8 +162,6 @@ class SMTP: def quit(self) -> _Reply: ... class SMTP_SSL(SMTP): - keyfile: str | None - certfile: str | None context: SSLContext if sys.version_info >= (3, 12): def __init__( @@ -170,6 +175,22 @@ class SMTP_SSL(SMTP): context: SSLContext | None = None, ) -> None: ... else: + @overload + def __init__( + self, + host: str = "", + port: int = 0, + local_hostname: str | None = None, + *, + timeout: float = ..., + source_address: _SourceAddress | None = None, + context: SSLContext | None = None, + ) -> None: ... + @overload + @deprecated( + "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " + "removed in Python 3.12. Use `context` parameter instead." + ) def __init__( self, host: str = "", @@ -181,6 +202,8 @@ class SMTP_SSL(SMTP): source_address: _SourceAddress | None = None, context: SSLContext | None = None, ) -> None: ... + keyfile: str | None + certfile: str | None LMTP_PORT: Final = 2003 From 24e1b9c1139d159a4b3095c7afe09860775b6582 Mon Sep 17 00:00:00 2001 From: donbarbos Date: Sun, 11 Jan 2026 18:08:20 +0400 Subject: [PATCH 2/4] Use StrOrBytesPath --- stdlib/ftplib.pyi | 10 +++++----- stdlib/http/client.pyi | 10 +++++----- stdlib/imaplib.pyi | 11 +++++------ stdlib/poplib.pyi | 7 +++++-- stdlib/smtplib.pyi | 12 ++++++------ 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/stdlib/ftplib.pyi b/stdlib/ftplib.pyi index df6d22f0e216..2558cbec7cd5 100644 --- a/stdlib/ftplib.pyi +++ b/stdlib/ftplib.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import SupportsRead, SupportsReadline +from _typeshed import StrOrBytesPath, SupportsRead, SupportsReadline from collections.abc import Callable, Iterable, Iterator from socket import socket from ssl import SSLContext @@ -144,8 +144,8 @@ class FTP_TLS(FTP): user: str = "", passwd: str = "", acct: str = "", - keyfile: str | None = None, - certfile: str | None = None, + keyfile: StrOrBytesPath | None = None, + certfile: StrOrBytesPath | None = None, context: SSLContext | None = None, timeout: float | None = ..., source_address: tuple[str, int] | None = None, @@ -153,8 +153,8 @@ class FTP_TLS(FTP): encoding: str = "utf-8", ) -> None: ... ssl_version: int - keyfile: str | None - certfile: str | None + keyfile: StrOrBytesPath | None + certfile: StrOrBytesPath | None context: SSLContext def login(self, user: str = "", passwd: str = "", acct: str = "", secure: bool = True) -> str: ... def auth(self) -> str: ... diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index 54a188d0dd14..e01c0165a151 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -3,7 +3,7 @@ import io import ssl import sys import types -from _typeshed import MaybeNone, ReadableBuffer, SupportsRead, SupportsReadline, WriteableBuffer +from _typeshed import MaybeNone, ReadableBuffer, StrOrBytesPath, SupportsRead, SupportsReadline, WriteableBuffer from collections.abc import Callable, Iterable, Iterator, Mapping from email._policybase import _MessageT from socket import socket @@ -243,8 +243,8 @@ class HTTPSConnection(HTTPConnection): self, host: str, port: int | None = None, - key_file: str | None = None, - cert_file: str | None = None, + key_file: StrOrBytesPath | None = None, + cert_file: StrOrBytesPath | None = None, timeout: float | None = ..., source_address: tuple[str, int] | None = None, *, @@ -252,8 +252,8 @@ class HTTPSConnection(HTTPConnection): check_hostname: bool | None = None, blocksize: int = 8192, ) -> None: ... - key_file: str | None - cert_file: str | None + key_file: StrOrBytesPath | None + cert_file: StrOrBytesPath | None class HTTPException(Exception): ... diff --git a/stdlib/imaplib.pyi b/stdlib/imaplib.pyi index 6fe123519d63..3f0e23cd5852 100644 --- a/stdlib/imaplib.pyi +++ b/stdlib/imaplib.pyi @@ -1,7 +1,7 @@ import subprocess import sys import time -from _typeshed import ReadableBuffer, SizedBuffer, Unused +from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath, Unused from builtins import list as _list # conflicts with a method named "list" from collections.abc import Callable, Generator from datetime import datetime @@ -120,9 +120,6 @@ if sys.version_info >= (3, 14): def burst(self, interval: float = 0.1) -> Generator[tuple[str, float | None]]: ... class IMAP4_SSL(IMAP4): - if sys.version_info < (3, 12): - keyfile: str - certfile: str if sys.version_info >= (3, 12): def __init__( self, host: str = "", port: int = 993, *, ssl_context: SSLContext | None = None, timeout: float | None = None @@ -141,11 +138,13 @@ class IMAP4_SSL(IMAP4): self, host: str = "", port: int = 993, - keyfile: str | None = None, - certfile: str | None = None, + keyfile: StrOrBytesPath | None = None, + certfile: StrOrBytesPath | None = None, ssl_context: SSLContext | None = None, timeout: float | None = None, ) -> None: ... + keyfile: StrOrBytesPath | None + certfile: StrOrBytesPath | None sslobj: SSLSocket if sys.version_info >= (3, 14): @property diff --git a/stdlib/poplib.pyi b/stdlib/poplib.pyi index 658ff57e6040..0b5b7d26f206 100644 --- a/stdlib/poplib.pyi +++ b/stdlib/poplib.pyi @@ -1,6 +1,7 @@ import socket import ssl import sys +from _typeshed import StrOrBytesPath from builtins import list as _list # conflicts with a method named "list" from re import Pattern from typing import Any, BinaryIO, Final, NoReturn, overload @@ -71,11 +72,13 @@ class POP3_SSL(POP3): self, host: str, port: int = 995, - keyfile: str | None = None, - certfile: str | None = None, + keyfile: StrOrBytesPath | None = None, + certfile: StrOrBytesPath | None = None, timeout: float = ..., context: ssl.SSLContext | None = None, ) -> None: ... + keyfile: StrOrBytesPath | None + certfile: StrOrBytesPath | None # "context" is actually the last argument, # but that breaks LSP and it doesn't really matter because all the arguments are ignored def stls(self, context: Any = None, keyfile: Any = None, certfile: Any = None) -> NoReturn: ... diff --git a/stdlib/smtplib.pyi b/stdlib/smtplib.pyi index 431e8c8eea8a..03d56883e55e 100644 --- a/stdlib/smtplib.pyi +++ b/stdlib/smtplib.pyi @@ -1,6 +1,6 @@ import sys from _socket import _Address as _SourceAddress -from _typeshed import ReadableBuffer, SizedBuffer +from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath from collections.abc import Sequence from email.message import Message as _Message from re import Pattern @@ -139,7 +139,7 @@ class SMTP: "removed in Python 3.12. Use `context` parameter instead." ) def starttls( - self, keyfile: str | None = None, certfile: str | None = None, context: SSLContext | None = None + self, keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, context: SSLContext | None = None ) -> _Reply: ... def sendmail( @@ -196,14 +196,14 @@ class SMTP_SSL(SMTP): host: str = "", port: int = 0, local_hostname: str | None = None, - keyfile: str | None = None, - certfile: str | None = None, + keyfile: StrOrBytesPath | None = None, + certfile: StrOrBytesPath | None = None, timeout: float = ..., source_address: _SourceAddress | None = None, context: SSLContext | None = None, ) -> None: ... - keyfile: str | None - certfile: str | None + keyfile: StrOrBytesPath | None + certfile: StrOrBytesPath | None LMTP_PORT: Final = 2003 From d2dca339e7592010b5ae79f0ac9d3cbe6b565e47 Mon Sep 17 00:00:00 2001 From: donbarbos Date: Sun, 11 Jan 2026 18:10:35 +0400 Subject: [PATCH 3/4] fix http.client * --- stdlib/http/client.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index e01c0165a151..19cee2ed0683 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -228,9 +228,9 @@ class HTTPSConnection(HTTPConnection): self, host: str, port: int | None = None, + *, timeout: float | None = ..., source_address: tuple[str, int] | None = None, - *, context: ssl.SSLContext | None = None, blocksize: int = 8192, ) -> None: ... From 77c70edaf11ee48220c1e311fdacc1f149c7e24b Mon Sep 17 00:00:00 2001 From: donbarbos Date: Mon, 12 Jan 2026 00:22:26 +0400 Subject: [PATCH 4/4] reflect the impossibility of passing context and "files" args at once --- stdlib/ftplib.pyi | 6 ++++-- stdlib/http/client.pyi | 5 ++++- stdlib/imaplib.pyi | 10 ++++++++-- stdlib/poplib.pyi | 10 ++++++++-- stdlib/smtplib.pyi | 9 +++++---- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/stdlib/ftplib.pyi b/stdlib/ftplib.pyi index 2558cbec7cd5..73eaa8a34e57 100644 --- a/stdlib/ftplib.pyi +++ b/stdlib/ftplib.pyi @@ -127,10 +127,12 @@ class FTP_TLS(FTP): user: str = "", passwd: str = "", acct: str = "", - *, + keyfile: None = None, + certfile: None = None, context: SSLContext | None = None, timeout: float | None = ..., source_address: tuple[str, int] | None = None, + *, encoding: str = "utf-8", ) -> None: ... @overload @@ -146,7 +148,7 @@ class FTP_TLS(FTP): acct: str = "", keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, - context: SSLContext | None = None, + context: None = None, timeout: float | None = ..., source_address: tuple[str, int] | None = None, *, diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index 19cee2ed0683..699ef0e4c6d6 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -228,10 +228,13 @@ class HTTPSConnection(HTTPConnection): self, host: str, port: int | None = None, - *, + key_file: None = None, + cert_file: None = None, timeout: float | None = ..., source_address: tuple[str, int] | None = None, + *, context: ssl.SSLContext | None = None, + check_hostname: None = None, blocksize: int = 8192, ) -> None: ... @overload diff --git a/stdlib/imaplib.pyi b/stdlib/imaplib.pyi index 3f0e23cd5852..471530124f0c 100644 --- a/stdlib/imaplib.pyi +++ b/stdlib/imaplib.pyi @@ -127,7 +127,13 @@ class IMAP4_SSL(IMAP4): else: @overload def __init__( - self, host: str = "", port: int = 993, *, ssl_context: SSLContext | None = None, timeout: float | None = None + self, + host: str = "", + port: int = 993, + keyfile: None = None, + certfile: None = None, + ssl_context: SSLContext | None = None, + timeout: float | None = None, ) -> None: ... @overload @deprecated( @@ -140,7 +146,7 @@ class IMAP4_SSL(IMAP4): port: int = 993, keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, - ssl_context: SSLContext | None = None, + ssl_context: None = None, timeout: float | None = None, ) -> None: ... keyfile: StrOrBytesPath | None diff --git a/stdlib/poplib.pyi b/stdlib/poplib.pyi index 0b5b7d26f206..f5669ec87e87 100644 --- a/stdlib/poplib.pyi +++ b/stdlib/poplib.pyi @@ -61,7 +61,13 @@ class POP3_SSL(POP3): else: @overload def __init__( - self, host: str, port: int = 995, *, timeout: float = ..., context: ssl.SSLContext | None = None + self, + host: str, + port: int = 995, + keyfile: None = None, + certfile: None = None, + timeout: float = ..., + context: ssl.SSLContext | None = None, ) -> None: ... @overload @deprecated( @@ -75,7 +81,7 @@ class POP3_SSL(POP3): keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, timeout: float = ..., - context: ssl.SSLContext | None = None, + context: None = None, ) -> None: ... keyfile: StrOrBytesPath | None certfile: StrOrBytesPath | None diff --git a/stdlib/smtplib.pyi b/stdlib/smtplib.pyi index 03d56883e55e..74b5ea2cb6fc 100644 --- a/stdlib/smtplib.pyi +++ b/stdlib/smtplib.pyi @@ -132,14 +132,14 @@ class SMTP: def starttls(self, *, context: SSLContext | None = None) -> _Reply: ... else: @overload - def starttls(self, *, context: SSLContext | None = None) -> _Reply: ... + def starttls(self, keyfile: None = None, certfile: None = None, context: SSLContext | None = None) -> _Reply: ... @overload @deprecated( "The `keyfile`, `certfile` parameters are deprecated since Python 3.6; " "removed in Python 3.12. Use `context` parameter instead." ) def starttls( - self, keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, context: SSLContext | None = None + self, keyfile: StrOrBytesPath | None = None, certfile: StrOrBytesPath | None = None, context: None = None ) -> _Reply: ... def sendmail( @@ -181,7 +181,8 @@ class SMTP_SSL(SMTP): host: str = "", port: int = 0, local_hostname: str | None = None, - *, + keyfile: None = None, + certfile: None = None, timeout: float = ..., source_address: _SourceAddress | None = None, context: SSLContext | None = None, @@ -200,7 +201,7 @@ class SMTP_SSL(SMTP): certfile: StrOrBytesPath | None = None, timeout: float = ..., source_address: _SourceAddress | None = None, - context: SSLContext | None = None, + context: None = None, ) -> None: ... keyfile: StrOrBytesPath | None certfile: StrOrBytesPath | None