Stefan Behnel | 27 Feb 10:59 2015
Picon

[Cython] PEP 448: Additional Unpacking Generalizations

Looks like a nice goody for Cython users, too:

https://www.python.org/dev/peps/pep-0448/

Requires grammar changes, but otherwise could be done with a transform, I
guess, by mapping the unpacking to list/tuple concatenations and dict updates.

Stefan
Raniere Silva | 20 Feb 21:31 2015
Picon

[Cython] ANN: SciPy Latin América 2015 - Call for Proposals

*Call for Proposals*

*SciPy Latin América 2015*, the third annual Scientific Computing with
Python Conference, will be held this *May 20-22* in *Posadas, Misiones,
Argentina*.

SciPy is a community dedicated to the advancement of scientific computing
through open source Python software for mathematics, science, and
engineering. The annual SciPy Conferences allows participants from
academic, commercial, and governmental organizations to showcase their
latest projects, learn from skilled users and developers, and collaborate
on code development.

*Proposals are now being accepted for SciPy Latin América 2015*.

Presentation content can be at a novice, intermediate or advanced level.
Talks will run 30-40 min and hands-on tutorials will run 100-120 min. We
also receive proposal for posters. For more information about the different
types of proposal, see below the "*Different types of Communication*"
section.

*How to Submit?*

   1. Register for an account on http://conf.scipyla.org/user/register
   2. Submit your proposal at http://conf.scipyla.org/activity/propose

*Important Dates*

   - *April 6th*: Talks, poster, tutorial submission deadline.
   - *April 20th*: Notification Talks / Posters / Tutorial accepted.
(Continue reading)

Ulrich Dobramysl | 11 Feb 09:56 2015
Picon
Picon

[Cython] operator() bug in cython

Dear all,

I tried to declare an external c++ class that includes an operator() function in a pxd file. When I then call a class instance, cython generates faulty c++ code. It includes a call to "operator()()", and not a call to the instance object. Here is a minimum working example:

call_operator.pxd:
----
cdef extern from "call_operator.hpp" nogil:
    cdef cppclass OperatorTest:
        int operator()()
----

test_call_operator.pyx:
----
from call_operator cimport OperatorTest
def test():
    cdef OperatorTest t
    t()
----

Running "cython --cplus test_call_operator.pyx" generates the following code for the test() function:

---- (relevant part only)
  /* "test_call_operator.pyx":4
 * def test():
 *     cdef OperatorTest t
 *     t()             # <<<<<<<<<<<<<<
 */
  operator()();  
----
As you can see, the code that is generated is a call to "operator()()" and not "t()" as it should be.

From what I've been able to work out, the problem seems to be that the call to "t()" is treated as a NameNode in ExprNodes.py and not an AttributeNode. However, I don't know enough about Cython's internals to track where exactly this decision is made.

Curiously, this bug isn't always triggered in more complex situations. I had a larger pxd file with multiple external declarations where one class operator() was treated correctly, while others weren't. I haven't been able to find out why this was the case.

Ulrich

