FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

refactor `visit_conditional_expr` to fix ternary behavior (option 1) by randolf-scholz · Pull Request #19563 · python/mypy · GitHub

Repository navigation

refactor visit_conditional_expr to fix ternary behavior (option 1) - #19563

Merged
hauntsaninja merged 5 commits into
python:masterfrom
randolf-scholz:fix_ternary_option1
Dec 14, 2025
Merged

hauntsaninja merged 5 commits into
python:masterfrom
randolf-scholz:fix_ternary_option1

Conversation

randolf-scholz commented Aug 1, 2025 •
edited
Loading

Copy link
Copy Markdown
Contributor

Option ① from #19561 (comment) which does not allow MemberExpr elements to the nested binder, hence ternaries like f(x.attr) if x.attr else g(x.attr) will not consider the narrowed type of x.attr

Option ②: #19562

The current implementation of visit_conditional_expr seemed to some rather complicated things, I found that if there is no context, we can simply use the union of the types produced when considering the branches context-free as an artificial context that leads to the desired behavior in the unification test cases.

randolf-scholz changed the title refactor visit_conditional_expr to fix ternary behavior refactor visit_conditional_expr to fix ternary behavior (option 1) Aug 1, 2025

This comment has been minimized.

1 similar comment

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

Repro of pyodide-build:

uv_bin: str | None

install_prefix = (
    [uv_bin, "pip", "install"]
    if bool()
    else ["/bin/python", "-m", "pip", "install", "--no-user"]
)
reveal_type(install_prefix)     # master: list[str | None], PR: list[str | None] | list[str]
reveal_type([*install_prefix])  # master: list[str | None], PR: list[Any]

It seems like this is due to some overly aggressive join operation, [*install_prefix] should get inferred as list[str | None] regardless whether install_prefix is just list[str | None] or list[str | None] | list[str].

Copy link
Copy Markdown
Collaborator

Joins don't typically result in Any's. Looks like this was some other missing case: #19650

This comment has been minimized.

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

optuna (https://github.com/optuna/optuna)
+ optuna/visualization/_intermediate_values.py:95: error: Unused "type: ignore" comment  [unused-ignore]

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/runner/storage.py:178: error: Argument 1 to "deepcopy" has incompatible type "Union[GitCredentials, Block, dict[str, Any]]"; expected "dict[str, Any]"  [arg-type]
+ src/prefect/runner/storage.py:183: error: TypedDict key must be a string literal; expected one of ("username", "access_token")  [literal-required]
+ src/prefect/runner/storage.py:185: error: TypedDict key must be a string literal; expected one of ("username", "access_token")  [literal-required]

colour (https://github.com/colour-science/colour)
+ colour/io/luts/lut.py:1418: error: Argument 1 to "tile" has incompatible type "Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None"; expected "_SupportsArray[dtype[signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | Any]] | _NestedSequence[_SupportsArray[dtype[signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | Any]]]"  [arg-type]
- colour/io/luts/lut.py:1432: error: No overload variant of "pad" matches argument types "ndarray[Any, Any]", "tuple[int, Any | signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit]]", "str", "float"  [call-overload]
- colour/io/luts/lut.py:1432: note: Possible overload variants:
- colour/io/luts/lut.py:1432: note:     def [_ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[_ScalarT]] | _NestedSequence[_SupportsArray[dtype[_ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[_ScalarT]]
- colour/io/luts/lut.py:1432: note:     def pad(array: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[Any]]
- colour/io/luts/lut.py:1432: note:     def [_ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[_ScalarT]] | _NestedSequence[_SupportsArray[dtype[_ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: _ModeFunc, **kwargs: Any) -> ndarray[tuple[Any, ...], dtype[_ScalarT]]
- colour/io/luts/lut.py:1432: note:     def pad(array: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: _ModeFunc, **kwargs: Any) -> ndarray[tuple[Any, ...], dtype[Any]]

mypy (https://github.com/python/mypy)
+ mypyc/irbuild/statement.py:602: error: Argument 1 to "accept" of "IRBuilder" has incompatible type "Optional[Block]"; expected "Statement"  [arg-type]

steam.py (https://github.com/Gobot1234/steam.py)
+ steam/utils.py:883: error: Unused "type: ignore" comment  [unused-ignore]
- steam/http.py:100: error: Dict entry 0 has incompatible type "str": "str | None"; expected "str": "str"  [dict-item]
- steam/gateway.py:830: error: No overload variant of "wait_for" of "SteamWebSocket" matches argument types "int", "Callable[[UnifiedMsgT], bool]"  [call-overload]
+ steam/gateway.py:830: error: No overload variant of "wait_for" of "SteamWebSocket" matches argument types "int", "Callable[[UnifiedMsgT], bool] | Callable[[Any], Any]"  [call-overload]

discord.py (https://github.com/Rapptz/discord.py)
+ discord/utils.py:485: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/utils.py:599: error: Unused "type: ignore" comment  [unused-ignore]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/appsec/_iast/_taint_tracking/aspects.py:706: error: Unused "type: ignore" comment  [unused-ignore]

pyodide (https://github.com/pyodide/pyodide)
- pyodide-build/pyodide_build/xbuildenv.py:309: error: List item 0 has incompatible type "list[str | None]"; expected "str | bytes | PathLike[str] | PathLike[bytes]"  [list-item]

hauntsaninja left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thanks, this seems like a really great change!

hauntsaninja merged commit bc2481a into python:master Dec 14, 2025
20 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

3 participants


Back | FazBrowse Home | New Git URL