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