-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Improve consistency of NoReturn #12043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Diff from mypy_primer, showing the effect of this PR on open source code: steam.py (https://github.com/Gobot1234/steam.py)
- steam/state.py:842: error: Incompatible types in assignment (expression has type "User", variable has type "CMsgClientFriendsListFriend") [assignment]
+ steam/state.py:842: error: Incompatible types in assignment (expression has type "Optional[User]", variable has type "CMsgClientFriendsListFriend") [assignment]
spark (https://github.com/apache/spark)
- python/pyspark/pandas/series.py:4247: error: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior [str-bytes-safe]
pip (https://github.com/pypa/pip)
- src/pip/_internal/cli/progress_bars.py:99: error: Incompatible types in assignment (expression has type "Callable[[int, FrameType], None]", variable has type "Union[Callable[[int, Optional[FrameType]], Any], int, None]")
+ src/pip/_internal/cli/progress_bars.py:99: error: Incompatible types in assignment (expression has type "Callable[[int, FrameType], None]", variable has type "Union[Callable[[int, Optional[FrameType]], Any], int, Handlers, None]")
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Please, see my comments 🙂
implementation CANNOT handle type aliases, because they might not yet be expanded. | ||
""" | ||
filtered: List[Type] = [tp for tp in types if not is_proper_noreturn_type(tp)] | ||
# If nothing is left, we know there was at least one NoReturn. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we can have an empty types[]
iterable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed this cannot happen, because in the call context of this method (constructor of Union) there must be at least one item in the Union.
So are you fine if I just add an assert len(types) >= 1
and chaning the type of types
to List
(instead of Iterable
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be Sequence
, the same as __init__
has
@@ -2611,6 +2623,11 @@ def is_optional(t: Type) -> bool: | |||
for e in t.items) | |||
|
|||
|
|||
def is_proper_noreturn_type(t: Type) -> bool: | |||
return isinstance(t, ProperType) and \ | |||
isinstance(t, UninhabitedType) and t.is_noreturn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t
is always ProperType
if it is UninhabitedType
.
I guess what we should do here is:
t = get_proper_type(t)
return isinstance(t, UninhabitedType) and t.is_noreturn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is related to the problem of the "Limitation" section.
t = get_proper_type(t)
return isinstance(t, UninhabitedType) and t.is_noreturn
here get_proper_type(t)
fails in _expand_once()
on the following assertion assert self.alias is not None
Therefore, I limited the implementation to not handle type aliases and added the isinstance(t, ProperType)
check instead.
@@ -385,7 +385,7 @@ from mypy_extensions import NoReturn | |||
def no_return() -> NoReturn: pass | |||
def f() -> int: | |||
return 0 | |||
reveal_type(f() or no_return()) # N: Revealed type is "builtins.int" | |||
reveal_type(f() or no_return()) # N: Revealed type is "Union[builtins.int]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not happen, Union
of a single item should be simplified to just this item.
The longer I think about it, the less useful I see these changes. The main problem I have right now is:
I will close this. In case I have a new idea, I would open a new PR. Sorry, for wasting time and thank you for your feedback :) |
Motivation
Follow-up pull request for #11996, implementing proposals from @JukkaL.
The mentioned PR used
make_simplified_union
to enable the following behavior:However, there are two problems with it:
Union
was simplified or not.Implementation
make_simplified_union
(I am planning to work on this bug afterwards):We could also keep it, to avoid this minor regression (the fix was never released so actually there is no regression).
Remove
NoReturn
types during the construction (after runningflatten_nested_unions
). For code readability reasons I decided to introduce another methodreduce_proper_noreturn_types
to perform this job (instead of doing the operation inflatten_nested_unions
).In order to fulfill the invariant for non changing semantic for
make_simplified_union
, the method was changed in order to ignoreNoReturn
types (except for reducingUnion[NoReturn]
toNoReturn
. In fact, this check is kind of useless, at the moment, becauseNoReturns
were already removed during theUnion
construction. However, it might help with consistency (for future code changes).Limitations
The implementation cannot handle type aliases:
The problem is that
Unions
are created before type aliases are fully expanded.However, we can get the expected behavior with the following horribly "hacky" code. Are there any idea how to solve this elegantly?
Test Plan
[case testUnionWithNoReturn]
to include more checksNoReturn
checks intotest_simplified_union
.mypy_primer
Reverse of #11996.