[clean-list] Calling Clean from Python

Timothy Hochberg tim.hochberg at ieee.org
Tue Mar 6 17:51:10 MET 2007


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:

# Load the dll and specify the types for our function
>>> from cleantypes import cdll, Int, IntArray
>>> dll = cdll.LoadLibrary("test_python")
>>> dll.factors.argtypes = [Int]
>>> dll.factors.restype = IntArray

# From now on we can call our function like this
>>> dll.factors(60)
[2, 2, 3, 5]

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.

-- 

//=][=\\

tim.hochberg at ieee.org

##############################################################################################

"""cleantypes

This module provides a set of types for calling functions defined in the
functional
languge Clean using ctypes.

Note that you will need a corresponding Clean Dll to get these doctests to
work

>>> dll = cdll.LoadLibrary("test_python")

>>> dll.stringlen.argtypes = [String]
>>> dll.stringlen.restype = Int

>>> dll.factors.argtypes = [Int]
>>> dll.factors.restype = IntArray

>>> dll.arrayinverse.argtypes = [RealArray]
>>> dll.arrayinverse.restype = RealArray

>>> dll.repeatstring.argtypes = [String, Int]
>>> dll.repeatstring.restype = String

>>> dll.intarraysum.argtypes = [IntArray, IntArray]
>>> dll.intarraysum.restype = IntArray

>>> dll.modify.argtypes = [IntArray]
>>> dll.modify.restype = IntArray

>>> dll.stringlen("12345")
5
>>> dll.factors(12)
[2, 2, 3]
>>> dll.arrayinverse([1,2,4,8])
[1.0, 0.5, 0.25, 0.125]
>>> dll.repeatstring("foo", 3)
'foofoofoo'
>>> dll.intarraysum([1,2,3], [4,5,6])
[5, 7, 9]

"""

from ctypes import cdll
from ctypes import POINTER as _POINTER, cast as _cast, sizeof as _sizeof
from ctypes import c_int as Int, c_double as Real, c_char as _char
from ctypes import create_string_buffer as _buffer, addressof as _addressof

class _Sequence(object):
    @classmethod
    def _create(cls, value):
        length = _cast(value, _POINTER(Int))[-cls.offset // _sizeof(Int)]
        data = _cast(value, _POINTER(cls.kind))
        shift = (cls.preamb - cls.offset) // _sizeof(cls.kind)
        return data[shift:shift+length]
    @classmethod
    def from_param(cls, value):
        if isinstance(value, cls.source):
            length = len(value)
            rawdata = _buffer(_sizeof(cls.kind) * len(value) + cls.preamb)
            _cast(rawdata, _POINTER(Int))[0] = length
            data = _cast(rawdata, _POINTER(cls.kind))
            shift = cls.preamb // _sizeof(cls.kind)
            for i, x in enumerate(value):
                data[i + shift] = x
            return _cast(_addressof(data.contents) + cls.offset, _POINTER(
cls.kind))
        elif isinstance(value,  _POINTER(cls.kind)):
            return value
        else:
            raise TypeError("can't convert object of type <%s> to type <%s>"
%
                                        (type(value).__name__,
cls.__name__))

class _Array(list, _Sequence):
    source = list
    preamb = 8
    offset = 8
    def __init__(self, value):
        list.__init__(self, self._create(value))

class RealArray(_Array):
    kind = Real

class IntArray(_Array):
    kind = Int

class CharArray(_Array):
    kind = _char
    preamb = 4
    offset = 4

class String(str, _Sequence):
    source = str
    kind = _char
    preamb = 4
    offset = 0
    def __new__(cls, value):
        return str.__new__(cls, cls._create(value))


if __name__ == "__main__":
    import doctest, cleantypes
    doctest.testmod(cleantypes)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mailman.science.ru.nl/pipermail/clean-list/attachments/20070306/7f54f5f8/attachment.html


More information about the clean-list mailing list