[Python-ideas] Conventions for Function Annotations

Mathias Panzenböck grosser.meister.morti at gmx.net
Sun Aug 7 17:31:10 CEST 2011


On 08/07/2011 01:27 PM, dag.odenhall at gmail.com wrote:
> This isn't really a proposal for any sort of language/stdlib change,
> rather I felt like discussing the potential for informal standard
> conventions with annotations.
>
> Probably for the better, there is no special syntax for annotating
> raised exceptions or yields from a generator. In line with how the
> "->" syntax sets the 'return' key, I suggest an informal standard of
> representing keywords this way, for example in a decorator for
> raise/yield annotations:
>
> # third-party decorator
> @raises(ValueError)
> def foo():pass
>
> assert foo.__annotations__['raise'] == ValueError
>

I wrote something using the foo.__annotations__ convention a while back, but it wasn't received well 
on this mailinglist. Here it is again now with an added `annotations` decorator:

"""
 >>> @annotation
 >>> def raises(*exceptions):
 >>> 	return exceptions
 >>>
 >>> @raises(TypeError)
 >>> def foo():
 >>> 	pass
 >>>
 >>> getannot(foo,'raises')
(<type 'exceptions.TypeError'>,)
 >>>
"""

from functools import wraps

def annotations(**annots):
	def deco(obj):
		if hasattr(obj,'__annotations__'):
			obj.__annotations__.update(annots)
		else:
			obj.__annotations__ = annots
		return obj
	return deco

_NONE = object()
def getannot(obj, key, default=_NONE):
	if hasattr(obj, '__annotations__'):
		if default is _NONE:
			return obj.__annotations__[key]
		else:
			return obj.__annotations__.get(key, default)
	elif default is _NONE:
		raise KeyError(key)
	else:
		return default

def setannot(obj, key, value):
	if hasattr(obj, '__annotations__'):
		obj.__annotations__[key] = value
	else:
		obj.__annotations__ = {key: value}

def hasannot(obj, key):
	if hasattr(obj, '__annotations__'):
		return key in obj.__annotations__
	else:
		return False

def annotation(annotfunc):
	if hasattr(annotfunc, '__name__'):
		key = annotfunc.__name__
	else:
		key = annotfunc.func_name
	
	@wraps(annotfunc)
	def params(*args,**kwargs):
		def deco(obj):
			setannot(obj, key, annotfunc(*args,**kwargs))
			return obj
		return deco
	return params



More information about the Python-ideas mailing list