Skip to content

Allow __init__ and __new__ to return NoReturn - #11216

Closed
BvB93 wants to merge 5 commits into
python:masterfrom
BvB93:noreturn
Closed

BvB93 wants to merge 5 commits into
python:masterfrom
BvB93:noreturn

Conversation

@BvB93

@BvB93 BvB93 commented Sep 28, 2021

Copy link
Copy Markdown
Contributor

Closes #10342

This PR allows __init__ and __new__ methods to return NoReturn, allowing for the annotation of classes
that cannot be directly initialized (e.g. those that are defined in C such as types.GeneratorType).

Comment on lines +6898 to +7303
class A:
def __new__(cls) -> NoReturn: ...

class B:
def __init__(self) -> NoReturn: ...

class C:
def __new__(cls) -> "C": ...
def __init__(self) -> NoReturn: ...

class D:
def __new__(cls) -> NoReturn: ...
def __init__(self) -> NoReturn: ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

class E:
    def __new__(cls) -> NoReturn: ...
    def __init__(self) -> None: ...

Notable in it's absence is the example above. Unfortunately this example fails to properly recognize NoReturn when instantiating the class, as mypy tends to ignore __new__ if __init__ is defined:

mypy/mypy/checkmember.py

Lines 969 to 973 in 8e82171

# Otherwise prefer __init__ in a tie. It isn't clear that this
# is the right thing, but __new__ caused problems with
# typeshed (#5647).
method = init_method.node
is_new = False

Comment thread test-data/unit/check-classes.test Outdated
Comment thread test-data/unit/check-classes.test Outdated
@BvB93

BvB93 commented Sep 30, 2021

Copy link
Copy Markdown
Contributor Author

Any idea what's going on with the failed Run mypy_primer / Run (2) Test?
It looks like it crashed while installing depencies or something.

@sobolevn

Copy link
Copy Markdown
Member

@BvB93 try to close / open this PR. It should be fixed now 👍

@BvB93 BvB93 closed this Sep 30, 2021
@BvB93 BvB93 reopened this Sep 30, 2021
@BvB93

BvB93 commented Sep 30, 2021

Copy link
Copy Markdown
Contributor Author

Let's give it a shot (note: I might need approval again as a first-time contributor)

@sobolevn

Copy link
Copy Markdown
Member

@BvB93 sorry, I cannot approve it 😞
We need to wait for maintainers to do that.

@JelleZijlstra

Copy link
Copy Markdown
Member

I pushed the approval button.

@BvB93

BvB93 commented Oct 11, 2021

Copy link
Copy Markdown
Contributor Author

So, are there any further comments on this PR?

@benkehoe

Copy link
Copy Markdown

Today I discovered that I can't annotate a class as unable to be instantiated through __init__() -> NoReturn. I'd love to see this PR merged!

@PedanticHacker

Copy link
Copy Markdown

Please let me get something straight. So this PR proposes to be able to annotate the return type of a class' __init__() with NoReturn rather than None?

So like

class MyExampleClass:
    def __init__(self) -> NoReturn:
        pass

rather than

class MyExampleClass:
    def __init__(self) -> None:
        pass

If that's the case, I am very much welcoming the change. It is more understandable to read that a class' __init__ doesn't return anything (NoReturn) as oppose to read that it returns None (which techically is not true).

@BvB93
BvB93 force-pushed the noreturn branch 2 times, most recently from 42ea2e6 to 47df7ef Compare February 11, 2022 13:59
@BvB93

BvB93 commented Feb 11, 2022

Copy link
Copy Markdown
Contributor Author

Closing and re-opening as no CI runs appear to be starting.

@BvB93 BvB93 closed this Feb 11, 2022
@BvB93 BvB93 reopened this Feb 11, 2022
@BvB93

BvB93 commented Feb 11, 2022 •

Copy link
Copy Markdown
Contributor Author

Closing and re-opening as no CI runs appear to be starting.

Right, that's better. This PR does still need approval after the latest master branch rebase.

Please let me get something straight. So this PR proposes to be able to annotate the return type of a class' init() with NoReturn rather than None?

@PedanticHacker not quite, NoReturn is used as return-annotation for functions that always raise an exception. In the examples you provided None is still the appropriate return type, as python functions without an explicit return statement alwways return None (note that this is actual runtime behavior; not just a convention).

class MyExampleClass:
    def __init__(self) -> NoReturn:
        raise TypeError("Cannot initialize 'MyExampleClass'")

@BvB93

BvB93 commented Feb 21, 2022

Copy link
Copy Markdown
Contributor Author

Rebased to get rid of another merge conflict. For future reference, is there a preference for either rebasing or updating from master when dealing with merge conflicts?

@github-actions

Copy link
Copy Markdown
Contributor

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

steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/commands/converters.py:494: error: "__new__" must return a class instance (got "NoReturn")  [misc]
- steam/ext/commands/commands.py:224: error: The type "Type[Greedy[Any]]" is not generic and not indexable  [misc]
+ steam/ext/commands/commands.py:224: error: Value of type "Callable[[VarArg(Any), KwArg(Any)], NoReturn]" is not indexable  [index]

@JelleZijlstra

Copy link
Copy Markdown
Member

Rebased to get rid of another merge conflict. For future reference, is there a preference for either rebasing or updating from master when dealing with merge conflicts?

Merging is generally preferred. When you force-push, the review history for comments before the force-push gets lost in the UI, making it harder for reviewers to review previous changes.

@hauntsaninja 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.

This looks great! If you fix the merge conflicts and ping me, I will merge :-)

@iyanging

Copy link
Copy Markdown
Contributor

Hi @BvB93 @hauntsaninja, I made another PR which merged master, maybe it's worth to have a look.

@hauntsaninja

Copy link
Copy Markdown
Collaborator

This got merged in #13480

@hauntsaninja

Copy link
Copy Markdown
Collaborator

Thank you BvB93!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allowing typing.NoReturn as a return hint for __init__ methods

7 participants