From 0da876ff34475ae823043c2ec5d001215becfc1a Mon Sep 17 00:00:00 2001 From: Pavel Karateev Date: Mon, 6 Dec 2021 21:31:21 +0300 Subject: [PATCH 1/3] Add more ast.parse() mode overrides eval -> Expression func_type -> FunctionType single -> Interactive --- stdlib/ast.pyi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index 8f9865679277..a93845bbba2d 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -165,6 +165,33 @@ if sys.version_info >= (3, 8): feature_version: None | int | _typing.Tuple[int, int] = ..., ) -> Module: ... @overload + def parse( + source: str | bytes, + filename: str | bytes = ..., + mode: Literal["eval"] = ..., + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Expression: ... + @overload + def parse( + source: str | bytes, + filename: str | bytes = ..., + mode: Literal["func_type"] = ..., + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> FunctionType: ... + @overload + def parse( + source: str | bytes, + filename: str | bytes = ..., + mode: Literal["single"] = ..., + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Interactive: ... + @overload def parse( source: str | bytes, filename: str | bytes = ..., @@ -178,6 +205,10 @@ else: @overload def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["exec"] = ...) -> Module: ... @overload + def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["eval"] = ...) -> Expression: ... + @overload + def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["single"] = ...) -> Interactive: ... + @overload def parse(source: str | bytes, filename: str | bytes = ..., mode: str = ...) -> AST: ... if sys.version_info >= (3, 9): From c092ce39c7d708900e0f1a53cb6a092daf6c80e6 Mon Sep 17 00:00:00 2001 From: Pavel Karateev Date: Thu, 9 Dec 2021 10:08:26 +0300 Subject: [PATCH 2/3] Resolve ast.parse() overrides clash We need (simplified) to cover all cases in Python >= 3.8 - 1 case: parse(filename: str = ...) - 4 cases: parse(filename: str, mode: Literal[...]) - 4 cases: parse(*, mode: Literal[...]) --- stdlib/ast.pyi | 65 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index a93845bbba2d..13c896608f93 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -159,7 +159,6 @@ if sys.version_info >= (3, 8): def parse( source: str | bytes, filename: str | bytes = ..., - mode: Literal["exec"] = ..., *, type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., @@ -167,8 +166,17 @@ if sys.version_info >= (3, 8): @overload def parse( source: str | bytes, - filename: str | bytes = ..., - mode: Literal["eval"] = ..., + filename: str | bytes, + mode: Literal["exec"], + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Module: ... + @overload + def parse( + source: str | bytes, + filename: str | bytes, + mode: Literal["eval"], *, type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., @@ -176,8 +184,8 @@ if sys.version_info >= (3, 8): @overload def parse( source: str | bytes, - filename: str | bytes = ..., - mode: Literal["func_type"] = ..., + filename: str | bytes, + mode: Literal["func_type"], *, type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., @@ -185,8 +193,8 @@ if sys.version_info >= (3, 8): @overload def parse( source: str | bytes, - filename: str | bytes = ..., - mode: Literal["single"] = ..., + filename: str | bytes, + mode: Literal["single"], *, type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., @@ -194,22 +202,51 @@ if sys.version_info >= (3, 8): @overload def parse( source: str | bytes, - filename: str | bytes = ..., - mode: str = ..., *, + mode: Literal["exec"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Module: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["eval"], type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., - ) -> AST: ... + ) -> Expression: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["func_type"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> FunctionType: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["single"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Interactive: ... else: @overload - def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["exec"] = ...) -> Module: ... + def parse(source: str | bytes, filename: str | bytes = ...) -> Module: ... + @overload + def parse(source: str | bytes, filename: str | bytes, mode: Literal["exec"]) -> Module: ... + @overload + def parse(source: str | bytes, filename: str | bytes, mode: Literal["eval"]) -> Expression: ... + @overload + def parse(source: str | bytes, filename: str | bytes, mode: Literal["single"]) -> Interactive: ... @overload - def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["eval"] = ...) -> Expression: ... + def parse(source: str | bytes, *, mode: Literal["exec"]) -> Module: ... @overload - def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["single"] = ...) -> Interactive: ... + def parse(source: str | bytes, *, mode: Literal["eval"]) -> Expression: ... @overload - def parse(source: str | bytes, filename: str | bytes = ..., mode: str = ...) -> AST: ... + def parse(source: str | bytes, *, mode: Literal["single"]) -> Interactive: ... if sys.version_info >= (3, 9): def unparse(ast_obj: AST) -> str: ... From 76bdcbaff6cd36f2104d99aa8923568ce0497e6a Mon Sep 17 00:00:00 2001 From: Pavel Karateev Date: Fri, 10 Dec 2021 18:40:27 +0300 Subject: [PATCH 3/3] Remove needless ast.parse() overloads The default case should have both `filename` and `mode` as keyword parameters, this way one can omit separate overloads for exec mode --- stdlib/ast.pyi | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index 13c896608f93..94d76f6cff5a 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -159,15 +159,7 @@ if sys.version_info >= (3, 8): def parse( source: str | bytes, filename: str | bytes = ..., - *, - type_comments: bool = ..., - feature_version: None | int | _typing.Tuple[int, int] = ..., - ) -> Module: ... - @overload - def parse( - source: str | bytes, - filename: str | bytes, - mode: Literal["exec"], + mode: Literal["exec"] = ..., *, type_comments: bool = ..., feature_version: None | int | _typing.Tuple[int, int] = ..., @@ -200,14 +192,6 @@ if sys.version_info >= (3, 8): feature_version: None | int | _typing.Tuple[int, int] = ..., ) -> Interactive: ... @overload - def parse( - source: str | bytes, - *, - mode: Literal["exec"], - type_comments: bool = ..., - feature_version: None | int | _typing.Tuple[int, int] = ..., - ) -> Module: ... - @overload def parse( source: str | bytes, *, @@ -234,16 +218,12 @@ if sys.version_info >= (3, 8): else: @overload - def parse(source: str | bytes, filename: str | bytes = ...) -> Module: ... - @overload - def parse(source: str | bytes, filename: str | bytes, mode: Literal["exec"]) -> Module: ... + def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["exec"] = ...) -> Module: ... @overload def parse(source: str | bytes, filename: str | bytes, mode: Literal["eval"]) -> Expression: ... @overload def parse(source: str | bytes, filename: str | bytes, mode: Literal["single"]) -> Interactive: ... @overload - def parse(source: str | bytes, *, mode: Literal["exec"]) -> Module: ... - @overload def parse(source: str | bytes, *, mode: Literal["eval"]) -> Expression: ... @overload def parse(source: str | bytes, *, mode: Literal["single"]) -> Interactive: ...