Re: [ctypes-users] What's the proper way of handling error-checking return values?
Brought to you by:
theller
From: Mike C. F. <mcf...@ro...> - 2005-08-27 17:48:47
|
Thomas Heller wrote: ... >>I'm basically wondering what the proper call on resultType (SOMETHING) >>is to do the same thing as would be done were restype a simple ctypes >>type. The code in GetResult (callproc.c) seems rather involved to >>write in Python, but I'd guess there's some way to trigger it given a >>resultType? >> >> > >I don't think there's a way currently to trigger that behaviour. Even >if you rewrite GetResult in Python, so that checkError can emulate it >after verifying that no error has occurred, checkError cannot access the >'void *result' pointer that callproc's GetResult has. > >The whole 'callable as restype' protocol is flawed, imo. But I fear it >has to stay for backwards compatibility. > > Hmm, that seems to avoid the alternative where we keep, but deprecate, the callable as restype protocol, and add a better protocol for all new-code development. >Why can't you use resultType to check for errors (rhetorical question)? > >Because of the way GetResult uses to contruct the return value, if it is >a ctypes type. GetResult calls the types constructor to create a new >instance [1], without any parameters. Then, it uses memcpy to copy the >result buffer into the new instance and returns it. It has to be done >this way because there is no common protocol in the ctypes types do do >this with method calls. So again, when the instance is created, it >doesn't have access to the functions return value to check for errors >(not your use case, but a common one for windows functions). > > >The only idea that I currently have which would be backward compatible >is to introduce a new 'magic' method that all ctypes types have by >default, let's call it __ctypes_check_retval__ or __ctypes_getresult__. > >callproc's GetResult could the be changed to create a new empty instance >of the result value (without calling __new__ or __init__). Then, memcpy >would be used to transfer the function call result into the instance. >Finally, __ctypes_check_retval__ would be called, probably without any >parameters, to check if the function call has failed or not. The return >value of __ctypes_check_retval__, which would be 'self' by default, >would then be returned from GetResult. __ctypes_check_retval__ would be >free to return something else, or raise an exception. > >Any comments? > > How about an alternate proposal: For the cFunction return-type protocol there shall be two entry points: restype -- a ctypes instance *or* a callable value, required, default c_int errcheck -- a callable instance taking { return-value from restype, the cFunction instance, and the set of argument objects passed into the call }, and checking for errors, optional The advantage here is that we don't need a different "type" of c_int to do error checking for a return value, instead, we assign a property on the function that wants the error checking. This should be completely backward compatible, it simply introduces a new entry point. In psuedo-code it looks like this: result = TraditionalGetResult( ... ) if (function.errcheck): # errcheck raises errors on failure, or can mutate result result = function.errcheck( result, function, arguments ) return result The use of callable values for restype is deprecated, but provided for backward compatability. I'm not sure, is there the potential for the raw copy of memory into result type to get "result" has a failure case? Anyway, that would be no different than the current situation if I'm reading correctly. Why all the extra arguments to errcheck? To allow for proper error-messages and to allow the handlers to be generically coded (i.e. you get a pointer to the cFunction so that you can decide which function it is in which you are checking for errors). In short, I'd rather see the checking code stored on the cFunction object. I actually have this functionality in the "wrapper" module in OpenGL-ctypes, it's just that I don't want to have to use (the comparatively heavy) wrapper module for *every* OpenGL call. Have fun, Mike -- ________________________________________________ Mike C. Fletcher Designer, VR Plumber, Coder http://www.vrplumber.com http://blog.vrplumber.com |