interface boilerplate

Michael Spencer mahs at telcopartners.com
Mon Oct 18 13:07:06 EDT 2004


John Hunter wrote:
> In matplotlib, a plotting library with an OO API and a matlab-like
> procedural interface, I have a lot of functions defined in the matlab
> interface module that wrap similarly named class methods defined in
> the Axes class of the axes module.  Eg, the Axes class defines a plot
> method and the matlab interface defines a plot function that gets the
> current Axes instance, calls the plot method on that instance, and
> does some error handling.  Here is the matlab interface wrapper (gca()
> returns the current Axes instance)
> 
> def plot(*args, **kwargs):
>     try:
>         ret =  gca().plot(*args, **kwargs)
>     except ValueError, msg:
>         msg = raise_msg_to_str(msg)
>         error_msg(msg)
>     else:
>         draw_if_interactive()
>         return ret
> plot.__doc__ = Axes.plot.__doc__
> 
> This is mostly boilerplate code that a lot of matlab interface
> functions use, and I'd like to automatically generate it.
> 
> This appears to (mostly) work
> 
> def _wrap_axfunc(name):
>     def wrapper(*args, **kwargs):
>         try:
>             func = getattr(gca(), name)
>             ret =  func(*args, **kwargs)
>         except ValueError, msg:
>             msg = raise_msg_to_str(msg)
>             error_msg(msg)
>         else:
>             draw_if_interactive()
>             return ret
>     wrapper.__doc__ = getattr(Axes, name).__doc__
>     #wrapper.__name__ = name
>     return wrapper
> 
> plot = _wrap_axfunc('plot')
> 
> The only problem I've seen so far is that the name of the function in
> pydoc string is 'wrapper', and I want it to appear as "plot".  I tried
> setting the __name__ attribute, but it is read only.
> 
> Any suggestions on how to best define these matlab interface functions
> by automatically wrapping the Axes instance functions?  I'd like to
> support python2.2 so python2.2 compliant solutions especially welcome.
> 
> JDH

John

The following descriptor-based delegation does not directly address your 
question, but perhaps the idea is applicable.  In any case, I'm curious 
to get reactions to the approach. It may be well-known, but I haven't 
seen a discussion of it in this group.

#Used on 2.3.3, but I think valid on 2.2+

class Delegate(object):
     """A descriptor that converts calls on obj, to calls on obj._data"""
     def __init__(self, attr):
         self.attr = attr
     def __get__(self,obj,objtype = None):
         return getattr(obj._data,self.attr) #Key step is here

#Example: wrap a subset of dict to get a read-only dict

class fdict(object):
     """Frozen Dictionary.  Read only after init"""
     def __init__(self,*args,**kw):
         self._data = dict(*args,**kw)
     def __repr__(self):
         return "f"+repr(self._data)

"""Example - dict methods for read-only"""
fdictmethods = ['__cmp__', '__contains__', '__eq__', '__ge__', 
'__getitem__','__gt__', '__iter__', '__le__', '__len__', '__lt__', 
'__ne__','__reduce__','__reduce_ex__', '__str__', 'copy' , 'get',
'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues','keys','values']

"""Add each method as an auto-delegating descriptor"""
for attr in fdictmethods:
     setattr(fdict,attr,Delegate(attr))


I like this because it's easy to automate, generates the the wrapper at 
compile-time, and preserves the argspec of the wrapped functions

Michael




More information about the Python-list mailing list