Commits

Maciej Fijalkowski committed 25763c3

some basics (leaking)

  • Participants
  • Parent commits 4450bb2

Comments (0)

Files changed (5)

File pypyembed/emb.c

   Py_INCREF(Py_None);
   return Py_None;
 }
+
+int _Py_get_file_input()
+{
+  return Py_file_input;
+}
+

File pypyembed/embed.py

 
-from ctypes import py_object, addressof, CDLL, c_long, c_char_p, c_int
-import inspect
+from ctypes import py_object, addressof, CDLL, c_long, c_char_p, c_int,\
+     POINTER, cast, c_char
+import inspect, numpy
 
 pypy = CDLL('./libpypy-c.so')
 pypy_main_startup = pypy.pypy_main_startup
 pypy_prepare_function.argtypes = [c_long, c_char_p]
 pypy_prepare_function.restype = None
 pypy_call_function = pypy.pypy_call_function
-pypy_call_function.argtypes = [c_char_p, c_long, py_object * 2]
+pypy_call_function.argtypes = [c_char_p, c_long, POINTER(py_object)]
 pypy_call_function.restype = py_object
 
 pypy_main_startup(3, (c_char_p * 3)("pypy-c", "-c", "pass"))
 
 pypy_prepare_function(0, open('inner.py').read())
 
+def wrap(arg):
+    if not isinstance(arg, numpy.ndarray):
+        return arg
+    return (arg.__array_interface__['data'][0], str(arg.dtype), arg.shape)
+
+def product(t):
+    s = 1
+    for i in t:
+        s *= i
+    return s
+
 def export_function(func):
     src = ['@cross_call\n'] + inspect.getsource(func).splitlines()[1:]
     pypy_prepare_function(0, "\n".join(src))
     def f(*args):
         lgt = len(args)
-        args = (py_object * lgt)(*args)
-        return pypy_call_function(func.func_name, lgt, args)
+        args = (py_object * lgt)(*[wrap(arg) for arg in args])
+        res = pypy_call_function(func.func_name, lgt, cast(args,
+                                                           POINTER(py_object)))
+        if isinstance(res, tuple):
+            size = res[2]
+            dtype = numpy.dtype(res[1])
+            raw_size = product(size)
+            buffer = (c_char*raw_size*dtype.itemsize).from_address(res[0])
+            return numpy.ndarray(size, dtype, buffer=buffer)
+        return res
     f.func_name = func.func_name
     return f

File pypyembed/example.py

 @export_function
 def f(a, b):
     return a + b
+
+@export_function
+def returning_numarray(size):
+    import numpy
+    return numpy.arange(size)
+
+print returning_numarray(100)

File pypyembed/inner.py

                                      [PY_OBJECT, ctypes.c_char_p], PY_OBJECT)
     PyObject_Call = declare('PyObject_Call', [PY_OBJECT, PY_OBJECT, PY_OBJECT],
                             PY_OBJECT)
