Hi!

To help automatic document generators and static type checkers reason more
about the code, the possible side-effects and raised exceptions could also
be annotated in a standardized way.

I'll let some example code talk on my behalf. Here's a simple decorator for
annotating exceptions:
In [1]: import typing as t

In [2]: def raises(exc: Exception) -> t.Callable:
   ...:     def decorator(fn: t.Callable) -> t.Callable:
   ...:         fn.__annotations__["__raises__"] = exc
   ...:         return fn
   ...:     return decorator
   ...:

In [3]: @raises(ValueError)
   ...: def hello_if_5(x: int) -> None:
   ...:     if x != 5:
   ...:         raise ValueError("number other than 5 given")
   ...:     print("Hello!")
   ...:

In [4]: hello_if_5.__annotations__
Out[4]: {'x': int, 'return': None, '__raises__': ValueError}

In [5]: hello_if_5(1)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-7fb1d79ce3f4> in <module>
----> 1 hello_if_5(1)

<ipython-input-3-1084d197ce1b> in hello_if_5(x)
      2 def hello_if_5(x: int) -> None:
      3     if x != 5:
----> 4         raise ValueError("number other than 5 given")
      5     print("Hello!")
      6

ValueError: number other than 5 given

In [6]: hello_if_5(5)
Hello!

In [7]:

and here's a simple decorator for annotating side-effects:

In [1]: import typing as t

In [2]: def side_effect(has_side_effect: bool) -> t.Callable:
   ...:     def decorator(fn: t.Callable) -> t.Callable:
   ...:         fn.__annotations__["__side_effect__"] = has_side_effect
   ...:         return fn
   ...:     return decorator
   ...:

In [3]: a = 10

In [4]: @side_effect(True)
   ...: def change_a(val: int) -> None:
   ...:     global a
   ...:     a = val
   ...:

In [5]: change_a.__annotations__
Out[5]: {'val': int, 'return': None, '__side_effect__': True}

In [6]: change_a(100)

In [7]: a
Out[7]: 100

In [8]: @side_effect(True)
   ...: def mutate_list(items: t.List) -> None:
   ...:     items.append("new item")
   ...:

In [9]: mutate_list.__annotations__
Out[9]: {'items': typing.List, 'return': None, '__side_effect__': True}

In [10]: l = ["old item"]

In [11]: mutate_list(l)

In [12]: l
Out[12]: ['old item', 'new item']

In [13]:

The example implementations have some obvious limitations, such as only
allowing one error type. What do you think of the idea in general? Do you
feel this is something that could be included in Python? typing would
probably be a good module to store such decorators, I guess…

Miikka Salminen
miikka.salmi...@gmail.com
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to