PEP 484: When will we have syntax for Exceptions?

No syntax for listing explicitly raised exceptions is proposed.
Currently the only known use case for this feature is documentational,
in which case the recommendation is to put this information in a
docstring.

Even the simplest syntax, like in Rust, would be helpful.
Example:

def some_example() -> Result[str, Exception]:...

If there are Optional, why not?

Although the approach to exceptions in python is closer to Java and more logical is a syntax like throwing. In that case something like:

def some_example() -> Raising[Excaptin1, Excaptin2] & str: ...

Is it worth waiting for it at all?

3 Likes

Search this forum for other times people have asked for this feature; the same arguments still apply. Here’s one thread to start you off:

In short: This is a “gotcha” idea that has been rejected many times by many languages. It may seem useful on the face of it, but it is actually a bad feature to have.

4 Likes

I have read the main arguments in the suggested thread.

I understand that this is a false sense of safety. But such a syntax (not the one I suggested, but a more appropriate one) would make the code more self-documenting.
A possible use case: documenting in fastapi, etc.

Read the entire thread. It’s not “a false sense of security”, it’s that the feature actually doesn’t work.

2 Likes

Can we please stop trying to turn exceptions into a bad-performance version of return values?

Can you explain what you mean by that?
The exception is just a turn of the stack, please note that it is almost the same return, only with a hidden and in-intuitive action.

If every function call has to be wrapped in a try/except, exceptions are no advantage over return codes. Every function could be defined to return a tuple of either (True, return value) or (False, error) and every call MUST check the return value. There are languages that are built this way, and they succeed because they don’t have the additional overhead of exception management. Requiring a try/except would be as bad as removing exceptions from the language altogether, but still paying the cost. It’s the worst of both worlds.

3 Likes

Apparently my idea is misunderstood or explained.
I’m not suggesting to change the python API, and I’m not suggesting to redo anything. I’m just proposing to use it for annotation. It has no real effect on error handling and python Exceptions approach.

Something like:

from typing import Raising

def some_example() -> Raising[Exception, IOError] & str:
    input("Enter something: ")
    
    return "some example"

The Rust approach is the Rust approach, and Python is already designed differently. Java is Java.
At this point in PEP 484 there is no way to simply annotate errors. It can be fixed this way.

I was simply explaining what you were unclear on from the original thread, and what it would mean for exceptions to become nothing more than a lower-performance version of tuple returns in that way.

The idea is still a bad one for all the reasons given in the original thread. “It can be fixed” is not true because the lack of checked exceptions is not a problem to be solved. If you think otherwise, respond to ALL of the arguments from that thread.

1 Like

IOError is a subclass of Exception, so all you’re really saying here is that this could raise Exception, which is nearly useless. It’s also wrong, since this function could easily raise KeyboardInterrupt, which isn’t a subclass of Exception. To be correct, you would have to annotate this as being able to raise BaseException, which is completely useless - every function can raise some subclass of BaseException.

You have gained zero information and only added unnecessary boilerplate to your functions.

5 Likes

You might be interested in

That’s cool, but that’s not what I meant. Within a week I’ll make a clearer explanation of my idea.

Just make sure you carefully read the ideas proposed in similar threads (I think at least two other were created in the last six months) and be ready to drop it if you find that your idea is essentially the same

Okay. I see no point in responding to the thesis described in that article, because Aaron Moore’s idea differed from mine at least in his desire to annotate to make it easier to find errors.

I will clarify my idea.
As you know, there is no syntax for describing errors. That doesn’t make any problem. Error annotation can just be good syntax for libraries. Here is a very simple example for a pseudo-library:

from pseudoapi import APIRouter, HTTPError404, HTTPError500
from random import randint
from repositories import test_repo, SmthException
from typing import Raises


router = APIRouter()

@router.get("/test/{tid}")
async def text(tid: str) -> Raises[HTTPError404, HTTPError500] & dict:
    if randint(0, 1) == 0:
        raise HTTPError500("Something went wrong")
    
    try:
        return await test_repo.get_test(tid)
    except SmthException as e:
        raise HTTPError404("Test not found")

Another use case for this is self-documenting code. Yes, this is much more intuitive than docstring.

Sounds ridiculous, in that case, you can just turn off the PC, I assure you, that does not wait even super safe Rust )
If you look at it from the point of view of error handling and making Python more safe – the annotation idea is not the best. But as a handy tool, why not?

“Why not” is not a reason to add a feature to a language. The correct question is “Why?”. What is the advantage of this? We don’t do things just because there’s no reason not to; there needs to be a solid reason for doing it.

And every reason given so far has been answered. So you’ll need to find a new and compelling reason.

1 Like

If you’re interested in doing this purely for documentation, not for type checking, you may be able to use typing.Annotated, something like Annotated[str, Raises(IOError)]. This would be ignored by static type checkers, but could still be useful for readers of the code.

7 Likes

Yes, that’s roughly what I mean. But at the moment there is no such syntax as Raises.

Raises can have its own specific additional syntax, such as Raises[exceptions] ^ returning
But this is cosmetic.

You can use this syntax today if you want; you don’t have to wait for the standard library. The point of Annotated is that you can put whatever you want in there.

Yes, I can make my own personal Raises and put exceptions in it. Something like this:

from typing import Annotated, Self, Type, TypeVar


_T = TypeVar("_T")

class Raises:
    def __init__(self, *exceptions):
        self.exceptions = exceptions
    
    def __class_getitem__(cls, exceptions: tuple[BaseException]) -> 'Raises':
        return Raises(*exceptions)
    
    def __xor__(self, other: Type[_T]) -> Annotated[Type[_T], Self]:
        return Annotated[other, self]


def test() -> Annotated[dict, Raises[ImportError, KeyError]]:
    return {"test": "test"}

def test() -> Raises[ImportError, KeyError] ^ dict:
    return {"test": "test"}

But this would not create a standardized approach for annotating errors. Or Python doesn’t plan to provide a syntax that allows to annotate exceptions?