<div><div dir="ltr">Dear all,<div><br></div>
<div>I tried to declare an external c++ class that includes an operator() function in a pxd file. When I then call a class instance, cython generates faulty c++ code. It includes a call to "operator()()", and not a call to the instance object. Here is a minimum working example:</div>
<div><br></div>
<div>call_operator.pxd:</div>
<div>----</div>
<div>
<div>cdef extern from "call_operator.hpp" nogil:</div>
<div>&nbsp; &nbsp; cdef cppclass OperatorTest:</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; int operator()()</div>
</div>
<div>----</div>
<div><br></div>
<div>test_call_operator.pyx:</div>
<div>----</div>
<div>
<div>from call_operator cimport OperatorTest</div>
<div>def test():</div>
<div>&nbsp; &nbsp; cdef OperatorTest t</div>
<div>&nbsp; &nbsp; t()</div>
</div>
<div>----</div>
<div><br></div>
<div>Running "cython --cplus test_call_operator.pyx" generates the following code for the test() function:</div>
<div><br></div>
<div>---- (relevant part only)</div>
<div>
<div>&nbsp; /* "test_call_operator.pyx":4</div>
<div>&nbsp;* def test():</div>
<div>&nbsp;* &nbsp; &nbsp; cdef OperatorTest t</div>
<div>&nbsp;* &nbsp; &nbsp; t() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</div>
<div>&nbsp;*/</div>
<div>&nbsp; operator()(); &nbsp;</div>
<div>
<span>----</span><br>
</div>
<div><span>As you can see, the code that is generated is a call to "operator()()" and not "t()" as it should be.</span></div>
<div><br></div>
</div>
<div>From what I've been able to work out, the problem seems to be that the call to "t()" is treated as a NameNode in ExprNodes.py and not an AttributeNode. However, I don't know enough about Cython's internals to track where exactly this decision is made.</div>
<div><br></div>
<div>Curiously, this bug isn't always triggered in more complex situations. I had a larger pxd file with multiple external declarations where one class operator() was treated correctly, while others weren't. I haven't been able to find out why this was the case.</div>
<div><br></div>
<div>Ulrich</div>
<div><br></div>
</div></div>
Richard Hansen | 2 Feb 01:52 2015
Picon

[Cython] [RFC PATCH] add read-only buffer support to typed memoryviews

This patch is a very rough attempt at adding support for read-only
buffer objects to typed memoryviews.  It is incomplete, has bugs, and
is very dirty.  I'm positing it anyway to solicit help in figuring out
the right way to add read-only buffer support.  The 'XXX' comments
mark issues I'm not sure about.

The problem:

The following example function raises an exception when passed a bytes
object or any other read-only buffer object:

    cpdef object printbuf(unsigned char[:] buf):
        chars = [chr(x) for x in buf]
        print(repr(''.join(chars)))

This is what happens:

    $ python -c 'import test; test.printbuf("test\0ing")'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "test.pyx", line 1, in test.printbuf (test.c:1417)
      File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6795)
      File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3341)
    BufferError: Object is not writable.

The exception is raised because the code generated for typed
memoryviews always passes the PyBUF_WRITABLE flag to
PyObject_GetBuffer(), and "test\0ing" is a read-only bytes object.
The bytes class raises an exception when it sees the PyBUF_WRITABLE
flag.

In this example case, there's no need to pass PyBUF_WRITABLE, and if
it wasn't passed then the code would work as expected.

The approach this patch takes is:

  * Never pass PyBUF_WRITABLE to PyObject_GetBuffer() just in case the
    underlying object is read-only.
  * If it turns out that we do need write access to the buffer (e.g.,
    to handle 'buf[0] = x'), then check to see if the Py_buffer
    structure's readonly member is false.  If so, it's safe to write.
    Otherwise, raise a BufferError exception ("read-only object").

This approach is not ideal because it doesn't support copy-on-write
objects or similarly complicated buffer objects, but a better approach
would be a more invasive change.  See the comments I added in
check_buffer_writable().

Feedback would be appreciated.

Thanks,
Richard
---
 Cython/Compiler/ExprNodes.py  | 100 ++++++++++++++++++++++++++++++++++++++++++
 Cython/Compiler/MemoryView.py |  12 ++---
 Cython/Utility/MemoryView.pyx |  14 +++++-
 tests/memoryview/memslice.pyx |  12 ++---
 4 files changed, 124 insertions(+), 14 deletions(-)

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index ac28d03..13017a9 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
 <at>  <at>  -3642,8 +3642,106  <at>  <at>  class IndexNode(ExprNode):
                 self.extra_index_params(code),
                 code.error_goto(self.pos)))

