[Python-3000] Fwd: Conventions for annotation consumers

Ron Adam rrr at ronadam.com
Sun Aug 20 23:01:46 CEST 2006


Paul Prescod wrote:

> I guess I still don't really understand what he's getting at or what the 
> value of @callmeta is in that example. It just seems like extra noise 
> with no value to me...
> 
> Ron: what *precisely* does the @callmeta decorator do? If you can 
> express it in code, so much the better.
> 
>  Paul Prescod
> 


Here's a working example.  @callmeta could be named something else like 
@asserter, @checker, or whatever.  And it should do more checks to avoid 
non callable annotations and to keep from writing over pre existing 
annotations, etc...

As I said this could all be put in a module and it's easy to create new 
assert tests without having to know about decorators or any special classes.

    Ron



# ----- Some assert test functions.

def IsAny(arg): pass

def IsNumber(arg):
     assert type(arg) in (int, long, float), \
            "%r is not a number" % arg

def IsInt(arg):
     assert type(arg) in (int, long), \
            "%r is not an Int" % arg

def IsFloat(arg):
     assert isinstance(arg, float), \
            "%r is not a flaot" % arg

def InRange(start, stop):
     def inrange(arg):
         assert start <= arg <= stop, \
                "%r is not in range %r through %r" % (arg, start, stop)
     return inrange

def InSet(list_):
     s = set(list_)
     def inset(arg):
         assert arg in s, \
                "%r is not in %r" % (arg, s)
     return inset


# ------- The add-annotation decorator.

def annotate(**kwds):
     def setter(func):
         func.__setattr__('__signature__', dict())
         func.__signature__['annotations'] = kwds
         return func
     return setter


# ------ The do-asserts decorator.

def callmeta(f):
     def new_f(*args, **kwds):
         d = dict(zip(f.func_code.co_varnames, args))
         d.update(kwds)
         tests = f.__signature__['annotations']
         for key in d:
             if key != 'returns':
                 tests[key](d[key])
         result = f(*args, **kwds)
         if 'returns' in tests:
             tests['returns'](result)
         return result
     new_f.func_name = f.func_name
     return new_f


# --------- Examples of using callable annotations.

@callmeta
@annotate(a=Any, b=IsInt, returns=IsInt)
def add(a, b):
     return a + b

print add(1, 4)

@callmeta
@annotate(a=IsInt, b=IsInt, returns=IsInt)
def add(a, b):
     return a + b

print add(1, 4.1)    # assertion error here.



# which could also be...

"""
@callmeta
def add(a:IsInt, b:IsInt) ->IsInt:
     return a + b
"""




More information about the Python-3000 mailing list