<div>I have a module which makes use of ctypes to interface to the IBM C-ISAM library under linux. I have created a libpyisam.so library which combines the two official libraries, libifisam.so and libifisamx.so and provides a SONAME for the ctypes module (if that is still required).</div>
<div> </div><div>My main object uses a dictionary in which the keys are the external functions that can be called from the externl library, and the values are initially tuples which define the arguments and return type for the functions. The first time that a function is called, the __getattr__ function locates the function in the library then modifies the return type and arguments according to the tuple stored in the value, this object is then stored in place of the tuple so that subsequent calls simply use the previous object.</div>
<div> </div><div>To check whether the function has been previously converted, I make use of internal objects within the ctypes module, namely, _SimpleCData and _CFuncPtr. Is this a safe thing to do, bearing in mind that the objects are documentated as internal?</div>
<div> </div><div>In order to make the above paragraphs clear, I provide a cutdown version of the object in question with a sample of the functions and the calling convention used. Is there a better way to do this using ctypes:</div>
<div> </div><div>from ctypes import *</div><div> </div><div>class ISAMobject(dict):</div><div>  """</div><div>  The _func dictionary initially consists of:</div><div>    (args,...)                where the return type is c_int and arguments are passed,</div>
<div>    (None,)                 where the return type is c_int but no arguments are passed,</div><div>    (ret,(args,...))        where the return type is not c_int and arguments are passed,</div><div>    (ret,None)             where the return type is not c_int and no arguments are passed,</div>
<div>    None                     where there is no return type and no arguments are passed</div><div>  """</div><div>  _func = {</div><div>    'isbegin'  : (None,),</div><div>    'iscluster' : (c_int, byref(keydesc)),</div>
<div>    'islangchk' : None,</div><div>    'islanginfo' : (c_char_p, (c_char_p,))</div><div>  }</div><div> </div><div>  _const = {</div><div>    'iserrno' : c_int,</div><div>    'iscopyright' : c_char_p</div>
<div>  }</div><div> </div><div>  _lib = cdll.LoadLibrary('./libpyisam.so')</div><div> </div><div>  def __getattr__(self, name):</div><div>    func_info = self._func.get(name, 'NONE')</div><div>    if func_info == 'NONE':</div>
<div>       const_info = self._const.get(name, 'NONE')</div><div>       if const_info == 'NONE':</div><div>          raise AttributeError('Underlying ISAM library does not have %s attribute' % name)</div>
<div>       if not isinstance(const_info, ctypes._SimpleCData):</div><div>          const_info = const_info.in_dll(self._lib, name)</div><div>          self._const[name] = const_info</div><div>       return const_info.value if hasattr(const_info, 'value') else const_info</div>
<div>    elif not instance(func_info, ctypes._CFuncPtr):</div><div>       real_func = getattr(self._lib, name)</div><div>       if real_func is None:</div><div>          raise AttributeError('Underlying ISAM library does not support %s function' % name)</div>
<div>       if func_info is None:</div><div>          real_func.restype = real.argtypes = None</div><div>       elif isinstance(func_info, list):</div><div>          real_func.restype, real_func.argtypes = func_info</div>
<div>       elif len(func_info) > 1 and isinstance(func_info[1], tuple):</div><div>          real_func.restype, real_func.argtypes = func_info</div><div>       elif isinstance(func_info, tuple):</div><div>          real_func.argtypes = func_info</div>
<div>       else:</div><div>          real_func.restype = func_info</div><div>       self._func[name] = func_info = real_func</div><div>    return func_info</div><div> </div><div>Thank you in advance,</div><div>Richard Moseley</div>