+    def check_buffer_writable(self, code):
+        """Raise BufferError if the Py_buffer struct's readonly flag is set"""
+
+        # XXX This is called from:
+        #   * generate_buffer_setitem_code()
+        #   * generate_memoryviewslice_setslice_code()
+        #   * generate_memoryviewslice_assign_scalar_code()
+        # Are these sufficient?  Is there another function called to
+        # generate code to directly modify a buffer via Cython syntax?
+
+        # XXX is it safe to call self.buffer_entry() multiple times?
+        buffer_entry = self.buffer_entry()
+
+        # XXX is this the right way to check to see if the object
+        # being modified is a memoryview slice object and not some
+        # other object type?
+        if not buffer_entry.type.is_buffer:
+
+            # XXX Currently the PyBUF_WRITABLE flag is never passed
+            # when calling PyObject_GetBuffer() on the underlying
+            # buffer object, so we never asked the buffer object to
+            # provide us with a writable chunk of memory.  Even if the
+            # Py_buffer struct's readonly flag is unset, might it be
+            # inappropriate to write to the buffer since we never
+            # passed PyBUF_WRITABLE?  The Python 3 documentation seems
+            # to imply that this is OK, but it's not entirely clear.
+
+            # XXX This code simply checks to see whether the Py_buffer
+            # view's readonly flag is unset.  This design does not
+            # support copy-on-write or other similarly complicated
+            # buffer objects.
+            #
+            # For example, imagine a class that does copy-on-write.
+            # Suppose there is an instance of that type, and a copy of
+            # it is made.  The copy hasn't been modified yet, so it
+            # shares a buffer with the original object.  If
+            # PyBUF_WRITABLE is not passed to PyObject_GetBuffer(),
+            # the returned Py_buffer simply points to the shared
+            # memory and the readonly flag is set to avoid corrupting
+            # the original object.  If PyBUF_WRITABLE is passed to
+            # PyObject_GetBuffer(), the object makes its own copy of
+            # the memory and the returned Py_buffer points to the
+            # private copy with the readonly flag unset.
+            #
+            # With the current design, writing to the copy in this
+            # scenario would raise a BufferError ("read-only buffer")
+            # even though it is possible to get a writable buffer by
+            # re-calling PyObject_GetBuffer() with PyBUF_WRITABLE.
+            #
+            # An improved design would look like this:
+            #
+            #   * When creating the typed memoryview:
+            #       1. Call PyObject_GetBuffer() to fetch a Py_buffer
+            #          view into the object, but do not pass
+            #          PyBUF_WRITABLE.
+            #       2. Save the Py_buffer view somewhere.
+            #       3. Save the flags that were passed to
+            #          PyObject_GetBuffer().
+            #
+            #   * Whenever write access is required:
+            #       1. If the saved flags do not include
+            #          PyBUF_WRITABLE:
+            #            a. Call PyOjbect_GetBuffer() again, but this
+            #               time include the PyBUF_WRITABLE flag.  If
+            #               this raises a BufferError exception, let
+            #               it propagate.
+            #            b. Call PyBuffer_Release() on the Py_buffer
+            #               view originally saved when the typed
+            #               memoryview was created.
+            #            c. Save the new Py_buffer view.
+            #            d. Save the new flags.
+            #       2. Assert that the Py_buffer view's readonly flag
+            #          is not set
+
+            # XXX is there a better way to get the cname of the
+            # __Pyx_memviewslice variable?
+            if self.is_temp:
+                # buffer_entry.cname is None in this case, so we have
+                # to get the name of the variable some other way
+                cname = self.temp_code
+            else:
+                cname = buffer_entry.cname
+            assert cname is not None
+
+            # XXX is this the right way to test if the Py_buffer's
+            # readonly flag is set?
+            code.putln('if (unlikely(%s.memview->view.readonly)) {' % (cname,))
+
+            # XXX is this the right way to raise an exception?
+            code.putln('PyErr_Format(PyExc_BufferError, "read-only buffer");')
+            code.putln(code.error_goto(self.pos))
+            code.putln('}')
+        else:
+            # XXX what do we do here?
+            raise NotImplementedError()
+
     def generate_buffer_setitem_code(self, rhs, code, op=""):
         # Used from generate_assignment_code and InPlaceAssignmentNode
+        self.check_buffer_writable(code)
+
         buffer_entry, ptrexpr = self.buffer_lookup_code(code)

         if self.buffer_type.dtype.is_pyobject:
 <at>  <at>  -3834,11 +3932,13  <at>  <at>  class IndexNode(ExprNode):

     def generate_memoryviewslice_setslice_code(self, rhs, code):
         "memslice1[...] = memslice2 or memslice1[:] = memslice2"
+        self.check_buffer_writable(code)
         from . import MemoryView
         MemoryView.copy_broadcast_memview_src_to_dst(rhs, self, code)

     def generate_memoryviewslice_assign_scalar_code(self, rhs, code):
         "memslice1[...] = 0.0 or memslice1[:] = 0.0"
+        self.check_buffer_writable(code)
         from . import MemoryView
         MemoryView.assign_scalar(self, rhs, code)

diff --git a/Cython/Compiler/MemoryView.py b/Cython/Compiler/MemoryView.py
index 8e2f58b..9e75267 100644
--- a/Cython/Compiler/MemoryView.py
+++ b/Cython/Compiler/MemoryView.py
 <at>  <at>  -32,12 +32,12  <at>  <at>  def concat_flags(*flags):

 format_flag = "PyBUF_FORMAT"

-memview_c_contiguous = "(PyBUF_C_CONTIGUOUS | PyBUF_FORMAT | PyBUF_WRITABLE)"
-memview_f_contiguous = "(PyBUF_F_CONTIGUOUS | PyBUF_FORMAT | PyBUF_WRITABLE)"
-memview_any_contiguous = "(PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT | PyBUF_WRITABLE)"
-memview_full_access = "PyBUF_FULL"
-#memview_strided_access = "PyBUF_STRIDED"
-memview_strided_access = "PyBUF_RECORDS"
+memview_c_contiguous = "(PyBUF_C_CONTIGUOUS | PyBUF_FORMAT)"
+memview_f_contiguous = "(PyBUF_F_CONTIGUOUS | PyBUF_FORMAT)"
+memview_any_contiguous = "(PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT)"
+memview_full_access = "PyBUF_FULL_RO"
+#memview_strided_access = "PyBUF_STRIDED_RO"
+memview_strided_access = "PyBUF_RECORDS_RO"

 MEMVIEW_DIRECT = '__Pyx_MEMVIEW_DIRECT'
 MEMVIEW_PTR    = '__Pyx_MEMVIEW_PTR'
diff --git a/Cython/Utility/MemoryView.pyx b/Cython/Utility/MemoryView.pyx
index f7ecd58..4344978 100644
--- a/Cython/Utility/MemoryView.pyx
+++ b/Cython/Utility/MemoryView.pyx
 <at>  <at>  -61,6 +61,7  <at>  <at>  cdef extern from *:
         PyBUF_STRIDES
         PyBUF_INDIRECT
         PyBUF_RECORDS
+        PyBUF_RECORDS_RO

     ctypedef struct __Pyx_TypeInfo:
         pass
 <at>  <at>  -367,6 +368,9  <at>  <at>  cdef class memoryview(object):
             return self.convert_item_to_object(itemp)

     def __setitem__(memoryview self, object index, object value):
+        if self.view.readonly:
+            raise BufferError('read-only buffer')
+
         have_slices, index = _unellipsify(index, self.view.ndim)

         if have_slices:
 <at>  <at>  -466,6 +470,9  <at>  <at>  cdef class memoryview(object):

      <at> cname('getbuffer')
     def __getbuffer__(self, Py_buffer *info, int flags):
+        if (flags & PyBUF_WRITABLE) and self.view.readonly:
+            raise BufferError("read-only buffer")
+
         if flags & PyBUF_STRIDES:
             info.shape = self.view.shape
         else:
 <at>  <at>  -490,7 +497,7  <at>  <at>  cdef class memoryview(object):
         info.ndim = self.view.ndim
         info.itemsize = self.view.itemsize
         info.len = self.view.len
-        info.readonly = 0
+        info.readonly = self.view.readonly
         info.obj = self

     __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
 <at>  <at>  -981,7 +988,10  <at>  <at>  cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
     (<__pyx_buffer *> &result.view).obj = Py_None
     Py_INCREF(Py_None)

-    result.flags = PyBUF_RECORDS
+    if (<memoryview>result.from_slice.memview).flags & PyBUF_WRITABLE:
+        result.flags = PyBUF_RECORDS
+    else:
+        result.flags = PyBUF_RECORDS_RO

     result.view.shape = <Py_ssize_t *> result.from_slice.shape
     result.view.strides = <Py_ssize_t *> result.from_slice.strides
diff --git a/tests/memoryview/memslice.pyx b/tests/memoryview/memslice.pyx
index 417bcbc..62f8782 100644
--- a/tests/memoryview/memslice.pyx
+++ b/tests/memoryview/memslice.pyx
 <at>  <at>  -480,7 +480,7  <at>  <at>  def strided(int[:] buf):
     released A
     2
     >>> [str(x) for x in A.recieved_flags] # Py2/3
-    ['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES']

     Check that the suboffsets were patched back prior to release.
     >>> A.release_ok
 <at>  <at>  -495,7 +495,7  <at>  <at>  def c_contig(int[::1] buf):
     >>> c_contig(A)
     2
     >>> [str(x) for x in A.recieved_flags]
-    ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
     """
     return buf[2]

 <at>  <at>  -508,7 +508,7  <at>  <at>  def c_contig_2d(int[:, ::1] buf):
     >>> c_contig_2d(A)
     7
     >>> [str(x) for x in A.recieved_flags]
-    ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
     """
     return buf[1, 3]

 <at>  <at>  -519,7 +519,7  <at>  <at>  def f_contig(int[::1, :] buf):
     >>> f_contig(A)
     2
     >>> [str(x) for x in A.recieved_flags]
-    ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
     """
     return buf[0, 1]

 <at>  <at>  -532,7 +532,7  <at>  <at>  def f_contig_2d(int[::1, :] buf):
     >>> f_contig_2d(A)
     7
     >>> [str(x) for x in A.recieved_flags]
-    ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
     """
     return buf[3, 1]

 <at>  <at>  -990,7 +990,7  <at>  <at>  def bufdefaults1(int[:] buf):
     acquired A
     released A
     >>> [str(x) for x in A.recieved_flags]
