logo       

Re: using decorators for api calls: msg#00009

python.ctypes

Subject: Re: using decorators for api calls

Niki Spahiev <niki@xxxxxxxxxx> writes:

> Thomas Heller wrote:
>> I've been playing with Python 2.4 decorators again.
>> I found a solution which lets us write compact code, here are two examples:
>> @ stdcall("user32", nonzero, "FindWindowW", c_wchar_p, c_wchar_p)
>> def FindWindow(classname=None, windowname=None):
>> return _call_(classname, windowname)
>
> I would prefer this empty function to be:
>
> def FindWindow(classname=None, windowname=None):
> "doc"
>
> and such empty code objects to be replaced by FFI call.

I have some code that does this, although it's not nice imo.

The problem is that the decorator must create a function like this for
the above, given only the function object of the FindWindow above:

def somefunc(classname=None, windowname=None):
return _call_(classname, windowname)

My code uses the inspect module to build a source code string containing
the 'somefunc', which is then exec'd, the somefunc function object
retrieved, and some properties like func_code and func_defaults are then
used to create a new function with new.function.

If someone finds an easier way, please speak up - I'll append the code I
have written (this code uses _api_ instead of _call_).

Thomas
--
import new

def _create_func_codestring(func, name):
# given a function object <func>, build the source code for another
# function, having the same argument list, and a function body
# which contains a call to an _api_ function.
# Assuming the <func> has this definition:
# def func(first, second="spam", third=42):
# ....
# a string containing the following code is returned:
# def <name>(first, second="spam", third=42):
# return _api_(first, second, third)
import inspect
args = inspect.getargspec(func)
if args[2]:
raise TypeError, "function argument list cannot contain ** argument"

argnames = args[0]
defaults = args[-1]

if not defaults:
if args[1]:
argnames.append("*%s" % args[1])
argnames = ", ".join(argnames)
return "def %s(%s): return _api_(%s)" % (name, argnames, argnames)

first_list = ", ".join(argnames)

args = argnames[:-len(defaults)]
args.extend( ["%s=%r" % t for t in zip(argnames[-len(defaults):],
defaults)] )
args = ", ".join(args)

return """def %s(%s): return _api_(%s)""" % (name, args, first_list)

def _decorate_with_api_global(func, call_api):
# return a new function derived from <func>, inserting an '_api_'
# symbol into the function globals, which is bound to the
# <call_api> object.
#
# If the body of <func> is empty, a new function body is created,
# which simply calls the _api_ object with all parameters passed to <func>.
if len(func.func_code.co_code) == 4:
code_string = _create_func_codestring(func, func.func_name)
d = {}
exec code_string in d
func = d[func.func_name]
func_globals = {"_api_": call_api}
func_globals.update(func.func_globals)
return new.function(func.func_code,
func_globals,
func.func_name,
func.func_defaults)




-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl


<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise