<br>I thought I'd let you know that I succeeded in my experiment in calling Clean from Python. Assuming you've already compiled a Clean dll with a function 'factors' in it, the code ends up looking like this:
<br><br><div style="margin-left: 40px;"># Load the dll and specify the types for our function<br>>>> from cleantypes import cdll, Int, IntArray<br>>>> dll = cdll.LoadLibrary("test_python")<br>>>>
dll.factors.argtypes = [Int]<br>>>> dll.factors.restype = IntArray<br><br># From now on we can call our function like this<br>>>> dll.factors(60)<br>[2, 2, 3, 5]<br></div><br>I expect that the code could be improved on quite a bit, but I'll go ahead and post it here; it should be a good starting point for anyone else who wants to pursue this just in case I don't do anymore with this.
<br clear="all"><br>-- <br><br>//=][=\\<br><br><a href="mailto:tim.hochberg@ieee.org">tim.hochberg@ieee.org</a><br><br>##############################################################################################<br><br>
"""cleantypes<br><br>This module provides a set of types for calling functions defined in the functional<br>languge Clean using ctypes. <br><br>Note that you will need a corresponding Clean Dll to get these doctests to work
<br><br>>>> dll = cdll.LoadLibrary("test_python")<br><br>>>> dll.stringlen.argtypes = [String]<br>>>> dll.stringlen.restype = Int<br><br>>>> dll.factors.argtypes = [Int]<br>>>>
dll.factors.restype = IntArray<br><br>>>> dll.arrayinverse.argtypes = [RealArray]<br>>>> dll.arrayinverse.restype = RealArray<br><br>>>> dll.repeatstring.argtypes = [String, Int]<br>>>>
dll.repeatstring.restype = String<br><br>>>> dll.intarraysum.argtypes = [IntArray, IntArray]<br>>>> dll.intarraysum.restype = IntArray<br><br>>>> dll.modify.argtypes = [IntArray]<br>>>>
dll.modify.restype = IntArray<br><br>>>> dll.stringlen("12345")<br>5<br>>>> dll.factors(12)<br>[2, 2, 3]<br>>>> dll.arrayinverse([1,2,4,8])<br>[1.0, 0.5, 0.25, 0.125]<br>>>> dll.repeatstring
("foo", 3)<br>'foofoofoo'<br>>>> dll.intarraysum([1,2,3], [4,5,6])<br>[5, 7, 9]<br><br>"""<br><br>from ctypes import cdll<br>from ctypes import POINTER as _POINTER, cast as _cast, sizeof as _sizeof
<br>from ctypes import c_int as Int, c_double as Real, c_char as _char<br>from ctypes import create_string_buffer as _buffer, addressof as _addressof<br><br>class _Sequence(object):<br> @classmethod<br> def _create(cls, value):
<br> length = _cast(value, _POINTER(Int))[-cls.offset // _sizeof(Int)]<br> data = _cast(value, _POINTER(cls.kind))<br> shift = (cls.preamb - cls.offset) // _sizeof(cls.kind)<br> return data[shift:shift+length]
<br> @classmethod<br> def from_param(cls, value):<br> if isinstance(value, cls.source):<br> length = len(value)<br> rawdata = _buffer(_sizeof(cls.kind) * len(value) + cls.preamb)<br> _cast(rawdata, _POINTER(Int))[0] = length
<br> data = _cast(rawdata, _POINTER(cls.kind))<br> shift = cls.preamb // _sizeof(cls.kind)<br> for i, x in enumerate(value):<br> data[i + shift] = x<br> return _cast(_addressof(
data.contents) + cls.offset, _POINTER(cls.kind))<br> elif isinstance(value, _POINTER(cls.kind)):<br> return value<br> else:<br> raise TypeError("can't convert object of type <%s> to type <%s>" %
<br> (type(value).__name__, cls.__name__))<br><br>class _Array(list, _Sequence):<br> source = list<br> preamb = 8<br> offset = 8<br> def __init__(self, value):<br> list.__init__(self, self._create(value))
<br> <br>class RealArray(_Array):<br> kind = Real<br> <br>class IntArray(_Array):<br> kind = Int<br> <br>class CharArray(_Array):<br> kind = _char<br> preamb = 4<br> offset = 4<br> <br>class String(str, _Sequence):
<br> source = str<br> kind = _char<br> preamb = 4<br> offset = 0<br> def __new__(cls, value):<br> return str.__new__(cls, cls._create(value))<br><br><br>if __name__ == "__main__":<br> import doctest, cleantypes
<br> doctest.testmod(cleantypes)<br><br><br><br><br>