From 6b52aadd3db3cab85be4738da142bf7e94be7022 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 19 Nov 2024 19:34:03 -0800 Subject: [PATCH 1/4] add email.__all__ --- stdlib/@tests/stubtest_allowlists/common.txt | 13 ----- stdlib/email/__init__.pyi | 53 ++++++++++++++------ 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 055e0d7d3df3..4b293be3b73f 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -577,19 +577,6 @@ codecs.StreamRecoder.\w+ urllib.response.addbase.\w+ # __all__-related weirdness (see #6523) -email.base64mime -email.charset -email.encoders -email.errors -email.feedparser -email.generator -email.header -email.iterators -email.message -email.mime -email.parser -email.quoprimime -email.utils xml.dom xml.etree xml.sax diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index fca302f5f1a7..ebdabaca634f 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -4,6 +4,44 @@ from email.policy import Policy from typing import IO from typing_extensions import TypeAlias +# These aren't actually imported here at runtime. This is a work-around for the +# fact that they're included in __all__ anyway. +from . import ( + base64mime as base64mime, + charset as charset, + encoders as encoders, + errors as errors, + feedparser as feedparser, + generator as generator, + header as header, + iterators as iterators, + message as message, + mime as mime, + parser as parser, + quoprimime as quoprimime, + utils as utils, +) + +__all__ = [ + "base64mime", + "charset", + "encoders", + "errors", + "feedparser", + "generator", + "header", + "iterators", + "message", + "message_from_file", + "message_from_binary_file", + "message_from_string", + "message_from_bytes", + "mime", + "parser", + "quoprimime", + "utils", +] + # Definitions imported by multiple submodules in typeshed _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 @@ -12,18 +50,3 @@ def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... - -# Names in __all__ with no definition: -# base64mime -# charset -# encoders -# errors -# feedparser -# generator -# header -# iterators -# message -# mime -# parser -# quoprimime -# utils From 9a9354ffda91c8a9ff3c9d31ad17702a03cdbbd0 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 19 Nov 2024 19:56:37 -0800 Subject: [PATCH 2/4] more accurate --- stdlib/email/__init__.pyi | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index ebdabaca634f..9475db72e00a 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -4,25 +4,7 @@ from email.policy import Policy from typing import IO from typing_extensions import TypeAlias -# These aren't actually imported here at runtime. This is a work-around for the -# fact that they're included in __all__ anyway. -from . import ( - base64mime as base64mime, - charset as charset, - encoders as encoders, - errors as errors, - feedparser as feedparser, - generator as generator, - header as header, - iterators as iterators, - message as message, - mime as mime, - parser as parser, - quoprimime as quoprimime, - utils as utils, -) - -__all__ = [ +__all__ = [ # noqa: F822 # Undefined names in __all__ "base64mime", "charset", "encoders", @@ -50,3 +32,18 @@ def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... + +# Names in __all__ with no definition: +# base64mime +# charset +# encoders +# errors +# feedparser +# generator +# header +# iterators +# message +# mime +# parser +# quoprimime +# utils From a46a1d286858e5afd985c1191ec8f47d8b0adc1d Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 19 Nov 2024 19:57:57 -0800 Subject: [PATCH 3/4] forgot to update the allowlist --- stdlib/@tests/stubtest_allowlists/common.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 4b293be3b73f..d8578bd70284 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -577,6 +577,20 @@ codecs.StreamRecoder.\w+ urllib.response.addbase.\w+ # __all__-related weirdness (see #6523) +email.__all__ +email.base64mime +email.charset +email.encoders +email.errors +email.feedparser +email.generator +email.header +email.iterators +email.message +email.mime +email.parser +email.quoprimime +email.utils xml.dom xml.etree xml.sax From 97b140909e1a26d3ddb52f64742fe17ba69f9162 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Tue, 19 Nov 2024 20:04:30 -0800 Subject: [PATCH 4/4] pyright ignores --- stdlib/email/__init__.pyi | 44 ++++++++++++++------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index 9475db72e00a..f564ced105bd 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -4,24 +4,27 @@ from email.policy import Policy from typing import IO from typing_extensions import TypeAlias +# At runtime, listing submodules in __all__ without them being imported is +# valid, and causes them to be included in a star import. See #6523 + __all__ = [ # noqa: F822 # Undefined names in __all__ - "base64mime", - "charset", - "encoders", - "errors", - "feedparser", - "generator", - "header", - "iterators", - "message", + "base64mime", # pyright: ignore[reportUnsupportedDunderAll] + "charset", # pyright: ignore[reportUnsupportedDunderAll] + "encoders", # pyright: ignore[reportUnsupportedDunderAll] + "errors", # pyright: ignore[reportUnsupportedDunderAll] + "feedparser", # pyright: ignore[reportUnsupportedDunderAll] + "generator", # pyright: ignore[reportUnsupportedDunderAll] + "header", # pyright: ignore[reportUnsupportedDunderAll] + "iterators", # pyright: ignore[reportUnsupportedDunderAll] + "message", # pyright: ignore[reportUnsupportedDunderAll] "message_from_file", "message_from_binary_file", "message_from_string", "message_from_bytes", - "mime", - "parser", - "quoprimime", - "utils", + "mime", # pyright: ignore[reportUnsupportedDunderAll] + "parser", # pyright: ignore[reportUnsupportedDunderAll] + "quoprimime", # pyright: ignore[reportUnsupportedDunderAll] + "utils", # pyright: ignore[reportUnsupportedDunderAll] ] # Definitions imported by multiple submodules in typeshed @@ -32,18 +35,3 @@ def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... - -# Names in __all__ with no definition: -# base64mime -# charset -# encoders -# errors -# feedparser -# generator -# header -# iterators -# message -# mime -# parser -# quoprimime -# utils