Skip to content

Instantly share code, notes, and snippets.

@kdcro101
Forked from phaustin/00README.rst
Created December 19, 2020 17:46
Show Gist options
  • Select an option

  • Save kdcro101/a5bda7de7d54e1d3ce2c57518b25b1f2 to your computer and use it in GitHub Desktop.

Select an option

Save kdcro101/a5bda7de7d54e1d3ce2c57518b25b1f2 to your computer and use it in GitHub Desktop.

Revisions

  1. @GaelVaroquaux GaelVaroquaux revised this gist Feb 22, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 00README.rst
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ You will need Cython, numpy, and a C compiler.

    To build the C extension in-place run::

    $ python setup.py build_ext --i
    $ python setup.py build_ext -i


    To test the C-Python bindings, run the `test.py` file.
  2. @GaelVaroquaux GaelVaroquaux revised this gist Jan 5, 2012. 2 changed files with 15 additions and 2 deletions.
    11 changes: 10 additions & 1 deletion cython_wrapper.pyx
    Original file line number Diff line number Diff line change
    @@ -14,6 +14,7 @@ cdef extern from "c_code.c":
    float *compute(int size)

    from libc.stdlib cimport free
    from cpython cimport PyObject, Py_INCREF

    # Import the Python-level symbols of numpy
    import numpy as np
    @@ -70,10 +71,18 @@ def py_compute(int size):
    not copy the data allocated in C.
    """
    cdef float *array
    cdef np.ndarray ndarray
    # Call the C function
    array = compute(size)

    array_wrapper = ArrayWrapper()
    array_wrapper.set_data(size, <void*> array)
    ndarray = np.array(array_wrapper, copy=False)
    # Assign our object to the 'base' of the ndarray object
    ndarray.base = <PyObject*> array_wrapper
    # Increment the reference count, as the above assignement was done in
    # C, and Python does not know that there is this additional reference
    Py_INCREF(array_wrapper)

    return np.array(array_wrapper)

    return ndarray
    6 changes: 5 additions & 1 deletion test.py
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,11 @@
    """
    # Author: Gael Varoquaux
    # License: BSD
    import numpy as np

    import cython_wrapper
    a = cython_wrapper.py_compute(10)
    print a

    print 'The array created is %s' % a
    print 'It carries a reference to our deallocator: %s ' % a.base
    np.testing.assert_allclose(a, np.arange(10))
  3. @GaelVaroquaux GaelVaroquaux revised this gist Dec 8, 2011. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions 00README.rst
    Original file line number Diff line number Diff line change
    @@ -10,10 +10,11 @@ The meat of the example is that the data is allocated in C, but exposed
    in Python without a copy using the `PyArray_SimpleNewFromData` numpy
    function in the Cython file `cython_wrapper.pyx`.

    Note that the ownership of the memory is then handed off to the Python
    VM, and there is no control of when Python will deallocate the memory. If
    the memory is still being used by the C code, please refer to the
    following blog post by Travis Oliphant:
    The purpose of the `ArrayWrapper` object, is to be garbage-collected by
    Python when the ndarray Python object disappear. The memory is then
    freed. Note that there is no control of when Python will deallocate the
    memory. If the memory is still being used by the C code, please refer to
    the following blog post by Travis Oliphant:

    http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory

  4. @GaelVaroquaux GaelVaroquaux revised this gist Dec 8, 2011. 1 changed file with 13 additions and 11 deletions.
    24 changes: 13 additions & 11 deletions cython_wrapper.pyx
    Original file line number Diff line number Diff line change
    @@ -33,33 +33,35 @@ cdef class ArrayWrapper:
    cdef int size

    cdef set_data(self, int size, void* data_ptr):
    """ Constructor for the class.
    """ Set the data of the array
    Mallocs a memory buffer of size (n*sizeof(int)) and sets up
    the numpy array.
    This cannot be done in the constructor as it must recieve C-level
    arguments.
    Parameters:
    -----------
    n -- Length of the array.
    Data attributes:
    ----------------
    data -- Pointer to an integer array.
    alloc -- Size of the data buffer allocated.
    size: int
    Length of the array.
    data_ptr: void*
    Pointer to the data
    """
    self.data_ptr = data_ptr
    self.size = size

    def __array__(self):
    """ Here we use the __array__ method, that is called when numpy
    tries to get an array from the object."""
    cdef np.npy_intp shape[1]
    shape[0] = <np.npy_intp> self.size
    # Create a 1D array, of length 'size'
    ndarray = np.PyArray_SimpleNewFromData(1, shape,
    np.NPY_INT, self.data_ptr)
    np.NPY_INT, self.data_ptr)
    return ndarray

    def __dealloc__(self):
    """ Frees the array. """
    """ Frees the array. This is called by Python when all the
    references to the object are gone. """
    free(<void*>self.data_ptr)


  5. @GaelVaroquaux GaelVaroquaux revised this gist Dec 8, 2011. 2 changed files with 45 additions and 16 deletions.
    58 changes: 43 additions & 15 deletions cython_wrapper.pyx
    Original file line number Diff line number Diff line change
    @@ -13,6 +13,8 @@ http://cython.org for more information
    cdef extern from "c_code.c":
    float *compute(int size)

    from libc.stdlib cimport free

    # Import the Python-level symbols of numpy
    import numpy as np

    @@ -23,6 +25,43 @@ cimport numpy as np
    # _always_ do that, or you will have segfaults
    np.import_array()

    # We need to build an array-wrapper class to deallocate our array when
    # the Python object is deleted.

    cdef class ArrayWrapper:
    cdef void* data_ptr
    cdef int size

    cdef set_data(self, int size, void* data_ptr):
    """ Constructor for the class.
    Mallocs a memory buffer of size (n*sizeof(int)) and sets up
    the numpy array.
    Parameters:
    -----------
    n -- Length of the array.
    Data attributes:
    ----------------
    data -- Pointer to an integer array.
    alloc -- Size of the data buffer allocated.
    """
    self.data_ptr = data_ptr
    self.size = size

    def __array__(self):
    cdef np.npy_intp shape[1]
    shape[0] = <np.npy_intp> self.size
    ndarray = np.PyArray_SimpleNewFromData(1, shape,
    np.NPY_INT, self.data_ptr)
    return ndarray

    def __dealloc__(self):
    """ Frees the array. """
    free(<void*>self.data_ptr)


    def py_compute(int size):
    """ Python binding of the 'compute' function in 'c_code.c' that does
    @@ -32,18 +71,7 @@ def py_compute(int size):
    # Call the C function
    array = compute(size)

    # Create a C array to describe the shape of the ndarray
    cdef np.npy_intp shape[1]
    shape[0] = <np.npy_intp> size

    # Use the PyArray_SimpleNewFromData function from numpy to create a
    # new Python object pointing to the existing data
    ndarray = np.PyArray_SimpleNewFromData(1, shape,
    np.NPY_INT, <void *> array)

    # Tell Python that it can deallocate the memory when the ndarray
    # object gets garbage collected
    # As the OWNDATA flag of an array is read-only in Python, we need to
    # call the C function PyArray_UpdateFlags
    np.PyArray_UpdateFlags(ndarray, ndarray.flags.num | np.NPY_OWNDATA)
    return ndarray
    array_wrapper = ArrayWrapper()
    array_wrapper.set_data(size, <void*> array)

    return np.array(array_wrapper)
    3 changes: 2 additions & 1 deletion test.py
    Original file line number Diff line number Diff line change
    @@ -4,4 +4,5 @@
    # License: BSD

    import cython_wrapper
    print cython_wrapper.py_compute(10)
    a = cython_wrapper.py_compute(10)
    print a
  6. @GaelVaroquaux GaelVaroquaux revised this gist Sep 29, 2011. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions cython_wrapper.pyx
    Original file line number Diff line number Diff line change
    @@ -40,4 +40,10 @@ def py_compute(int size):
    # new Python object pointing to the existing data
    ndarray = np.PyArray_SimpleNewFromData(1, shape,
    np.NPY_INT, <void *> array)

    # Tell Python that it can deallocate the memory when the ndarray
    # object gets garbage collected
    # As the OWNDATA flag of an array is read-only in Python, we need to
    # call the C function PyArray_UpdateFlags
    np.PyArray_UpdateFlags(ndarray, ndarray.flags.num | np.NPY_OWNDATA)
    return ndarray
  7. @GaelVaroquaux GaelVaroquaux revised this gist Sep 28, 2011. 1 changed file with 13 additions and 4 deletions.
    17 changes: 13 additions & 4 deletions 00README.rst
    Original file line number Diff line number Diff line change
    @@ -14,18 +14,27 @@ Note that the ownership of the memory is then handed off to the Python
    VM, and there is no control of when Python will deallocate the memory. If
    the memory is still being used by the C code, please refer to the
    following blog post by Travis Oliphant:
    http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory

    To build it you will need Cython, numpy, and a C compiler.
    http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory

    Run::
    You will need Cython, numpy, and a C compiler.

    To build the C extension in-place run::

    $ python setup.py build_ext --i

    to build the C extension in-place.

    To test the C-Python bindings, run the `test.py` file.

    ================= =========================================================
    Files
    ================= =========================================================
    c_code.c The C code to bind. Knows nothing about Python
    cython_wrapper.c The Cython code implementing the binding
    setup.py The configure/make/install script
    test.py Python code using the C extension
    ================= =========================================================

    ____

    :Author: Gael Varoquaux
  8. @GaelVaroquaux GaelVaroquaux revised this gist Sep 28, 2011. 1 changed file with 32 additions and 0 deletions.
    32 changes: 32 additions & 0 deletions 00README.rst
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    ============================================================================
    Cython example of exposing C-computed arrays in Python without data copies
    ============================================================================

    The goal of this example is to show how an existing C codebase for
    numerical computing (here `c_code.c`) can be wrapped in Cython to be
    exposed in Python.

    The meat of the example is that the data is allocated in C, but exposed
    in Python without a copy using the `PyArray_SimpleNewFromData` numpy
    function in the Cython file `cython_wrapper.pyx`.

    Note that the ownership of the memory is then handed off to the Python
    VM, and there is no control of when Python will deallocate the memory. If
    the memory is still being used by the C code, please refer to the
    following blog post by Travis Oliphant:
    http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory

    To build it you will need Cython, numpy, and a C compiler.

    Run::

    $ python setup.py build_ext --i

    to build the C extension in-place.

    To test the C-Python bindings, run the `test.py` file.

    ____

    :Author: Gael Varoquaux
    :License: BSD
  9. @GaelVaroquaux GaelVaroquaux revised this gist Sep 28, 2011. 3 changed files with 100 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions c_code.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    /* Small C file creating an array to demo C -> Python data passing
    *
    * Author: Gael Varoquaux
    * License: BSD
    */

    #include <stdlib.h>

    float *compute(int size)
    {
    int* array;
    array = malloc(sizeof(int)*size);
    int i;
    for (i=0; i<size; i++)
    {
    array[i] = i;
    }
    return array;
    }

    43 changes: 43 additions & 0 deletions cython_wrapper.pyx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    """ Small Cython file to demonstrate the use of PyArray_SimpleNewFromData
    in Cython to create an array from already allocated memory.
    Cython enables mixing C-level calls and Python-level calls in the same
    file with a Python-like syntax and easy type cohersion. See
    http://cython.org for more information
    """

    # Author: Gael Varoquaux
    # License: BSD

    # Declare the prototype of the C function we are interested in calling
    cdef extern from "c_code.c":
    float *compute(int size)

    # Import the Python-level symbols of numpy
    import numpy as np

    # Import the C-level symbols of numpy
    cimport numpy as np

    # Numpy must be initialized. When using numpy from C or Cython you must
    # _always_ do that, or you will have segfaults
    np.import_array()


    def py_compute(int size):
    """ Python binding of the 'compute' function in 'c_code.c' that does
    not copy the data allocated in C.
    """
    cdef float *array
    # Call the C function
    array = compute(size)

    # Create a C array to describe the shape of the ndarray
    cdef np.npy_intp shape[1]
    shape[0] = <np.npy_intp> size

    # Use the PyArray_SimpleNewFromData function from numpy to create a
    # new Python object pointing to the existing data
    ndarray = np.PyArray_SimpleNewFromData(1, shape,
    np.NPY_INT, <void *> array)
    return ndarray
    37 changes: 37 additions & 0 deletions setup.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    """ Example of building a module with a Cython file. See the distutils
    and numpy distutils documentations for more info:
    http://docs.scipy.org/doc/numpy/reference/distutils.html
    """
    # Author: Gael Varoquaux
    # License: BSD

    import numpy
    from Cython.Distutils import build_ext

    def configuration(parent_package='', top_path=None):
    """ Function used to build our configuration.
    """
    from numpy.distutils.misc_util import Configuration

    # The configuration object that hold information on all the files
    # to be built.
    config = Configuration('', parent_package, top_path)
    config.add_extension('cython_wrapper',
    sources=['cython_wrapper.pyx'],
    # libraries=['m'],
    depends=['c_code.c'],
    include_dirs=[numpy.get_include()])
    return config


    if __name__ == '__main__':
    # Retrieve the parameters of our local configuration
    params = configuration(top_path='').todict()

    # Override the C-extension building so that it knows about '.pyx'
    # Cython files
    params['cmdclass'] = dict(build_ext=build_ext)

    # Call the actual building/packaging function (see distutils docs)
    from numpy.distutils.core import setup
    setup(**params)
  10. @GaelVaroquaux GaelVaroquaux created this gist Sep 28, 2011.
    7 changes: 7 additions & 0 deletions test.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    """ Script to smoke-test our Cython wrappers
    """
    # Author: Gael Varoquaux
    # License: BSD

    import cython_wrapper
    print cython_wrapper.py_compute(10)