-    PyTuple_New = declare('PyTuple_New', [ctypes.c_int], PY_OBJECT)
-    PyTuple_SetItem = declare('PyTuple_SetItem', [PY_OBJECT, ctypes.c_int,
-                                                  PY_OBJECT], ctypes.c_int,
+    PyTuple_New = declare('PyTuple_New', [ctypes.c_long], PY_OBJECT)
+    PyTuple_SetItem = declare('PyTuple_SetItem', [PY_OBJECT, ctypes.c_long,
+                                                  PY_OBJECT], ctypes.c_long,
                               errcond=-1)
     Py_CompileStringFlags = declare('Py_CompileStringFlags',
          [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int, PY_OBJECT], PY_OBJECT)
     PyFloat_AsDouble = declare('PyFloat_AsDouble', [PY_OBJECT], ctypes.c_double)
     PyFloat_FromDouble = declare('PyFloat_FromDouble', [ctypes.c_double],
                                  PY_OBJECT)
-    Py_file_input = 257 # XXX
+    _Py_get_file_input = declare_extra('_Py_get_file_input', [],
+                                       ctypes.c_int)
+    Py_file_input = _Py_get_file_input()
     PyEval_EvalCode = declare('PyEval_EvalCode', [PY_OBJECT] * 3, PY_OBJECT)
     PyDict_SetItemString = declare('PyDict_SetItemString',
                                    [PY_OBJECT, ctypes.c_char_p, PY_OBJECT],
     PyEval_GetBuiltins = declare('PyEval_GetBuiltins', [], PY_OBJECT)
     PyString_Check = declare_extra('_PyString_Check', [PY_OBJECT], ctypes.c_bool)
     Py_GetNone = declare_extra('_Py_GetNone', [], PY_OBJECT)
+    PyBool_FromLong = declare('PyBool_FromLong', [ctypes.c_long], PY_OBJECT)
 
-    class WrappedObject(object):
-        def __init__(self, pyobj, unwrap=True):
-            self.pyobj = pyobj
-            self.unwrap = unwrap
-
-        def __call__(self, *args):
-            py_args = PyTuple_New(len(args))
-            for i, arg in enumerate(args):
-                PyTuple_SetItem(py_args, i, wrap(arg))
-            py_res = PyObject_Call(self.pyobj, py_args, None)
-            Py_DECREF(py_args)
-            if not self.unwrap:
-                return py_res
-            res = unwrap(py_res)
-            Py_DECREF(py_res)
-            return res
-
-        def __del__(self):
-            Py_DECREF(self.pyobj)
-
-    def applevel(code, unwrap=False):
-        code = "\n".join(["  " + line for line in code.split("\n") if line])
-        code = "def anonymous():\n" + code
-        py_code = Py_CompileStringFlags(code, 'exec', Py_file_input, None)
-        Py_INCREF(py_code)
-        py_elem = PyObject_GetAttrString(py_code, 'co_consts')
-        Py_INCREF(py_elem)
-        py_zero = PyInt_FromLong(0)
-        py_item = PyObject_GetItem(py_elem, py_zero)
-        Py_DECREF(py_zero)
-        py_locals = PyDict_New()
-        py_globals = PyDict_New()
-        py_bltns = PyEval_GetBuiltins()
-        PyDict_SetItemString(py_globals, "__builtins__", py_bltns)
-        py_res = PyEval_EvalCode(py_item, py_globals, py_locals)
-        Py_DECREF(py_locals)
-        Py_DECREF(py_globals)
-        Py_DECREF(py_code)
-        return WrappedObject(py_res, unwrap=unwrap)
-
-    # XXX size is incorrent (and why do we care?)
-    #convert_numpy_arr = applevel('''
-    #def convert(i, size, dtype):
-    #    import ctypes
-    #    import numpy
-    #    return numpy.ndarray([size], dtype=dtype, buffer=(ctypes.c_char*size*ctypes.sizeof(ctypes.c_long)).from_address(i))
-    #return convert
-    #''')
+    global_arrays = []
 
     def wrap(x):
         if isinstance(x, int):
         elif isinstance(x, float):
             return PyFloat_FromDouble(x)
         elif isinstance(x, numpypy.ndarray):
-            i = x.__array_interface__['data'][0]
-            # HAAAACK
-            if 'int64' in str(x.dtype):
-                dtype = 'i8'
-            else:
-                dtype = 'f8'
-            return convert_numpy_arr(i, x.shape[0], dtype)
+            data = x.__array_interface__['data'][0]
+            # XXX implement refcounts
+            global_arrays.append(x)
+            item = PyInt_FromLong(data)
+            res = PyTuple_New(3)
+            PyTuple_SetItem(res, 0, item)
+            PyTuple_SetItem(res, 1, PyString_FromString(str(x.dtype)))
+            shape = PyTuple_New(len(x.shape))
+            for i in range(len(x.shape)):
+                PyTuple_SetItem(shape, i, PyInt_FromLong(x.shape[i]))
+            PyTuple_SetItem(res, 2, shape)
+            return res
         else:
             raise NotImplementedError(x)
 
             raise NotImplementedError("unknown type")
         return res
 
-    class WrappedModule(object):
-        def __init__(self, pymod):
-            self.pymod = pymod
-
-        def __getattr__(self, name):
-            py_func_obj = PyObject_GetAttrString(self.pymod, name)
-            return WrappedObject(py_func_obj)
-
-
-    def import_mod(modname):
-        py_modname = PyString_FromString(modname)
-        try:
-            mod = PyImport_Import(py_modname)
-            return WrappedModule(mod)
-        finally:
-            Py_DECREF(py_modname)
-
     def cross_call(func):
         def wrapped(*args):
             try:
                 return Py_GetNone()
         return wrapped
 
-    def main():
-        pass
-        #modname = PyString_FromString('matplotlib')
-        #a = numpypy.arange(200, dtype=int)
-        #p = a.__array_interface__['data'][0]
-        #Py_DECREF(modname)
-        #Py_CompileStringFlags
-
 except Exception, e:
     traceback.print_tb(sys.exc_info()[2])
     print e

File pypyembed/test/test_example.py

 def test_basics():
     assert adder(1, 2) == 3
     assert adder(1.2, 3.4) == 4.6
+
+@export_function
+def returning_numarray(size):
+    import numpy
+    return numpy.arange(size)
+
+def test_returning_numarray():
+    assert returning_numarray(100)[13] == 13
+
+@export_function
+def returning_numarray_multidim(a, b):
+    import numpy
+    return numpy.arange(a * b).reshape(a, b)
+
+def test_returning_numarray_multidim():
+    assert (returning_numarray_multidim(2, 5)[1] == [5, 6, 7, 8, 9]).all()
+