-    ['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
+    ['FORMAT', 'ND', 'STRIDES']
     """
     pass

--

-- 
2.2.2

Michael | 30 Jan 10:49 2015
Picon

[Cython] Compilation failes if a class member is named "INFINITY"

Hello,

if I try to compile the following minimal example:

cdef class Test:

    cdef readonly int INFINITY

cython does not complain but gcc refuses with an error message:
In file included from /usr/include/math.h:38:0,
                 from /usr/include/python2.7/pyport.h:325,
                 from /usr/include/python2.7/Python.h:58,
                 from testinf.c:16:
testinf.c:433:7: error: field '__builtin_inff' declared as a function
   int INFINITY;
       ^
testinf.c: In function '__pyx_pf_7testinf_4Test_8INFINITY___get__':
testinf.c:569:50: error: expected identifier before '(' token
   __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_self->INFINITY); if
(unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 10;
__pyx_clineno = __LINE__; goto __pyx_L1_error;}
                                                  ^
Apparently the name "INFINITY" is handled wrongly; any other variable
name seems to be fine.

Regards,
Michael

Richard Hansen | 27 Jan 23:38 2015
Picon

[Cython] bug in typed memoryviews (memoryviewslice)

Hi all,

If I create foo.pyx with the following contents:

cpdef object foo():
    cdef unsigned char[:] s = <bytearray><unsigned char *>"012345"
    return s

I notice the following behavior:

$ python -c '
import foo
m=foo.foo()
print repr(memoryview(m.base).tobytes())
print repr(memoryview(m).tobytes())
'
'012345'
'123450'

Notice how the bytes are printed in the wrong order unless I use the
original buffer object via the typed memoryview object's base attribute.

-Richard
Apps Embedded | 27 Jan 15:12 2015
Picon

[Cython] IPython with Cython support on Android

Hi,

We have developped an android app which makes it possible to use the IPython shell through Android.

https://play.google.com/store/apps/details?id=com.appsopensource.labpy
https://play.google.com/store/apps/details?id=com.appsopensource.labpypremium

We decided then to add the Cython extension to speed up script execution through the notebook for instance.

Our app bundle is covered by the Gnu GPL v3 licence.
Cython is covered by the Apache Licence version 2.0 which is compatible with the Gnu GPL v3 licence.

Our question concerns the Pyrex licence on which Cython is based. It is on OSI approved licence.

From your point of view, is the Pyrex licence GPL v3 compatible ?

Thanks for your help.

Apps Embedded team.
<div><div dir="ltr">
<div>
<div>
<div>
<div>Hi,<br><br>We have developped an android app which makes it possible to use the IPython shell through Android.<br><br><a href="https://play.google.com/store/apps/details?id=com.appsopensource.labpy">https://play.google.com/store/apps/details?id=com.appsopensource.labpy</a><br><a href="https://play.google.com/store/apps/details?id=com.appsopensource.labpypremium">https://play.google.com/store/apps/details?id=com.appsopensource.labpypremium</a><br><br>
</div>We decided then to add the Cython extension to speed up script execution through the notebook for instance.<br><br>
</div>Our app bundle is covered by the Gnu GPL v3 licence.<br>
</div>Cython is covered by the Apache Licence version 2.0 which is compatible with the Gnu GPL v3 licence.<br><br>Our question concerns the Pyrex licence on which Cython is based.  It is on OSI approved licence. <br><br>From your point of view, is the Pyrex licence GPL v3 compatible ?<br><br>
</div>Thanks for your help.<br><br>Apps Embedded team.<br>
</div></div>
Favian Contreras | 22 Jan 05:14 2015
Picon

[Cython] Variable Step Value

Hey all,

I am having some trouble figuring out how to pass in an extra IfStatNode in Optimize.py, to the code generation stage (see 1st commented block). I am also having trouble getting the temp variable of the iteration variable, so that I can adjust the temp to be the value that would be in index (see the 2nd comment block), before the iteration variable gets set.

As of now I get the correct number of steps, as long as the step value is not 0. I've tried making these fields "StatListNode"s, but that gives a messy error. Any suggestions for how to handle these 2 problems?


Thanks,
Favian Contreras
<div><div dir="ltr">
<div>
<div>
<div>
<div>Hey all,<br><br>
</div>I am having some trouble figuring out how to pass in an extra IfStatNode in Optimize.py, to the code generation stage (see 1st commented block). I am also having trouble getting the temp variable of the iteration variable, so that I can adjust the temp to be the value that would be in index (see the 2nd comment block), before the iteration variable gets set.<br><br>
</div>As of now I get the correct number of steps, as long as the step value is not 0. I've tried making these fields "StatListNode"s, but that gives a messy error. Any suggestions for how to handle these 2 problems?<br><br>
</div>
<div>commit: <a href="https://github.com/BigFav/cython/commit/015440543b051168cb34441a6a8494b6fa5bdd7c">https://github.com/BigFav/cython/commit/015440543b051168cb34441a6a8494b6fa5bdd7c</a><br>
</div>
<div><br></div>Thanks,<br>
</div>Favian Contreras<br>
</div></div>
Robert Bradshaw | 18 Jan 00:10 2015
Picon

[Cython] Cython 0.22.alpha

It's been too long since we've done a release, and the features have
started to pile up, so I'm getting the ball rolling with 0.22.alpha0.
I've uploaded a tarball to
http://cython.org/release/Cython-0.22.alpha0.tar.gz; you can also get
it from github.

Let me know what breaks/works for you, and if there's anything you
think should get in. If feedback is good I'll be cutting a beta (to
the users list) next week.

- Robert
Stefan Behnel | 20 Dec 10:14 2014
Picon

[Cython] GvR on type hinting in Python

Looks like type annotations in Python are about to leave the "maybe one
day" status:

http://thread.gmane.org/gmane.comp.python.ideas/30432

Stefan
Kevin Norris | 20 Dec 01:47 2014
Picon

[Cython] Cythonize silently ignores nonexistent files

Is this behavior intentional?

    >>> from Cython.Build import cythonize
    >>> cythonize('/this/file/doesnt/exist.pyx')
    []

It would be *really* nice if Cython would raise an exception (or
something) in this case.  I just spent 20 minutes trying to puzzle out
Cython/Setuptools compatibility when the actual problem was staring me
in the face.

--
Kevin Norris

Gmane