Commit 0e289608 authored by scoder's avatar scoder Committed by GitHub

Merge branch 'master' into broken_and_redirect_links

parents 6ff0ce3c d460da83
...@@ -70,6 +70,9 @@ Bugs fixed ...@@ -70,6 +70,9 @@ Bugs fixed
generated an invalid C function call to the (non-existent) base type implementation. generated an invalid C function call to the (non-existent) base type implementation.
(Github issue #2309) (Github issue #2309)
* Exception catching based on a non-literal (runtime) tuple could fail to match the
exception. (Github issue #2425)
0.28.3 (2018-05-27) 0.28.3 (2018-05-27)
=================== ===================
...@@ -2180,9 +2183,9 @@ Features added ...@@ -2180,9 +2183,9 @@ Features added
* GDB support. http://docs.cython.org/src/userguide/debugging.html * GDB support. http://docs.cython.org/src/userguide/debugging.html
* A new build system with support for inline distutils directives, correct dependency tracking, and parallel compilation. http://wiki.cython.org/enhancements/distutils_preprocessing * A new build system with support for inline distutils directives, correct dependency tracking, and parallel compilation. https://github.com/cython/cython/wiki/enhancements-distutils_preprocessing
* Support for dynamic compilation at runtime via the new cython.inline function and cython.compile decorator. http://wiki.cython.org/enhancements/inline * Support for dynamic compilation at runtime via the new cython.inline function and cython.compile decorator. https://github.com/cython/cython/wiki/enhancements-inline
* "nogil" blocks are supported when compiling pure Python code by writing "with cython.nogil". * "nogil" blocks are supported when compiling pure Python code by writing "with cython.nogil".
......
...@@ -809,8 +809,7 @@ def create_extension_list(patterns, exclude=None, ctx=None, aliases=None, quiet= ...@@ -809,8 +809,7 @@ def create_extension_list(patterns, exclude=None, ctx=None, aliases=None, quiet=
elif name: elif name:
module_name = name module_name = name
if module_name == 'cython': Utils.raise_error_if_module_name_forbidden(module_name)
raise ValueError('cython is a special module, cannot be used as a module name')
if module_name not in seen: if module_name not in seen:
try: try:
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Cython Scanner - Lexical Definitions # Cython Scanner - Lexical Definitions
# #
from __future__ import absolute_import from __future__ import absolute_import, unicode_literals
raw_prefixes = "rR" raw_prefixes = "rR"
bytes_prefixes = "bB" bytes_prefixes = "bB"
......
...@@ -469,6 +469,8 @@ def run_pipeline(source, options, full_module_name=None, context=None): ...@@ -469,6 +469,8 @@ def run_pipeline(source, options, full_module_name=None, context=None):
abs_path = os.path.abspath(source) abs_path = os.path.abspath(source)
full_module_name = full_module_name or context.extract_module_name(source, options) full_module_name = full_module_name or context.extract_module_name(source, options)
Utils.raise_error_if_module_name_forbidden(full_module_name)
if options.relative_path_in_code_position_comments: if options.relative_path_in_code_position_comments:
rel_path = full_module_name.replace('.', os.sep) + source_ext rel_path = full_module_name.replace('.', os.sep) + source_ext
if not abs_path.endswith(rel_path): if not abs_path.endswith(rel_path):
......
...@@ -3260,9 +3260,6 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, ...@@ -3260,9 +3260,6 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return node return node
if node.type.is_pyobject: if node.type.is_pyobject:
if operator in ('Eq', 'Ne'):
ret_type = PyrexTypes.c_bint_type
else:
ret_type = PyrexTypes.py_object_type ret_type = PyrexTypes.py_object_type
elif node.type is PyrexTypes.c_bint_type and operator in ('Eq', 'Ne'): elif node.type is PyrexTypes.c_bint_type and operator in ('Eq', 'Ne'):
ret_type = PyrexTypes.c_bint_type ret_type = PyrexTypes.c_bint_type
......
...@@ -14,13 +14,15 @@ cdef class Method: ...@@ -14,13 +14,15 @@ cdef class Method:
cdef dict kwargs cdef dict kwargs
cdef readonly object __name__ # for tracing the scanner cdef readonly object __name__ # for tracing the scanner
## methods commented with '##' out are used by Parsing.py when compiled.
@cython.final @cython.final
cdef class CompileTimeScope: cdef class CompileTimeScope:
cdef public dict entries cdef public dict entries
cdef public CompileTimeScope outer cdef public CompileTimeScope outer
cdef declare(self, name, value) ##cdef declare(self, name, value)
cdef lookup_here(self, name) ##cdef lookup_here(self, name)
cpdef lookup(self, name) ##cpdef lookup(self, name)
@cython.final @cython.final
cdef class PyrexScanner(Scanner): cdef class PyrexScanner(Scanner):
...@@ -51,15 +53,15 @@ cdef class PyrexScanner(Scanner): ...@@ -51,15 +53,15 @@ cdef class PyrexScanner(Scanner):
@cython.locals(current_level=cython.long, new_level=cython.long) @cython.locals(current_level=cython.long, new_level=cython.long)
cpdef indentation_action(self, text) cpdef indentation_action(self, text)
#cpdef eof_action(self, text) #cpdef eof_action(self, text)
cdef next(self) ##cdef next(self)
cdef peek(self) ##cdef peek(self)
#cpdef put_back(self, sy, systring) #cpdef put_back(self, sy, systring)
#cdef unread(self, token, value) #cdef unread(self, token, value)
cdef bint expect(self, what, message = *) except -2 ##cdef bint expect(self, what, message = *) except -2
cdef expect_keyword(self, what, message = *) ##cdef expect_keyword(self, what, message = *)
cdef expected(self, what, message = *) ##cdef expected(self, what, message = *)
cdef expect_indent(self) ##cdef expect_indent(self)
cdef expect_dedent(self) ##cdef expect_dedent(self)
cdef expect_newline(self, message=*, bint ignore_semicolon=*) ##cdef expect_newline(self, message=*, bint ignore_semicolon=*)
cdef int enter_async(self) except -1 ##cdef int enter_async(self) except -1
cdef int exit_async(self) except -1 ##cdef int exit_async(self) except -1
This diff is collapsed.
...@@ -153,6 +153,13 @@ cdef extern from "Python.h": ...@@ -153,6 +153,13 @@ cdef extern from "Python.h":
# PyErr_SetFromErrno(type);" when the system call returns an # PyErr_SetFromErrno(type);" when the system call returns an
# error. # error.
PyObject* PyErr_SetFromErrnoWithFilenameObject(object type, object filenameObject) except NULL
# Similar to PyErr_SetFromErrno(), with the additional behavior
# that if filenameObject is not NULL, it is passed to the
# constructor of type as a third parameter.
# In the case of OSError exception, this is used to define
# the filename attribute of the exception instance.
PyObject* PyErr_SetFromErrnoWithFilename(object type, char *filename) except NULL PyObject* PyErr_SetFromErrnoWithFilename(object type, char *filename) except NULL
# Return value: Always NULL. Similar to PyErr_SetFromErrno(), # Return value: Always NULL. Similar to PyErr_SetFromErrno(),
# with the additional behavior that if filename is not NULL, it is # with the additional behavior that if filename is not NULL, it is
......
cdef extern from "<forward_list>" namespace "std" nogil:
cdef cppclass forward_list[T,ALLOCATOR=*]:
ctypedef T value_type
ctypedef ALLOCATOR allocator_type
# these should really be allocator_type.size_type and
# allocator_type.difference_type to be true to the C++ definition
# but cython doesn't support deferred access on template arguments
ctypedef size_t size_type
ctypedef ptrdiff_t difference_type
cppclass iterator:
iterator()
iterator(iterator &)
T& operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
cppclass const_iterator(iterator):
pass
forward_list() except +
forward_list(forward_list&) except +
forward_list(size_t, T&) except +
#forward_list& operator=(forward_list&)
bint operator==(forward_list&, forward_list&)
bint operator!=(forward_list&, forward_list&)
bint operator<(forward_list&, forward_list&)
bint operator>(forward_list&, forward_list&)
bint operator<=(forward_list&, forward_list&)
bint operator>=(forward_list&, forward_list&)
void assign(size_t, T&)
T& front()
iterator before_begin()
const_iterator const_before_begin "before_begin"()
iterator begin()
const_iterator const_begin "begin"()
iterator end()
const_iterator const_end "end"()
bint empty()
size_t max_size()
void clear()
iterator insert_after(iterator, T&)
void insert_after(iterator, size_t, T&)
iterator erase_after(iterator)
iterator erase_after(iterator, iterator)
void push_front(T&)
void pop_front()
void resize(size_t)
void resize(size_t, T&)
void swap(forward_list&)
void merge(forward_list&)
void merge[Compare](forward_list&, Compare)
void splice_after(iterator, forward_list&)
void splice_after(iterator, forward_list&, iterator)
void splice_after(iterator, forward_list&, iterator, iterator)
void remove(const T&)
void remove_if[Predicate](Predicate)
void reverse()
void unique()
void unique[Predicate](Predicate)
void sort()
void sort[Compare](Compare)
...@@ -28,18 +28,23 @@ cdef class Scanner: ...@@ -28,18 +28,23 @@ cdef class Scanner:
cdef public level cdef public level
@cython.final
@cython.locals(input_state=long) @cython.locals(input_state=long)
cdef next_char(self) cdef next_char(self)
@cython.locals(action=Action) @cython.locals(action=Action)
cpdef tuple read(self) cpdef tuple read(self)
@cython.final
cdef tuple scan_a_token(self) cdef tuple scan_a_token(self)
cdef tuple position(self) ##cdef tuple position(self) # used frequently by Parsing.py
@cython.final
@cython.locals(cur_pos=Py_ssize_t, cur_line=Py_ssize_t, cur_line_start=Py_ssize_t, @cython.locals(cur_pos=Py_ssize_t, cur_line=Py_ssize_t, cur_line_start=Py_ssize_t,
input_state=long, next_pos=Py_ssize_t, state=dict, input_state=long, next_pos=Py_ssize_t, state=dict,
buf_start_pos=Py_ssize_t, buf_len=Py_ssize_t, buf_index=Py_ssize_t, buf_start_pos=Py_ssize_t, buf_len=Py_ssize_t, buf_index=Py_ssize_t,
trace=bint, discard=Py_ssize_t, data=unicode, buffer=unicode) trace=bint, discard=Py_ssize_t, data=unicode, buffer=unicode)
cdef run_machine_inlined(self) cdef run_machine_inlined(self)
@cython.final
cdef begin(self, state) cdef begin(self, state)
@cython.final
cdef produce(self, value, text = *) cdef produce(self, value, text = *)
...@@ -796,15 +796,48 @@ static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, ...@@ -796,15 +796,48 @@ static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err,
// so far, we only call PyErr_GivenExceptionMatches() with an exception type (not instance) as first argument // so far, we only call PyErr_GivenExceptionMatches() with an exception type (not instance) as first argument
// => optimise for that case // => optimise for that case
static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) {
Py_ssize_t i, n;
assert(PyExceptionClass_Check(exc_type));
n = PyTuple_GET_SIZE(tuple);
#if PY_MAJOR_VERSION >= 3
// the tighter subtype checking in Py3 allows faster out-of-order comparison
for (i=0; i<n; i++) {
if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1;
}
#endif
for (i=0; i<n; i++) {
PyObject *t = PyTuple_GET_ITEM(tuple, i);
#if PY_MAJOR_VERSION < 3
if (likely(exc_type == t)) return 1;
#endif
if (likely(PyExceptionClass_Check(t))) {
if (__Pyx_inner_PyErr_GivenExceptionMatches2(exc_type, NULL, t)) return 1;
} else {
// FIXME: Py3: PyErr_SetString(PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed");
}
}
return 0;
}
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject* exc_type) { static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject* exc_type) {
if (likely(err == exc_type)) return 1; if (likely(err == exc_type)) return 1;
if (likely(PyExceptionClass_Check(err))) { if (likely(PyExceptionClass_Check(err))) {
if (likely(PyExceptionClass_Check(exc_type))) {
return __Pyx_inner_PyErr_GivenExceptionMatches2(err, NULL, exc_type); return __Pyx_inner_PyErr_GivenExceptionMatches2(err, NULL, exc_type);
} else if (likely(PyTuple_Check(exc_type))) {
return __Pyx_PyErr_GivenExceptionMatchesTuple(err, exc_type);
} else {
// FIXME: Py3: PyErr_SetString(PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed");
}
} }
return PyErr_GivenExceptionMatches(err, exc_type); return PyErr_GivenExceptionMatches(err, exc_type);
} }
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *exc_type1, PyObject *exc_type2) { static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *exc_type1, PyObject *exc_type2) {
// Only used internally with known exception types => pure safety check assertions.
assert(PyExceptionClass_Check(exc_type1));
assert(PyExceptionClass_Check(exc_type2));
if (likely(err == exc_type1 || err == exc_type2)) return 1; if (likely(err == exc_type1 || err == exc_type2)) return 1;
if (likely(PyExceptionClass_Check(err))) { if (likely(PyExceptionClass_Check(err))) {
return __Pyx_inner_PyErr_GivenExceptionMatches2(err, exc_type1, exc_type2); return __Pyx_inner_PyErr_GivenExceptionMatches2(err, exc_type1, exc_type2);
......
...@@ -713,7 +713,7 @@ static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject els ...@@ -713,7 +713,7 @@ static CYTHON_INLINE {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject els
{{py: c_op = {'Eq': '==', 'Ne': '!='}[op] }} {{py: c_op = {'Eq': '==', 'Ne': '!='}[op] }}
{{py: {{py:
return_compare = ( return_compare = (
(lambda a,b,c_op: "if ({a} {c_op} {b}) {return_true}; else {return_false};".format( (lambda a,b,c_op, return_true=return_true, return_false=return_false: "if ({a} {c_op} {b}) {return_true}; else {return_false};".format(
a=a, b=b, c_op=c_op, return_true=return_true, return_false=return_false)) a=a, b=b, c_op=c_op, return_true=return_true, return_false=return_false))
if ret_type.is_pyobject else if ret_type.is_pyobject else
(lambda a,b,c_op: "return ({a} {c_op} {b});".format(a=a, b=b, c_op=c_op)) (lambda a,b,c_op: "return ({a} {c_op} {b});".format(a=a, b=b, c_op=c_op))
......
...@@ -487,3 +487,9 @@ def add_metaclass(metaclass): ...@@ -487,3 +487,9 @@ def add_metaclass(metaclass):
orig_vars.pop('__weakref__', None) orig_vars.pop('__weakref__', None)
return metaclass(cls.__name__, cls.__bases__, orig_vars) return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper return wrapper
def raise_error_if_module_name_forbidden(full_module_name):
#it is bad idea to call the pyx-file cython.pyx, so fail early
if full_module_name == 'cython' or full_module_name.endswith('.cython'):
raise ValueError('cython is a special module, cannot be used as a module name')
...@@ -127,7 +127,7 @@ pygments_style = 'sphinx' ...@@ -127,7 +127,7 @@ pygments_style = 'sphinx'
todo_include_todos = True todo_include_todos = True
# intersphinx for standard :keyword:s (def, for, etc.) # intersphinx for standard :keyword:s (def, for, etc.)
intersphinx_mapping = {'python': ('http://docs.python.org/3/', None)} intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)}
# If true, keep warnings as "system message" paragraphs in the built documents. # If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False #keep_warnings = False
......
from libc.stdlib cimport atoi from libc.stdlib cimport atoi
cdef parse_charptr_to_py_int(char*s): cdef parse_charptr_to_py_int(char* s):
assert s is not NULL, "byte string value is NULL" assert s is not NULL, "byte string value is NULL"
return atoi(s) # note: atoi() has no error detection! return atoi(s) # note: atoi() has no error detection!
...@@ -4,4 +4,4 @@ cdef extern from "string.h": ...@@ -4,4 +4,4 @@ cdef extern from "string.h":
cdef char* data = "hfvcakdfagbcffvschvxcdfgccbcfhvgcsnfxjh" cdef char* data = "hfvcakdfagbcffvschvxcdfgccbcfhvgcsnfxjh"
cdef char* pos = strstr(needle='akd', haystack=data) cdef char* pos = strstr(needle='akd', haystack=data)
print(pos != NULL) print(pos is not NULL)
cimport cython
@cython.profile(False)
def my_often_called_function():
pass
# mymodule.pxd
# declare a C function as "cpdef" to export it to the module
cdef extern from "math.h":
cpdef double sin(double x)
# mymodule.py
import cython
# override with Python import if not in compiled code
if not cython.compiled:
from math import sin
# calls sin() from math.h when compiled with Cython and math.sin() in Python
print(sin(0))
cdef class Shrubbery:
cdef int width, height
from __future__ import print_function
cdef class Shrubbery:
def __init__(self, w, h):
self.width = w
self.height = h
def describe(self):
print("This shrubbery is", self.width,
"by", self.height, "cubits.")
from my_module cimport Shrubbery
cdef Shrubbery another_shrubbery(Shrubbery sh1):
cdef Shrubbery sh2
sh2 = Shrubbery()
sh2.width = sh1.width
sh2.height = sh1.height
return sh2
from my_module cimport Shrubbery
cdef widen_shrubbery(Shrubbery sh, extra_width):
sh.width = sh.width + extra_width
# delorean.pyx
cdef public struct Vehicle:
int speed
float power
cdef api void activate(Vehicle *v):
if v.speed >= 88 and v.power >= 1.21:
print("Time travel achieved")
\ No newline at end of file
# marty.c
#include "delorean_api.h"
Vehicle car;
int main(int argc, char *argv[]) {
Py_Initialize();
import_delorean();
car.speed = atoi(argv[1]);
car.power = atof(argv[2]);
activate(&car);
Py_Finalize();
}
from cpython.ref cimport PyObject
from libc.stdint cimport uintptr_t
python_string = "foo"
cdef void* ptr = <void*>python_string
cdef uintptr_t adress_in_c = <uintptr_t>ptr
address_from_void = adress_in_c # address_from_void is a python int
cdef PyObject* ptr2 = <PyObject*>python_string
cdef uintptr_t address_in_c2 = <uintptr_t>ptr2
address_from_PyObject = address_in_c2 # address_from_PyObject is a python int
assert address_from_void == address_from_PyObject == id(python_string)
print(<object>ptr) # Prints "foo"
print(<object>ptr2) # prints "foo"
from __future__ import print_function
cdef:
struct Spam:
int tons
int i
float a
Spam *p
void f(Spam *s):
print(s.tons, "Tons of spam")
from __future__ import print_function
DEF FavouriteFood = u"spam"
DEF ArraySize = 42
DEF OtherArraySize = 2 * ArraySize + 17
cdef int a1[ArraySize]
cdef int a2[OtherArraySize]
print("I like", FavouriteFood)
\ No newline at end of file
def f(a, b, *args, c, d = 42, e, **kwds):
...
# We cannot call f with less verbosity than this.
foo = f(4, "bar", c=68, e=1.0)
def g(a, b, *, c, d):
...
# We cannot call g with less verbosity than this.
foo = g(4.0, "something", c=68, d="other")
from libc.stdio cimport FILE, fopen
from libc.stdlib cimport malloc, free
from cpython.exc cimport PyErr_SetFromErrnoWithFilenameObject
def open_file():
cdef FILE* p
p = fopen("spam.txt", "r")
if p is NULL:
PyErr_SetFromErrnoWithFilenameObject(OSError, "spam.txt")
...
def allocating_memory(number=10):
cdef double *my_array = <double *> malloc(number * sizeof(double))
if not my_array: # same as 'is NULL' above
raise MemoryError()
...
free(my_array)
cdef class A:
cdef foo(self)
cdef class B(A):
cdef foo(self, x=*)
cdef class C(B):
cpdef foo(self, x=*, int k=*)
from __future__ import print_function
cdef class A:
cdef foo(self):
print("A")
cdef class B(A):
cdef foo(self, x=None):
print("B", x)
cdef class C(B):
cpdef foo(self, x=True, int k=3):
print("C", x, k)
from __future__ import print_function
cdef class A:
cdef foo(self):
print("A")
cdef class B(A):
cpdef foo(self):
print("B")
class C(B): # NOTE: not cdef class
def foo(self):
print("C")
import numpy as np
def add_one(int[:,:] buf):
for x in range(buf.shape[0]):
for y in range(buf.shape[1]):
buf[x, y] += 1
# exporting_object must be a Python object
# implementing the buffer interface, e.g. a numpy array.
exporting_object = np.zeros((10, 20), dtype=np.intc)
add_one(exporting_object)
import numpy as np
cdef int[:, :, :] to_view, from_view
to_view = np.empty((20, 15, 30), dtype=np.intc)
from_view = np.ones((20, 15, 30), dtype=np.intc)
# copy the elements in from_view to to_view
to_view[...] = from_view
# or
to_view[:] = from_view
# or
to_view[:, :, :] = from_view
from cython cimport view
# direct access in both dimensions, strided in the first dimension, contiguous in the last
cdef int[:, ::view.contiguous] a
# contiguous list of pointers to contiguous lists of ints
cdef int[::view.indirect_contiguous, ::1] b
# direct or indirect in the first dimension, direct in the second dimension
# strided in both dimensions
cdef int[::view.generic, :] c
from cython cimport view
# VALID
cdef int[::view.indirect, ::1, :] a
cdef int[::view.indirect, :, ::1] b
cdef int[::view.indirect_contiguous, ::1, :] c
import numpy as np
def process_buffer(int[:,:] input_view not None,
int[:,:] output_view=None):
if output_view is None:
# Creating a default view, e.g.
output_view = np.empty_like(input_view)
# process 'input_view' into 'output_view'
return output_view
import numpy as np
cdef const double[:] myslice # const item type => read-only view
a = np.linspace(0, 10, num=50)
a.setflags(write=False)
myslice = a
import numpy as np
exporting_object = np.arange(0, 15 * 10 * 20, dtype=np.intc).reshape((15, 10, 20))
cdef int[:, :, :] my_view = exporting_object
# These are all equivalent
my_view[10]
my_view[10, :, :]
my_view[10, ...]
import numpy as np
array = np.arange(20, dtype=np.intc).reshape((2, 10))
cdef int[:, ::1] c_contig = array
cdef int[::1, :] f_contig = c_contig.T
cdef bint is_y_in(const unsigned char[:] string_view):
cdef int i
for i in range(string_view.shape[0]):
if string_view[i] == b'y':
return True
return False
print(is_y_in(b'hello world')) # False
print(is_y_in(b'hello Cython')) # True
cdef extern from "lunch.h":
void eject_tomato(float)
cdef enum otherstuff:
sausage, eggs, lettuce
cdef struct spamdish:
int oz_of_spam
otherstuff filler
cimport shrubbing
import shrubbing
def main():
cdef shrubbing.Shrubbery sh
sh = shrubbing.standard_shrubbery()
print("Shrubbery size is", sh.width, 'x', sh.length)
cimport c_lunch
def eject_tomato(float speed):
c_lunch.eject_tomato(speed)
from __future__ import print_function
cimport dishes
from dishes cimport spamdish
cdef void prepare(spamdish *d):
d.oz_of_spam = 42
d.filler = dishes.sausage
def serve():
cdef spamdish d
prepare(&d)
print(f'{d.oz_of_spam} oz spam, filler no. {d.filler}')
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize(["landscaping.pyx", "shrubbing.pyx"]))
cdef class Shrubbery:
cdef int width
cdef int length
cdef class Shrubbery:
def __cinit__(self, int w, int l):
self.width = w
self.length = l
def standard_shrubbery():
return Shrubbery(3, 7)
from __future__ import print_function
from volume cimport cube
def menu(description, size):
print(description, ":", cube(size),
"cubic metres of spam")
menu("Entree", 1)
menu("Main course", 3)
menu("Dessert", 2)
cdef float cube(float x):
return x * x * x
...@@ -8,5 +8,5 @@ cdef extern from "Rectangle.h" namespace "shapes": ...@@ -8,5 +8,5 @@ cdef extern from "Rectangle.h" namespace "shapes":
Rectangle(int, int, int, int) except + Rectangle(int, int, int, int) except +
int x0, y0, x1, y1 int x0, y0, x1, y1
int getArea() int getArea()
void getSize(int*width, int*height) void getSize(int* width, int* height)
void move(int, int) void move(int, int)
# distutils: language = c++
cdef extern from "<algorithm>" namespace "std":
T max[T](T a, T b)
print(max[long](3, 4))
print(max(1.5, 2.5)) # simple template argument deduction
# distutils: language = c++
from libcpp.vector cimport vector
def main():
cdef vector[int] v = [4, 6, 5, 10, 3]
cdef int value
for value in v:
print(value)
return [x*x for x in v if x % 2 == 0]
# distutils: language = c++
cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]:
cppclass iterator:
T operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
vector()
void push_back(T&)
T& operator[](int)
T& at(int)
iterator begin()
iterator end()
cdef vector[int].iterator iter #iter is declared as being of type vector<int>::iterator
# distutils: language = c++
from libcpp.string cimport string
from libcpp.vector cimport vector
py_bytes_object = b'The knights who say ni'
py_unicode_object = u'Those who hear them seldom live to tell the tale.'
cdef string s = py_bytes_object
print(s) # b'The knights who say ni'
cdef string cpp_string = <string> py_unicode_object.encode('utf-8')
print(cpp_string) # b'Those who hear them seldom live to tell the tale.'
cdef vector[int] vect = range(1, 10, 2)
print(vect) # [1, 3, 5, 7, 9]
cdef vector[string] cpp_strings = b'It is a good shrubbery'.split()
print(cpp_strings[1]) # b'is'
# distutils: language = c++
# import dereference and increment operators
from cython.operator cimport dereference as deref, preincrement as inc
cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]:
cppclass iterator:
T operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
vector()
void push_back(T&)
T& operator[](int)
T& at(int)
iterator begin()
iterator end()
cdef vector[int] *v = new vector[int]()
cdef int i
for i in range(10):
v.push_back(i)
cdef vector[int].iterator it = v.begin()
while it != v.end():
print(deref(it))
inc(it)
del v
# distutils: language = c++
from libcpp.vector cimport vector
cdef vector[int] vect
cdef int i, x
for i in range(10):
vect.push_back(i)
for i in range(10):
print(vect[i])
for x in vect:
print(x)
# distutils: language = c++
from libcpp.vector cimport vector
cdef class VectorStack:
cdef vector[int] v
def push(self, x):
self.v.push_back(x)
def pop(self):
if self.v.empty():
raise IndexError()
x = self.v.back()
self.v.pop_back()
return x
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html web htmlhelp latex changes linkcheck
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " web to make files usable by Sphinx.web"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview over all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
clean:
-rm -rf build/*
html:
mkdir -p build/html build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
@echo
@echo "Build finished. The HTML pages are in build/html."
web:
mkdir -p build/web build/doctrees
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web
@echo
@echo "Build finished; now you can run"
@echo " python -m sphinx.web build/web"
@echo "to start the server."
htmlhelp:
mkdir -p build/htmlhelp build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in build/htmlhelp."
latex:
mkdir -p build/latex build/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
@echo
@echo "Build finished; the LaTeX files are in build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
mkdir -p build/changes build/doctrees
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
@echo
@echo "The overview file is in build/changes."
linkcheck:
mkdir -p build/linkcheck build/doctrees
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in build/linkcheck/output.txt."
...@@ -51,7 +51,8 @@ system, for example, it might look similar to this:: ...@@ -51,7 +51,8 @@ system, for example, it might look similar to this::
(``gcc`` will need to have paths to your included header files and paths (``gcc`` will need to have paths to your included header files and paths
to libraries you want to link with.) to libraries you want to link with.)
After compilation, a ``yourmod.so`` file is written into the target directory After compilation, a ``yourmod.so`` (:file:`yourmod.pyd` for Windows)
file is written into the target directory
and your module, ``yourmod``, is available for you to import as with any other and your module, ``yourmod``, is available for you to import as with any other
Python module. Note that if you are not relying on ``cythonize`` or distutils, Python module. Note that if you are not relying on ``cythonize`` or distutils,
you will not automatically benefit from the platform specific file extension you will not automatically benefit from the platform specific file extension
...@@ -104,7 +105,13 @@ the necessary include files, e.g. for NumPy:: ...@@ -104,7 +105,13 @@ the necessary include files, e.g. for NumPy::
include_path = [numpy.get_include()] include_path = [numpy.get_include()]
Note for Numpy users. Despite this, you will still get warnings like the .. note::
Using memoryviews or importing NumPy with ``import numpy`` does not mean that
you have to add the path to NumPy include files. You need to add this path only
if you use ``cimport numpy``.
Despite this, you will still get warnings like the
following from the compiler, because Cython is using a deprecated Numpy API:: following from the compiler, because Cython is using a deprecated Numpy API::
.../include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp] .../include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
...@@ -462,6 +469,7 @@ C-compiling the module C files. ...@@ -462,6 +469,7 @@ C-compiling the module C files.
Also take a look at the `cython_freeze Also take a look at the `cython_freeze
<https://github.com/cython/cython/blob/master/bin/cython_freeze>`_ tool. <https://github.com/cython/cython/blob/master/bin/cython_freeze>`_ tool.
.. _pyximport:
Compiling with :mod:`pyximport` Compiling with :mod:`pyximport`
=============================== ===============================
......
...@@ -158,7 +158,7 @@ We can thus change the init function as follows: ...@@ -158,7 +158,7 @@ We can thus change the init function as follows:
exception instance in order to raise it may actually fail because exception instance in order to raise it may actually fail because
we are running out of memory. Luckily, CPython provides a C-API we are running out of memory. Luckily, CPython provides a C-API
function ``PyErr_NoMemory()`` that safely raises the right function ``PyErr_NoMemory()`` that safely raises the right
exception for us. Since version 0.14.1, Cython automatically exception for us. Cython automatically
substitutes this C-API call whenever you write ``raise substitutes this C-API call whenever you write ``raise
MemoryError`` or ``raise MemoryError()``. If you use an older MemoryError`` or ``raise MemoryError()``. If you use an older
version, you have to cimport the C-API function from the standard version, you have to cimport the C-API function from the standard
......
...@@ -77,7 +77,7 @@ It is shipped and installed with Cython and can be used like this:: ...@@ -77,7 +77,7 @@ It is shipped and installed with Cython and can be used like this::
>>> import helloworld >>> import helloworld
Hello World Hello World
Since Cython 0.11, the :ref:`Pyximport<pyximport>` module also has experimental The :ref:`Pyximport<pyximport>` module also has experimental
compilation support for normal Python modules. This allows you to compilation support for normal Python modules. This allows you to
automatically run Cython on every .pyx and .py module that Python automatically run Cython on every .pyx and .py module that Python
imports, including the standard library and installed packages. imports, including the standard library and installed packages.
......
...@@ -92,7 +92,7 @@ names like this:: ...@@ -92,7 +92,7 @@ names like this::
char* strstr(const char*, const char*) char* strstr(const char*, const char*)
However, this prevents Cython code from calling it with keyword However, this prevents Cython code from calling it with keyword
arguments (supported since Cython 0.19). It is therefore preferable arguments. It is therefore preferable
to write the declaration like this instead: to write the declaration like this instead:
.. literalinclude:: ../../examples/tutorial/external/keyword_args.pyx .. literalinclude:: ../../examples/tutorial/external/keyword_args.pyx
......
...@@ -23,7 +23,8 @@ the Cython version -- Cython uses ".pyx" as its file suffix. ...@@ -23,7 +23,8 @@ the Cython version -- Cython uses ".pyx" as its file suffix.
.. literalinclude:: ../../examples/tutorial/numpy/convolve_py.py .. literalinclude:: ../../examples/tutorial/numpy/convolve_py.py
This should be compiled to produce :file:`yourmod.so` (for Linux systems). We This should be compiled to produce :file:`yourmod.so` (for Linux systems, on Windows
systems, it will be :file:`yourmod.pyd`). We
run a Python session to test both the Python version (imported from run a Python session to test both the Python version (imported from
``.py``-file) and the compiled Cython module. ``.py``-file) and the compiled Cython module.
......
...@@ -44,14 +44,9 @@ If your profiling is messed up because of the call overhead to some small ...@@ -44,14 +44,9 @@ If your profiling is messed up because of the call overhead to some small
functions that you rather do not want to see in your profile - either because functions that you rather do not want to see in your profile - either because
you plan to inline them anyway or because you are sure that you can't make them you plan to inline them anyway or because you are sure that you can't make them
any faster - you can use a special decorator to disable profiling for one any faster - you can use a special decorator to disable profiling for one
function only:: function only (regardless of whether it is globally enabled or not):
cimport cython
@cython.profile(False)
def my_often_called_function():
pass
.. literalinclude:: ../../examples/tutorial/profiling_tutorial/often_called.pyx
Enabling line tracing Enabling line tracing
--------------------- ---------------------
......
...@@ -299,25 +299,11 @@ Calling C functions ...@@ -299,25 +299,11 @@ Calling C functions
Normally, it isn't possible to call C functions in pure Python mode as there Normally, it isn't possible to call C functions in pure Python mode as there
is no general way to support it in normal (uncompiled) Python. However, in is no general way to support it in normal (uncompiled) Python. However, in
cases where an equivalent Python function exists, this can be achieved by cases where an equivalent Python function exists, this can be achieved by
combining C function coercion with a conditional import as follows:: combining C function coercion with a conditional import as follows:
# in mymodule.pxd: .. literalinclude:: ../../examples/tutorial/pure/mymodule.pxd
# declare a C function as "cpdef" to export it to the module .. literalinclude:: ../../examples/tutorial/pure/mymodule.py
cdef extern from "math.h":
cpdef double sin(double x)
# in mymodule.py:
import cython
# override with Python import if not in compiled code
if not cython.compiled:
from math import sin
# calls sin() from math.h when compiled with Cython and math.sin() in Python
print(sin(0))
Note that the "sin" function will show up in the module namespace of "mymodule" Note that the "sin" function will show up in the module namespace of "mymodule"
here (i.e. there will be a ``mymodule.sin()`` function). You can mark it as an here (i.e. there will be a ``mymodule.sin()`` function). You can mark it as an
...@@ -334,7 +320,7 @@ to make the names match again. ...@@ -334,7 +320,7 @@ to make the names match again.
Using C arrays for fixed size lists Using C arrays for fixed size lists
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since Cython 0.22, C arrays can automatically coerce to Python lists or tuples. C arrays can automatically coerce to Python lists or tuples.
This can be exploited to replace fixed size Python lists in Python code by C This can be exploited to replace fixed size Python lists in Python code by C
arrays when compiled. An example: arrays when compiled. An example:
......
...@@ -164,7 +164,7 @@ the assignment in a try-finally construct: ...@@ -164,7 +164,7 @@ the assignment in a try-finally construct:
To convert the byte string back into a C :c:type:`char*`, use the To convert the byte string back into a C :c:type:`char*`, use the
opposite assignment:: opposite assignment::
cdef char* other_c_string = py_string cdef char* other_c_string = py_string # other_c_string is a 0-terminated string.
This is a very fast operation after which ``other_c_string`` points to This is a very fast operation after which ``other_c_string`` points to
the byte string buffer of the Python string itself. It is tied to the the byte string buffer of the Python string itself. It is tied to the
...@@ -260,7 +260,7 @@ not modify a string they return, for example: ...@@ -260,7 +260,7 @@ not modify a string they return, for example:
.. literalinclude:: ../../examples/tutorial/string/someheader.h .. literalinclude:: ../../examples/tutorial/string/someheader.h
Since version 0.18, Cython has support for the ``const`` modifier in Cython has support for the ``const`` modifier in
the language, so you can declare the above functions straight away as the language, so you can declare the above functions straight away as
follows: follows:
...@@ -296,7 +296,7 @@ bytes most of which tend to be 0. ...@@ -296,7 +296,7 @@ bytes most of which tend to be 0.
Again, no bounds checking is done if slice indices are provided, so Again, no bounds checking is done if slice indices are provided, so
incorrect indices lead to data corruption and crashes. However, using incorrect indices lead to data corruption and crashes. However, using
negative indices is possible since Cython 0.17 and will inject a call negative indices is possible and will inject a call
to :c:func:`strlen()` in order to determine the string length. to :c:func:`strlen()` in order to determine the string length.
Obviously, this only works for 0-terminated strings without internal Obviously, this only works for 0-terminated strings without internal
null bytes. Text encoded in UTF-8 or one of the ISO-8859 encodings is null bytes. Text encoded in UTF-8 or one of the ISO-8859 encodings is
...@@ -467,7 +467,7 @@ supports the ``__future__`` import ``unicode_literals`` that instructs ...@@ -467,7 +467,7 @@ supports the ``__future__`` import ``unicode_literals`` that instructs
the parser to read all unprefixed :obj:`str` literals in a source file as the parser to read all unprefixed :obj:`str` literals in a source file as
unicode string literals, just like Python 3. unicode string literals, just like Python 3.
.. _`CEP 108`: http://wiki.cython.org/enhancements/stringliterals .. _`CEP 108`: https://github.com/cython/cython/wiki/enhancements-stringliterals
Single bytes and characters Single bytes and characters
--------------------------- ---------------------------
...@@ -475,7 +475,7 @@ Single bytes and characters ...@@ -475,7 +475,7 @@ Single bytes and characters
The Python C-API uses the normal C :c:type:`char` type to represent The Python C-API uses the normal C :c:type:`char` type to represent
a byte value, but it has two special integer types for a Unicode code a byte value, but it has two special integer types for a Unicode code
point value, i.e. a single Unicode character: :c:type:`Py_UNICODE` point value, i.e. a single Unicode character: :c:type:`Py_UNICODE`
and :c:type:`Py_UCS4`. Since version 0.13, Cython supports the and :c:type:`Py_UCS4`. Cython supports the
first natively, support for :c:type:`Py_UCS4` is new in Cython 0.15. first natively, support for :c:type:`Py_UCS4` is new in Cython 0.15.
:c:type:`Py_UNICODE` is either defined as an unsigned 2-byte or :c:type:`Py_UNICODE` is either defined as an unsigned 2-byte or
4-byte integer, or as :c:type:`wchar_t`, depending on the platform. 4-byte integer, or as :c:type:`wchar_t`, depending on the platform.
......
...@@ -105,21 +105,23 @@ will be very inefficient. If the attribute is private, it will not work at all ...@@ -105,21 +105,23 @@ will be very inefficient. If the attribute is private, it will not work at all
-- the code will compile, but an attribute error will be raised at run time. -- the code will compile, but an attribute error will be raised at run time.
The solution is to declare ``sh`` as being of type :class:`Shrubbery`, as The solution is to declare ``sh`` as being of type :class:`Shrubbery`, as
follows:: follows:
cdef widen_shrubbery(Shrubbery sh, extra_width): .. literalinclude:: ../../examples/userguide/extension_types/widen_shrubbery.pyx
sh.width = sh.width + extra_width
Now the Cython compiler knows that ``sh`` has a C attribute called Now the Cython compiler knows that ``sh`` has a C attribute called
:attr:`width` and will generate code to access it directly and efficiently. :attr:`width` and will generate code to access it directly and efficiently.
The same consideration applies to local variables, for example,:: The same consideration applies to local variables, for example:
.. literalinclude:: ../../examples/userguide/extension_types/shrubbery_2.pyx
.. note::
cdef Shrubbery another_shrubbery(Shrubbery sh1): We here ``cimport`` the class :class:`Shrubbery`, and this is necessary
cdef Shrubbery sh2 to declare the type at compile time. To be able to ``cimport`` an extension type,
sh2 = Shrubbery() we split the class definition into two parts, one in a definition file and
sh2.width = sh1.width the other in the corresponding implementation file. You should read
sh2.height = sh1.height :ref:`sharing_extension_types` to learn to do that.
return sh2
Type Testing and Casting Type Testing and Casting
...@@ -347,7 +349,7 @@ inherit from multiple extension types provided that the usual Python rules for ...@@ -347,7 +349,7 @@ inherit from multiple extension types provided that the usual Python rules for
multiple inheritance are followed (i.e. the C layouts of all the base classes multiple inheritance are followed (i.e. the C layouts of all the base classes
must be compatible). must be compatible).
Since Cython 0.13.1, there is a way to prevent extension types from There is a way to prevent extension types from
being subtyped in Python. This is done via the ``final`` directive, being subtyped in Python. This is done via the ``final`` directive,
usually set on an extension type using a decorator:: usually set on an extension type using a decorator::
...@@ -419,7 +421,7 @@ compatible types.:: ...@@ -419,7 +421,7 @@ compatible types.::
cdef void* ptr cdef void* ptr
def __dealloc__(self): def __dealloc__(self):
if self.ptr != NULL: if self.ptr is not NULL:
free(self.ptr) free(self.ptr)
@staticmethod @staticmethod
......
...@@ -458,32 +458,12 @@ contains the api call which is generating the segmentation fault does not call ...@@ -458,32 +458,12 @@ contains the api call which is generating the segmentation fault does not call
the :func:`import_modulename` function before the api call which crashes. the :func:`import_modulename` function before the api call which crashes.
Any public C type or extension type declarations in the Cython module are also Any public C type or extension type declarations in the Cython module are also
made available when you include :file:`modulename_api.h`.:: made available when you include :file:`modulename_api.h`.:
# delorean.pyx .. literalinclude:: ../../examples/userguide/external_C_code/delorean.pyx
cdef public struct Vehicle:
int speed
float power
cdef api void activate(Vehicle *v): .. literalinclude:: ../../examples/userguide/external_C_code/marty.c
if v.speed >= 88 and v.power >= 1.21: :language: C
print("Time travel achieved")
.. sourcecode:: c
# marty.c
#include "delorean_api.h"
Vehicle car;
int main(int argc, char *argv[]) {
Py_Initialize();
import_delorean();
car.speed = atoi(argv[1]);
car.power = atof(argv[2]);
activate(&car);
Py_Finalize();
}
.. note:: .. note::
...@@ -587,7 +567,7 @@ header:: ...@@ -587,7 +567,7 @@ header::
If the callback may be called from another non-Python thread, If the callback may be called from another non-Python thread,
care must be taken to initialize the GIL first, through a call to care must be taken to initialize the GIL first, through a call to
`PyEval_InitThreads() <http://docs.python.org/dev/c-api/init.html#PyEval_InitThreads>`_. `PyEval_InitThreads() <https://docs.python.org/dev/c-api/init.html#c.PyEval_InitThreads>`_.
If you're already using :ref:`cython.parallel <parallel>` in your module, this will already have been taken care of. If you're already using :ref:`cython.parallel <parallel>` in your module, this will already have been taken care of.
The GIL may also be acquired through the ``with gil`` statement:: The GIL may also be acquired through the ``with gil`` statement::
......
...@@ -107,21 +107,9 @@ You can declare classes with :keyword:`cdef`, making them :ref:`extension-types` ...@@ -107,21 +107,9 @@ You can declare classes with :keyword:`cdef`, making them :ref:`extension-types`
have a behavior very close to python classes, but are faster because they use a ``struct`` have a behavior very close to python classes, but are faster because they use a ``struct``
internally to store attributes. internally to store attributes.
Here is a simple example:: Here is a simple example:
from __future__ import print_function .. literalinclude:: ../../examples/userguide/extension_types/shrubbery.pyx
cdef class Shrubbery:
cdef int width, height
def __init__(self, w, h):
self.width = w
self.height = h
def describe(self):
print("This shrubbery is", self.width,
"by", self.height, "cubits.")
You can read more about them in :ref:`extension-types`. You can read more about them in :ref:`extension-types`.
...@@ -179,20 +167,9 @@ Grouping multiple C declarations ...@@ -179,20 +167,9 @@ Grouping multiple C declarations
-------------------------------- --------------------------------
If you have a series of declarations that all begin with :keyword:`cdef`, you If you have a series of declarations that all begin with :keyword:`cdef`, you
can group them into a :keyword:`cdef` block like this:: can group them into a :keyword:`cdef` block like this:
from __future__ import print_function
cdef: .. literalinclude:: ../../examples/userguide/language_basics/cdef_block.pyx
struct Spam:
int tons
int i
float a
Spam *p
void f(Spam *s):
print(s.tons, "Tons of spam")
.. _cpdef: .. _cpdef:
.. _cdef: .. _cdef:
...@@ -311,35 +288,15 @@ To avoid repetition (and potential future inconsistencies), default argument val ...@@ -311,35 +288,15 @@ To avoid repetition (and potential future inconsistencies), default argument val
not visible in the declaration (in ``.pxd`` files) but only in not visible in the declaration (in ``.pxd`` files) but only in
the implementation (in ``.pyx`` files). the implementation (in ``.pyx`` files).
When in a ``.pyx`` file, the signature is the same as it is in Python itself:: When in a ``.pyx`` file, the signature is the same as it is in Python itself:
from __future__ import print_function
cdef class A:
cdef foo(self):
print("A")
cdef class B(A):
cdef foo(self, x=None):
print("B", x)
cdef class C(B):
cpdef foo(self, x=True, int k=3):
print("C", x, k)
.. literalinclude:: ../../examples/userguide/language_basics/optional_subclassing.pyx
When in a ``.pxd`` file, the signature is different like this example: ``cdef foo(x=*)``. When in a ``.pxd`` file, the signature is different like this example: ``cdef foo(x=*)``.
This is because the program calling the function just needs to know what signatures are This is because the program calling the function just needs to know what signatures are
possible in C, but doesn't need to know the value of the default arguments.:: possible in C, but doesn't need to know the value of the default arguments.:
cdef class A:
cdef foo(self)
cdef class B(A):
cdef foo(self, x=*)
cdef class C(B):
cpdef foo(self, x=*, int k=*)
.. literalinclude:: ../../examples/userguide/language_basics/optional_subclassing.pxd
.. note:: .. note::
The number of arguments may increase when subclassing, The number of arguments may increase when subclassing,
...@@ -355,13 +312,9 @@ Keyword-only Arguments ...@@ -355,13 +312,9 @@ Keyword-only Arguments
---------------------- ----------------------
As in Python 3, ``def`` functions can have keyword-only arguments As in Python 3, ``def`` functions can have keyword-only arguments
listed after a ``"*"`` parameter and before a ``"**"`` parameter if any:: listed after a ``"*"`` parameter and before a ``"**"`` parameter if any:
def f(a, b, *args, c, d = 42, e, **kwds): .. literalinclude:: ../../examples/userguide/language_basics/kwargs_1.pyx
...
# We cannot call f with less verbosity than this.
foo = f(4, "bar", c=68, e=1.0)
As shown above, the ``c``, ``d`` and ``e`` arguments can not be As shown above, the ``c``, ``d`` and ``e`` arguments can not be
passed as positional arguments and must be passed as keyword arguments. passed as positional arguments and must be passed as keyword arguments.
...@@ -369,16 +322,12 @@ Furthermore, ``c`` and ``e`` are **required** keyword arguments ...@@ -369,16 +322,12 @@ Furthermore, ``c`` and ``e`` are **required** keyword arguments
since they do not have a default value. since they do not have a default value.
A single ``"*"`` without argument name can be used to A single ``"*"`` without argument name can be used to
terminate the list of positional arguments:: terminate the list of positional arguments:
def g(a, b, *, c, d):
...
# We cannot call g with less verbosity than this. .. literalinclude:: ../../examples/userguide/language_basics/kwargs_2.pyx
foo = g(4.0, "something", c=68, d="other")
Shown above, the signature takes exactly two positional Shown above, the signature takes exactly two positional
parameters and has two required keyword parameters parameters and has two required keyword parameters.
Function Pointers Function Pointers
----------------- -----------------
...@@ -479,12 +428,9 @@ returns ``NULL``. The except clause doesn't work that way; its only purpose is ...@@ -479,12 +428,9 @@ returns ``NULL``. The except clause doesn't work that way; its only purpose is
for propagating Python exceptions that have already been raised, either by a Cython for propagating Python exceptions that have already been raised, either by a Cython
function or a C function that calls Python/C API routines. To get an exception function or a C function that calls Python/C API routines. To get an exception
from a non-Python-aware function such as :func:`fopen`, you will have to check the from a non-Python-aware function such as :func:`fopen`, you will have to check the
return value and raise it yourself, for example,:: return value and raise it yourself, for example:
cdef FILE* p .. literalinclude:: ../../examples/userguide/language_basics/open_file.pyx
p = fopen("spam.txt", "r")
if p == NULL:
raise SpamError("Couldn't open the spam file")
.. _overriding_in_extension_types: .. _overriding_in_extension_types:
...@@ -492,39 +438,15 @@ Overriding in extension types ...@@ -492,39 +438,15 @@ Overriding in extension types
----------------------------- -----------------------------
``cpdef`` methods can override ``cdef`` methods:: ``cpdef`` methods can override ``cdef`` methods:
from __future__ import print_function .. literalinclude:: ../../examples/userguide/language_basics/optional_subclassing.pyx
cdef class A:
cdef foo(self):
print("A")
cdef class B(A):
cdef foo(self, x=None):
print("B", x)
cdef class C(B):
cpdef foo(self, x=True, int k=3):
print("C", x, k)
When subclassing an extension type with a Python class, When subclassing an extension type with a Python class,
``def`` methods can override ``cpdef`` methods but not ``cdef`` ``def`` methods can override ``cpdef`` methods but not ``cdef``
methods:: methods:
from __future__ import print_function
cdef class A:
cdef foo(self):
print("A")
cdef class B(A): .. literalinclude:: ../../examples/userguide/language_basics/override.pyx
cpdef foo(self):
print("B")
class C(B): # NOTE: not cdef class
def foo(self):
print("C")
If ``C`` above would be an extension type (``cdef class``), If ``C`` above would be an extension type (``cdef class``),
this would not work correctly. this would not work correctly.
...@@ -556,6 +478,8 @@ possibilities. ...@@ -556,6 +478,8 @@ possibilities.
+----------------------------+--------------------+------------------+ +----------------------------+--------------------+------------------+
| char* | str/bytes | str/bytes [#]_ | | char* | str/bytes | str/bytes [#]_ |
+----------------------------+--------------------+------------------+ +----------------------------+--------------------+------------------+
| C array | iterable | list [#2]_ |
+----------------------------+--------------------+------------------+
| struct, | | dict [#1]_ | | struct, | | dict [#1]_ |
| union | | | | union | | |
+----------------------------+--------------------+------------------+ +----------------------------+--------------------+------------------+
...@@ -568,6 +492,10 @@ possibilities. ...@@ -568,6 +492,10 @@ possibilities.
combinations. An example is a union of an ``int`` and a ``char*``, combinations. An example is a union of an ``int`` and a ``char*``,
in which case the pointer value may or may not be a valid pointer. in which case the pointer value may or may not be a valid pointer.
.. [#2] Other than signed/unsigned char[].
The conversion will fail if the length of C array is not known at compile time,
and when using a slice of a C array.
Caveats when using a Python string in a C context Caveats when using a Python string in a C context
------------------------------------------------- -------------------------------------------------
...@@ -632,26 +560,9 @@ You can also cast a C pointer back to a Python object reference ...@@ -632,26 +560,9 @@ You can also cast a C pointer back to a Python object reference
with ``<object>``, or a more specific builtin or extension type with ``<object>``, or a more specific builtin or extension type
(e.g. ``<MyExtType>ptr``). This will increase the reference count of (e.g. ``<MyExtType>ptr``). This will increase the reference count of
the object by one, i.e. the cast returns an owned reference. the object by one, i.e. the cast returns an owned reference.
Here is an example:: Here is an example:
from cpython.ref cimport PyObject
from libc.stdint cimport uintptr_t
python_string = "foo"
cdef void* ptr = <void*>python_string
cdef uintptr_t adress_in_c = <uintptr_t>ptr
address_from_void = adress_in_c # address_from_void is a python int
cdef PyObject* ptr2 = <PyObject*>python_string
cdef uintptr_t address_in_c2 = <uintptr_t>ptr2
address_from_PyObject = address_in_c2 # address_from_PyObject is a python int
assert address_from_void == address_from_PyObject == id(python_string)
print(<object>ptr) # Prints "foo"
print(<object>ptr2) # prints "foo"
.. literalinclude:: ../../examples/userguide/language_basics/casting_python.pyx
The precedence of ``<...>`` is such that ``<type>a.b.c`` is interpreted as ``<type>(a.b.c)``. The precedence of ``<...>`` is such that ``<type>a.b.c`` is interpreted as ``<type>(a.b.c)``.
...@@ -971,13 +882,7 @@ the source at that point as a literal. For this to work, the compile-time ...@@ -971,13 +882,7 @@ the source at that point as a literal. For this to work, the compile-time
expression must evaluate to a Python value of type ``int``, ``long``, expression must evaluate to a Python value of type ``int``, ``long``,
``float``, ``bytes`` or ``unicode`` (``str`` in Py3). ``float``, ``bytes`` or ``unicode`` (``str`` in Py3).
:: .. literalinclude:: ../../examples/userguide/language_basics/compile_time.pyx
from __future__ import print_function
cdef int a1[ArraySize]
cdef int a2[OtherArraySize]
print("I like", FavouriteFood)
Conditional Statements Conditional Statements
---------------------- ----------------------
......
...@@ -71,14 +71,9 @@ This also works conveniently as function arguments: ...@@ -71,14 +71,9 @@ This also works conveniently as function arguments:
The ``not None`` declaration for the argument automatically rejects The ``not None`` declaration for the argument automatically rejects
None values as input, which would otherwise be allowed. The reason why None values as input, which would otherwise be allowed. The reason why
None is allowed by default is that it is conveniently used for return None is allowed by default is that it is conveniently used for return
arguments:: arguments:
def process_buffer(int[:,:] input not None, .. literalinclude:: ../../examples/userguide/memoryviews/not_none.pyx
int[:,:] output = None):
if output is None:
output = ... # e.g. numpy.empty_like(input)
# process 'input' into 'output'
return output
Cython will reject incompatible buffers automatically, e.g. passing a Cython will reject incompatible buffers automatically, e.g. passing a
three dimensional buffer into a function that requires a two three dimensional buffer into a function that requires a two
...@@ -102,40 +97,24 @@ dimension:: ...@@ -102,40 +97,24 @@ dimension::
print(buf[-1,-2]) print(buf[-1,-2])
The following function loops over each dimension of a 2D array and The following function loops over each dimension of a 2D array and
adds 1 to each item:: adds 1 to each item:
def add_one(int[:,:] buf): .. literalinclude:: ../../examples/userguide/memoryviews/add_one.pyx
for x in xrange(buf.shape[0]):
for y in xrange(buf.shape[1]):
buf[x,y] += 1
Indexing and slicing can be done with or without the GIL. It basically works Indexing and slicing can be done with or without the GIL. It basically works
like NumPy. If indices are specified for every dimension you will get an element like NumPy. If indices are specified for every dimension you will get an element
of the base type (e.g. `int`). Otherwise, you will get a new view. An Ellipsis of the base type (e.g. `int`). Otherwise, you will get a new view. An Ellipsis
means you get consecutive slices for every unspecified dimension:: means you get consecutive slices for every unspecified dimension:
cdef int[:, :, :] my_view = exporting_object .. literalinclude:: ../../examples/userguide/memoryviews/slicing.pyx
# These are all equivalent
my_view[10]
my_view[10, :, :]
my_view[10, ...]
Copying Copying
------- -------
Memory views can be copied in place:: Memory views can be copied in place:
cdef int[:, :, :] to_view, from_view
...
# copy the elements in from_view to to_view .. literalinclude:: ../../examples/userguide/memoryviews/copy.pyx
to_view[...] = from_view
# or
to_view[:] = from_view
# or
to_view[:, :, :] = from_view
They can also be copied with the ``copy()`` and ``copy_fortran()`` methods; see They can also be copied with the ``copy()`` and ``copy_fortran()`` methods; see
:ref:`view_copy_c_fortran`. :ref:`view_copy_c_fortran`.
...@@ -146,10 +125,9 @@ Transposing ...@@ -146,10 +125,9 @@ Transposing
----------- -----------
In most cases (see below), the memoryview can be transposed in the same way that In most cases (see below), the memoryview can be transposed in the same way that
NumPy slices can be transposed:: NumPy slices can be transposed:
cdef int[:, ::1] c_contig = ... .. literalinclude:: ../../examples/userguide/memoryviews/transpose.pyx
cdef int[::1, :] f_contig = c_contig.T
This gives a new, transposed, view on the data. This gives a new, transposed, view on the data.
...@@ -171,6 +149,9 @@ As for NumPy, new axes can be introduced by indexing an array with ``None`` :: ...@@ -171,6 +149,9 @@ As for NumPy, new axes can be introduced by indexing an array with ``None`` ::
# 2D array with shape (50, 1) # 2D array with shape (50, 1)
myslice[:, None] myslice[:, None]
# 3D array with shape (1, 10, 1)
myslice[None, 10:-20:2, None]
One may mix new axis indexing with all other forms of indexing and slicing. One may mix new axis indexing with all other forms of indexing and slicing.
See also an example_. See also an example_.
...@@ -178,13 +159,14 @@ Read-only views ...@@ -178,13 +159,14 @@ Read-only views
--------------- ---------------
Since Cython 0.28, the memoryview item type can be declared as ``const`` to Since Cython 0.28, the memoryview item type can be declared as ``const`` to
support read-only buffers as input:: support read-only buffers as input:
cdef const double[:] myslice # const item type => read-only view .. literalinclude:: ../../examples/userguide/memoryviews/np_flag_const.pyx
a = np.linspace(0, 10, num=50) Using a non-const memoryview with a binary Python string produces a runtime error.
a.setflags(write=False) You can solve this issue with a ``const`` memoryview:
myslice = a
.. literalinclude:: ../../examples/userguide/memoryviews/view_string.pyx
Note that this does not *require* the input buffer to be read-only:: Note that this does not *require* the input buffer to be read-only::
...@@ -436,31 +418,21 @@ The flags are as follows: ...@@ -436,31 +418,21 @@ The flags are as follows:
* contiguous - contiguous and direct * contiguous - contiguous and direct
* indirect_contiguous - the list of pointers is contiguous * indirect_contiguous - the list of pointers is contiguous
and they can be used like this:: and they can be used like this:
from cython cimport view
# direct access in both dimensions, strided in the first dimension, contiguous in the last .. literalinclude:: ../../examples/userguide/memoryviews/memory_layout.pyx
cdef int[:, ::view.contiguous] a
# contiguous list of pointers to contiguous lists of ints Only the first, last or the dimension following an indirect dimension may be
cdef int[::view.indirect_contiguous, ::1] b specified contiguous:
# direct or indirect in the first dimension, direct in the second dimension .. literalinclude:: ../../examples/userguide/memoryviews/memory_layout_2.pyx
# strided in both dimensions
cdef int[::view.generic, :] c
Only the first, last or the dimension following an indirect dimension may be ::
specified contiguous::
# INVALID # INVALID
cdef int[::view.contiguous, ::view.indirect, :] a cdef int[::view.contiguous, ::view.indirect, :] d
cdef int[::1, ::view.indirect, :] b cdef int[::1, ::view.indirect, :] e
# VALID
cdef int[::view.indirect, ::1, :] a
cdef int[::view.indirect, :, ::1] b
cdef int[::view.indirect_contiguous, ::1, :]
The difference between the `contiguous` flag and the `::1` specifier is that the The difference between the `contiguous` flag and the `::1` specifier is that the
former specifies contiguity for only one dimension, whereas the latter specifies former specifies contiguity for only one dimension, whereas the latter specifies
...@@ -686,7 +658,5 @@ call functions in C files, see :ref:`using_c_libraries`. ...@@ -686,7 +658,5 @@ call functions in C files, see :ref:`using_c_libraries`.
.. _GIL: http://docs.python.org/dev/glossary.html#term-global-interpreter-lock .. _GIL: http://docs.python.org/dev/glossary.html#term-global-interpreter-lock
.. _new style buffers: https://docs.python.org/c-api/buffer.html
.. _pep 3118: https://www.python.org/dev/peps/pep-3118/
.. _NumPy: https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html#memory-layout .. _NumPy: https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html#memory-layout
.. _example: http://www.scipy.org/Numpy_Example_List#newaxis .. _example: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
...@@ -147,7 +147,8 @@ Cython version -- Cython uses ".pyx" as its file suffix. ...@@ -147,7 +147,8 @@ Cython version -- Cython uses ".pyx" as its file suffix.
.. literalinclude:: ../../examples/userguide/numpy_tutorial/convolve_py.py .. literalinclude:: ../../examples/userguide/numpy_tutorial/convolve_py.py
:linenos: :linenos:
This should be compiled to produce :file:`convolve_cy.so` (for Linux systems). We This should be compiled to produce :file:`convolve_cy.so` (for Linux systems,
on Windows systems, this will be a ``.pyd`` file). We
run a Python session to test both the Python version (imported from run a Python session to test both the Python version (imported from
``.py``-file) and the compiled Cython module. ``.py``-file) and the compiled Cython module.
......
...@@ -131,7 +131,7 @@ It currently supports OpenMP, but later on more backends might be supported. ...@@ -131,7 +131,7 @@ It currently supports OpenMP, but later on more backends might be supported.
with nogil, parallel(): with nogil, parallel():
local_buf = <int *> malloc(sizeof(int) * size) local_buf = <int *> malloc(sizeof(int) * size)
if local_buf == NULL: if local_buf is NULL:
abort() abort()
# populate our local buffer in a sequential loop # populate our local buffer in a sequential loop
......
Porting Cython code to PyPy Porting Cython code to PyPy
=========================== ===========================
Since version 0.17, Cython has basic support for cpyext, the layer in Cython has basic support for cpyext, the layer in
`PyPy <http://pypy.org/>`_ that emulates CPython's C-API. This is `PyPy <http://pypy.org/>`_ that emulates CPython's C-API. This is
achieved by making the generated C code adapt at C compile time, so achieved by making the generated C code adapt at C compile time, so
the generated code will compile in both CPython and PyPy unchanged. the generated code will compile in both CPython and PyPy unchanged.
......
...@@ -21,10 +21,14 @@ Python 3 Support ...@@ -21,10 +21,14 @@ Python 3 Support
Cython creates ``.c`` files that can be built and used with both Cython creates ``.c`` files that can be built and used with both
Python 2.x and Python 3.x. In fact, compiling your module with Python 2.x and Python 3.x. In fact, compiling your module with
Cython may very well be the easiest way to port code to Python 3. Cython may very well be an easy way to port code to Python 3.
We are also working to make the compiler run in both Python 2.x and 3.x.
Many Python 3 constructs are already supported by Cython. Cython also supports various syntax additions that came with
Python 3.0 and later major Python releases. If they do not conflict
with existing Python 2.x syntax or semantics, they are usually just
accepted by the compiler. Everything else depends on the
compiler directive ``language_level=3``
(see :ref:`compiler directives<compiler-directives>`).
List/Set/Dict Comprehensions List/Set/Dict Comprehensions
---------------------------- ----------------------------
...@@ -67,7 +71,6 @@ extra positional arguments, e.g.:: ...@@ -67,7 +71,6 @@ extra positional arguments, e.g.::
takes exactly two positional parameters and has two required keyword parameters. takes exactly two positional parameters and has two required keyword parameters.
Conditional expressions "x if b else y" Conditional expressions "x if b else y"
========================================= =========================================
...@@ -258,26 +261,13 @@ remain the same. There is a slight performance penalty in some cases when a ...@@ -258,26 +261,13 @@ remain the same. There is a slight performance penalty in some cases when a
cdef/cpdef function without any optional is overridden with one that does have cdef/cpdef function without any optional is overridden with one that does have
default argument values. default argument values.
For example, one can have the ``.pxd`` file:: For example, one can have the ``.pxd`` file:
cdef class A: .. literalinclude:: ../../examples/userguide/language_basics/optional_subclassing.pxd
cdef foo(self)
cdef class B(A)
cdef foo(self, x=*)
cdef class C(B):
cpdef foo(self, x=*, int k=*)
with corresponding ``.pyx`` file:: with corresponding ``.pyx`` file:
cdef class A: .. literalinclude:: ../../examples/userguide/language_basics/optional_subclassing.pyx
cdef foo(self):
print "A"
cdef class B(A)
cdef foo(self, x=None)
print "B", x
cdef class C(B):
cpdef foo(self, x=True, int k=3)
print "C", x, k
.. note:: .. note::
......
...@@ -80,28 +80,13 @@ Here is an example. :file:`dishes.pxd` is a definition file which exports a ...@@ -80,28 +80,13 @@ Here is an example. :file:`dishes.pxd` is a definition file which exports a
C data type. :file:`restaurant.pyx` is an implementation file which imports and C data type. :file:`restaurant.pyx` is an implementation file which imports and
uses it. uses it.
:file:`dishes.pxd`:: :file:`dishes.pxd`:
cdef enum otherstuff: .. literalinclude:: ../../examples/userguide/sharing_declarations/dishes.pxd
sausage, eggs, lettuce
cdef struct spamdish: :file:`restaurant.pyx`:
int oz_of_spam
otherstuff filler
:file:`restaurant.pyx`:: .. literalinclude:: ../../examples/userguide/sharing_declarations/restaurant.pyx
cimport dishes
from dishes cimport spamdish
cdef void prepare(spamdish *d):
d.oz_of_spam = 42
d.filler = dishes.sausage
def serve():
cdef spamdish d
prepare(&d)
print("%d oz spam, filler no. %d" % (d.oz_of_spam, d.filler))
It is important to understand that the :keyword:`cimport` statement can only It is important to understand that the :keyword:`cimport` statement can only
be used to import C data types, C functions and variables, and extension be used to import C data types, C functions and variables, and extension
...@@ -147,17 +132,13 @@ for an imaginary module, and :keyword:`cimport` that module. You can then ...@@ -147,17 +132,13 @@ for an imaginary module, and :keyword:`cimport` that module. You can then
refer to the C functions by qualifying them with the name of the module. refer to the C functions by qualifying them with the name of the module.
Here's an example: Here's an example:
:file:`c_lunch.pxd`:: :file:`c_lunch.pxd`:
cdef extern from "lunch.h": .. literalinclude:: ../../examples/userguide/sharing_declarations/c_lunch.pxd
void eject_tomato(float)
:file:`lunch.pyx`:: :file:`lunch.pyx`:
cimport c_lunch .. literalinclude:: ../../examples/userguide/sharing_declarations/lunch.pyx
def eject_tomato(float speed):
c_lunch.eject_tomato(speed)
You don't need any :file:`c_lunch.pyx` file, because the only things defined You don't need any :file:`c_lunch.pyx` file, because the only things defined
in :file:`c_lunch.pxd` are extern C entities. There won't be any actual in :file:`c_lunch.pxd` are extern C entities. There won't be any actual
...@@ -173,28 +154,17 @@ C functions defined at the top level of a module can be made available via ...@@ -173,28 +154,17 @@ C functions defined at the top level of a module can be made available via
:keyword:`cimport` by putting headers for them in the ``.pxd`` file, for :keyword:`cimport` by putting headers for them in the ``.pxd`` file, for
example: example:
:file:`volume.pxd`:: :file:`volume.pxd`:
cdef float cube(float)
:file:`volume.pyx`:: .. literalinclude:: ../../examples/userguide/sharing_declarations/volume.pxd
cdef float cube(float x): :file:`volume.pyx`:
return x * x * x
:file:`spammery.pyx`:: .. literalinclude:: ../../examples/userguide/sharing_declarations/volume.pyx
from __future__ import print_function :file:`spammery.pyx`:
from volume cimport cube .. literalinclude:: ../../examples/userguide/sharing_declarations/spammery.pyx
def menu(description, size):
print(description, ":", cube(size),
"cubic metres of spam")
menu("Entree", 1)
menu("Main course", 3)
menu("Dessert", 2)
.. note:: .. note::
...@@ -203,6 +173,7 @@ example: ...@@ -203,6 +173,7 @@ example:
this object from Python, nor can you use it from Cython using a normal import this object from Python, nor can you use it from Cython using a normal import
statement; you have to use :keyword:`cimport`. statement; you have to use :keyword:`cimport`.
.. _sharing_extension_types:
Sharing Extension Types Sharing Extension Types
======================= =======================
...@@ -222,38 +193,23 @@ Python methods. ...@@ -222,38 +193,23 @@ Python methods.
Here is an example of a module which defines and exports an extension type, Here is an example of a module which defines and exports an extension type,
and another module which uses it: and another module which uses it:
:file:`Shrubbing.pxd`:: :file:`shrubbing.pxd`:
cdef class Shrubbery:
cdef int width
cdef int length
:file:`Shrubbing.pyx`::
cdef class Shrubbery: .. literalinclude:: ../../examples/userguide/sharing_declarations/shrubbing.pxd
def __cinit__(self, int w, int l):
self.width = w
self.length = l
def standard_shrubbery(): :file:`shrubbing.pyx`:
return Shrubbery(3, 7)
:file:`Landscaping.pyx`:: .. literalinclude:: ../../examples/userguide/sharing_declarations/shrubbing.pyx
cimport Shrubbing :file:`landscaping.pyx`:
import Shrubbing
cdef Shrubbing.Shrubbery sh .. literalinclude:: ../../examples/userguide/sharing_declarations/landscaping.pyx
sh = Shrubbing.standard_shrubbery()
print("Shrubbery size is %d x %d" % (sh.width, sh.length))
One would then need to compile both of these modules, e.g. using One would then need to compile both of these modules, e.g. using
:file:`setup.py`:: :file:`setup.py`:
from distutils.core import setup .. literalinclude:: ../../examples/userguide/sharing_declarations/setup.py
from Cython.Build import cythonize
setup(ext_modules = cythonize(["Landscaping.pyx", "Shrubbing.pyx"]))
Some things to note about this example: Some things to note about this example:
......
...@@ -75,8 +75,6 @@ them through :func:`cythonize`:: ...@@ -75,8 +75,6 @@ them through :func:`cythonize`::
) )
.. _pyximport:
Pyximport Pyximport
=========== ===========
...@@ -107,51 +105,4 @@ on end user side as it hooks into their import system. The best way ...@@ -107,51 +105,4 @@ on end user side as it hooks into their import system. The best way
to cater for end users is to provide pre-built binary packages in the to cater for end users is to provide pre-built binary packages in the
`wheel <https://wheel.readthedocs.io/>`_ packaging format. `wheel <https://wheel.readthedocs.io/>`_ packaging format.
Arguments To have more information of :mod:`pyximport`, please refer to :ref:`pyximport`.
--------- \ No newline at end of file
The function ``pyximport.install()`` can take several arguments to
influence the compilation of Cython or Python files.
.. autofunction:: pyximport.install
Dependency Handling
--------------------
Since :mod:`pyximport` does not use `cythonize()` internally, it currently
requires a different setup for dependencies. It is possible to declare that
your module depends on multiple files, (likely ``.h`` and ``.pxd`` files).
If your Cython module is named ``foo`` and thus has the filename
:file:`foo.pyx` then you should create another file in the same directory
called :file:`foo.pyxdep`. The :file:`modname.pyxdep` file can be a list of
filenames or "globs" (like ``*.pxd`` or ``include/*.h``). Each filename or
glob must be on a separate line. Pyximport will check the file date for each
of those files before deciding whether to rebuild the module. In order to
keep track of the fact that the dependency has been handled, Pyximport updates
the modification time of your ".pyx" source file. Future versions may do
something more sophisticated like informing distutils of the dependencies
directly.
Limitations
------------
Pyximport does not give you any control over how your Cython file is
compiled. Usually the defaults are fine. You might run into problems if
you wanted to write your program in half-C, half-Cython and build them
into a single library.
Pyximport does not hide the Distutils/GCC warnings and errors generated
by the import process. Arguably this will give you better feedback if
something went wrong and why. And if nothing went wrong it will give you
the warm fuzzy feeling that pyximport really did rebuild your module as it
was supposed to.
Basic module reloading support is available with the option ``reload_support=True``.
Note that this will generate a new module filename for each build and thus
end up loading multiple shared libraries into memory over time. CPython does
not support reloading shared libraries as such.
Pyximport puts both your ``.c`` file and the platform-specific binary into
a separate build directory, usually ``$HOME/.pyxblx/``. To copy it back
into the package hierarchy (usually next to the source file) for manual
reuse, you can pass the option ``inplace=True``.
...@@ -185,6 +185,8 @@ method called :meth:`__next__`, not next. The Python system will automatically ...@@ -185,6 +185,8 @@ method called :meth:`__next__`, not next. The Python system will automatically
supply a next method which calls your :meth:`__next__`. Do *NOT* explicitly supply a next method which calls your :meth:`__next__`. Do *NOT* explicitly
give your type a :meth:`next` method, or bad things could happen. give your type a :meth:`next` method, or bad things could happen.
.. _special_methods_table:
Special Method Table Special Method Table
--------------------- ---------------------
...@@ -241,6 +243,8 @@ like :meth:`__eq__` or the single special method :meth:`__richcmp__`. ...@@ -241,6 +243,8 @@ like :meth:`__eq__` or the single special method :meth:`__richcmp__`.
Depending on the application, one way or the other may be better. Depending on the application, one way or the other may be better.
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+ +-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| Name | Parameters | Return type | Description |
+=======================+=======================================+=============+========================================================+
| __eq__ |self, y | object | self == y | | __eq__ |self, y | object | self == y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+ +-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __ne__ |self, y | object | self != y (falls back to ``__eq__`` if not available) | | __ne__ |self, y | object | self != y (falls back to ``__eq__`` if not available) |
......
...@@ -252,25 +252,12 @@ themselves:: ...@@ -252,25 +252,12 @@ themselves::
Nested class declarations Nested class declarations
-------------------------- --------------------------
C++ allows nested class declaration. Class declarations can also be C++ allows nested class declaration. Class declarations can also be
nested in Cython:: nested in Cython:
cdef extern from "<vector>" namespace "std": .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/nested_class.pyx
cdef cppclass vector[T]:
cppclass iterator: Note that the nested class is declared with a ``cppclass`` but without a ``cdef``,
T operator*() as it is already part of a ``cdef`` declaration section.
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
vector()
void push_back(T&)
T& operator[](int)
T& at(int)
iterator begin()
iterator end()
cdef vector[int].iterator iter #iter is declared as being of type vector<int>::iterator
Note that the nested class is declared with a ``cppclass`` but without a ``cdef``.
C++ operators not compatible with Python syntax C++ operators not compatible with Python syntax
------------------------------------------------ ------------------------------------------------
...@@ -299,36 +286,9 @@ which can also be written ``&foo``. ...@@ -299,36 +286,9 @@ which can also be written ``&foo``.
Templates Templates
---------- ----------
Cython uses a bracket syntax for templating. A simple example for wrapping C++ vector:: Cython uses a bracket syntax for templating. A simple example for wrapping C++ vector:
# import dereference and increment operators .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/templates.pyx
from cython.operator cimport dereference as deref, preincrement as inc
cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]:
cppclass iterator:
T operator*()
iterator operator++()
bint operator==(iterator)
bint operator!=(iterator)
vector()
void push_back(T&)
T& operator[](int)
T& at(int)
iterator begin()
iterator end()
cdef vector[int] *v = new vector[int]()
cdef int i
for i in range(10):
v.push_back(i)
cdef vector[int].iterator it = v.begin()
while it != v.end():
print(deref(it))
inc(it)
del v
Multiple template parameters can be defined as a list, such as ``[T, U, V]`` Multiple template parameters can be defined as a list, such as ``[T, U, V]``
or ``[int, bool, char]``. Optional template parameters can be indicated or ``[int, bool, char]``. Optional template parameters can be indicated
...@@ -339,55 +299,33 @@ a typedef for its template parameters it is preferable to use that name here. ...@@ -339,55 +299,33 @@ a typedef for its template parameters it is preferable to use that name here.
Template functions are defined similarly to class templates, with Template functions are defined similarly to class templates, with
the template parameter list following the function name:: the template parameter list following the function name:
cdef extern from "<algorithm>" namespace "std":
T max[T](T a, T b)
print(max[long](3, 4)) .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/function_template.pyx
print(max(1.5, 2.5)) # simple template argument deduction
Standard library Standard library
----------------- -----------------
Most of the containers of the C++ Standard Library have been declared Most of the containers of the C++ Standard Library have been declared
in pxd files located in ``/Cython/Includes/libcpp``. These containers in pxd files located
are: deque, list, map, pair, queue, set, stack, vector. in `/Cython/Includes/libcpp <https://github.com/cython/cython/tree/master/Cython/Includes/libcpp>`_.
These containers are: deque, list, map, pair, queue, set, stack, vector.
For example:: For example:
from libcpp.vector cimport vector .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/vector_demo.pyx
cdef vector[int] vect The pxd files
cdef int i, x in `/Cython/Includes/libcpp <https://github.com/cython/cython/tree/master/Cython/Includes/libcpp>`_
for i in range(10): also work as good examples on how to declare C++ classes.
vect.push_back(i)
for i in range(10):
print(vect[i])
for x in vect:
print(x)
The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on The STL containers coerce from and to the
how to declare C++ classes.
Since Cython 0.17, the STL containers coerce from and to the
corresponding Python builtin types. The conversion is triggered corresponding Python builtin types. The conversion is triggered
either by an assignment to a typed variable (including typed function either by an assignment to a typed variable (including typed function
arguments) or by an explicit cast, e.g.:: arguments) or by an explicit cast, e.g.:
from libcpp.string cimport string
from libcpp.vector cimport vector
cdef string s = py_bytes_object
print(s)
cpp_string = <string> py_unicode_object.encode('utf-8')
cdef vector[int] vect = xrange(1, 10, 2) .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/python_to_cpp.pyx
print(vect) # [1, 3, 5, 7, 9]
cdef vector[string] cpp_strings = b'ab cd ef gh'.split()
print(cpp_strings[1]) # b'cd'
The following coercions are available: The following coercions are available:
...@@ -413,16 +351,21 @@ inside of containers, e.g. a C++ vector of maps of strings. ...@@ -413,16 +351,21 @@ inside of containers, e.g. a C++ vector of maps of strings.
Iteration over stl containers (or indeed any class with ``begin()`` and Iteration over stl containers (or indeed any class with ``begin()`` and
``end()`` methods returning an object supporting incrementing, dereferencing, ``end()`` methods returning an object supporting incrementing, dereferencing,
and comparison) is supported via the ``for .. in`` syntax (including in list and comparison) is supported via the ``for .. in`` syntax (including in list
comprehensions). For example, one can write:: comprehensions). For example, one can write:
cdef vector[int] v = ... .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/iterate.pyx
for value in v:
f(value)
return [x*x for x in v if x % 2 == 0]
If the loop target variable is unspecified, an assignment from type If the loop target variable is unspecified, an assignment from type
``*container.begin()`` is used for :ref:`type inference <compiler-directives>`. ``*container.begin()`` is used for :ref:`type inference <compiler-directives>`.
.. note::
Slicing stl containers is supported,
you can do ``for x in my_vector[:5]: ...`` but unlike pointers slices,
it will create a temporary Python object and iterate over it. Thus
making the iteration very slow. You might want to avoid slicing
C++ containers for performance reasons.
Simplified wrapping with default constructor Simplified wrapping with default constructor
-------------------------------------------- --------------------------------------------
...@@ -430,20 +373,9 @@ Simplified wrapping with default constructor ...@@ -430,20 +373,9 @@ Simplified wrapping with default constructor
If your extension type instantiates a wrapped C++ class using the default If your extension type instantiates a wrapped C++ class using the default
constructor (not passing any arguments), you may be able to simplify the constructor (not passing any arguments), you may be able to simplify the
lifecycle handling by tying it directly to the lifetime of the Python wrapper lifecycle handling by tying it directly to the lifetime of the Python wrapper
object. Instead of a pointer attribute, you can declare an instance:: object. Instead of a pointer attribute, you can declare an instance:
cdef class VectorStack:
cdef vector[int] v
def push(self, x):
self.v.push_back(x)
def pop(self): .. literalinclude:: ../../examples/userguide/wrapping_CPlusPlus/wrapper_vector.pyx
if self.v.empty():
raise IndexError()
x = self.v.back()
self.v.pop_back()
return x
Cython will automatically generate code that instantiates the C++ object Cython will automatically generate code that instantiates the C++ object
instance when the Python object is created and deletes it when the Python instance when the Python object is created and deletes it when the Python
...@@ -598,7 +530,8 @@ possible to declare them in the :file:`setup.py` file:: ...@@ -598,7 +530,8 @@ possible to declare them in the :file:`setup.py` file::
Cython will generate and compile the :file:`rect.cpp` file (from Cython will generate and compile the :file:`rect.cpp` file (from
:file:`rect.pyx`), then it will compile :file:`Rectangle.cpp` :file:`rect.pyx`), then it will compile :file:`Rectangle.cpp`
(implementation of the ``Rectangle`` class) and link both object files (implementation of the ``Rectangle`` class) and link both object files
together into :file:`rect.so`, which you can then import in Python using together into :file:`rect.so` on Linux, or :file:`rect.pyd` on windows,
which you can then import in Python using
``import rect`` (if you forget to link the :file:`Rectangle.o`, you will ``import rect`` (if you forget to link the :file:`Rectangle.o`, you will
get missing symbols while importing the library in Python). get missing symbols while importing the library in Python).
......
...@@ -618,7 +618,7 @@ class TestBuilder(object): ...@@ -618,7 +618,7 @@ class TestBuilder(object):
test_class = CythonUnitTestCase test_class = CythonUnitTestCase
else: else:
test_class = CythonRunTestCase test_class = CythonRunTestCase
elif mode in ['compile', 'error', 'test']: elif mode in ['compile', 'error']:
test_class = CythonCompileTestCase test_class = CythonCompileTestCase
else: else:
raise KeyError('Invalid test mode: ' + mode) raise KeyError('Invalid test mode: ' + mode)
......
...@@ -85,20 +85,20 @@ def compile_cython_modules(profile=False, compile_more=False, cython_with_refnan ...@@ -85,20 +85,20 @@ def compile_cython_modules(profile=False, compile_more=False, cython_with_refnan
compiled_modules = [ compiled_modules = [
"Cython.Plex.Scanners", "Cython.Plex.Scanners",
"Cython.Plex.Actions", "Cython.Plex.Actions",
"Cython.Compiler.Pythran",
"Cython.Compiler.Lexicon",
"Cython.Compiler.Scanning", "Cython.Compiler.Scanning",
"Cython.Compiler.Parsing",
"Cython.Compiler.Visitor", "Cython.Compiler.Visitor",
"Cython.Compiler.FlowControl", "Cython.Compiler.FlowControl",
"Cython.Compiler.Code",
"Cython.Runtime.refnanny", "Cython.Runtime.refnanny",
"Cython.Compiler.FusedNode", "Cython.Compiler.FusedNode",
"Cython.Tempita._tempita", "Cython.Tempita._tempita",
"Cython.StringIOTree",
] ]
if compile_more: if compile_more:
compiled_modules.extend([ compiled_modules.extend([
"Cython.StringIOTree",
"Cython.Compiler.Code",
"Cython.Compiler.Lexicon",
"Cython.Compiler.Parsing",
"Cython.Compiler.Pythran",
"Cython.Build.Dependencies", "Cython.Build.Dependencies",
"Cython.Compiler.ParseTreeTransforms", "Cython.Compiler.ParseTreeTransforms",
"Cython.Compiler.Nodes", "Cython.Compiler.Nodes",
......
PYTHON -c "import cythonize_tests"
PYTHON -c "import cython_tests"
######## cythonize_tests.py ########
from Cython.Build.Cythonize import main as cythonize
for test_case in ["cython.pyx", "src/cython.pyx", "src2/cython.pyx"]:
try:
cythonize([test_case])
except ValueError:
pass
else:
assert False, "ValueError not raised - forbidding cythonize "+test_case+" doesn't work"
try:
cythonize(["notcython.pys"])
except ValueError:
assert False, "ValueError raised - forbidding cythonize notcython.pyx should work"
else:
pass
######## cython_tests.py ########
from Cython.Compiler.Main import main as cython
import sys
for test_case in ["cython.pyx", "src/cython.pyx", "src2/cython.pyx"]:
sys.argv=["cython", test_case] #cython.py will extract parameters from sys.argv
try:
cython(command_line=1)
except ValueError:
pass
else:
assert False, "ValueError not raised - forbidding cython "+test_case+" doesn't work"
sys.argv=["cython", "notcython.pyx"] #cython.py will extract parameters from sys.argv
try:
cython(["notcython.pys"])
except ValueError:
assert False, "ValueError raised - forbidding cythonize notcython.pyx should work"
else:
pass
######## cython.pyx ########
######## src/__init__.py ########
######## src/cython.pyx ########
######## notcython.pyx ########
######## src2/cython.pyx ########
# mode: run
# tag: cpp, werror, cpp11
from cython.operator cimport dereference as deref
from cython.operator cimport preincrement as incr
from libcpp.forward_list cimport forward_list
from libcpp cimport bool as cbool
def simple_iteration_test(L):
"""
>>> iteration_test([1,2,4,8])
8
4
2
1
>>> iteration_test([8,4,2,1])
1
2
4
8
"""
cdef forward_list[int] l
for a in L:
l.push_front(a)
for a in l:
print(a)
def iteration_test(L):
"""
>>> iteration_test([1,2,4,8])
8
4
2
1
>>> iteration_test([8,4,2,1])
1
2
4
8
"""
l = new forward_list[int]()
try:
for a in L:
l.push_front(a)
it = l.begin()
while it != l.end():
a = deref(it)
incr(it)
print(a)
finally:
del l
def test_value_type(x):
"""
>>> test_value_type(2)
2.0
>>> test_value_type(2.5)
2.5
"""
cdef forward_list[double].value_type val = x
return val
def test_value_type_complex(x):
"""
>>> test_value_type_complex(2)
(2+0j)
"""
cdef forward_list[double complex].value_type val = x
return val
# Tests GitHub issue #1788.
cdef cppclass MyForwardList[T](forward_list):
pass
cdef cppclass Ints(MyForwardList[int]):
pass
...@@ -898,4 +898,33 @@ def test_copy_buffer(np.ndarray[double, ndim=1] a): ...@@ -898,4 +898,33 @@ def test_copy_buffer(np.ndarray[double, ndim=1] a):
return a return a
@testcase
def test_broadcast_comparison(np.ndarray[double, ndim=1] a):
"""
>>> a = np.ones(10, dtype=np.double)
>>> a0, obj0, a1, obj1 = test_broadcast_comparison(a)
>>> np.all(a0 == (a == 0)) or a0
True
>>> np.all(a1 == (a == 1)) or a1
True
>>> np.all(obj0 == (a == 0)) or obj0
True
>>> np.all(obj1 == (a == 1)) or obj1
True
>>> a = np.zeros(10, dtype=np.double)
>>> a0, obj0, a1, obj1 = test_broadcast_comparison(a)
>>> np.all(a0 == (a == 0)) or a0
True
>>> np.all(a1 == (a == 1)) or a1
True
>>> np.all(obj0 == (a == 0)) or obj0
True
>>> np.all(obj1 == (a == 1)) or obj1
True
"""
cdef object obj = a
return a == 0, obj == 0, a == 1, obj == 1
include "numpy_common.pxi" include "numpy_common.pxi"
...@@ -22,7 +22,7 @@ def test_itimer(sec, usec): ...@@ -22,7 +22,7 @@ def test_itimer(sec, usec):
t.it_value.tv_sec = 0 t.it_value.tv_sec = 0
t.it_value.tv_usec = 0 t.it_value.tv_usec = 0
ret = setitimer(ITIMER_REAL, &t, NULL) ret = setitimer(ITIMER_REAL, &t, NULL)
return gtime.it_interval.tv_sec, gtime.it_interval.tv_usec return int(gtime.it_interval.tv_sec), int(gtime.it_interval.tv_usec)
def test_gettimeofday(): def test_gettimeofday():
""" """
......
# mode: test # mode: run
def f(x, y): def f(x, y):
x = y x = y
......
...@@ -58,6 +58,36 @@ def single_except_expression(a, x): ...@@ -58,6 +58,36 @@ def single_except_expression(a, x):
i = 3 i = 3
return i return i
exceptions = (ValueError, TypeError)
def single_except_global_tuple(x):
"""
>>> single_except_global_tuple(None)
2
>>> single_except_global_tuple(ValueError('test'))
3
>>> single_except_global_tuple(TypeError('test'))
3
>>> class TypeErrorSubtype(TypeError): pass
>>> single_except_global_tuple(TypeErrorSubtype('test'))
3
>>> single_except_global_tuple(AttributeError('test'))
Traceback (most recent call last):
AttributeError: test
"""
cdef int i
try:
i = 1
if x:
raise x
i = 2
except exceptions:
i = 3
return i
def double_except_no_raise(a,b): def double_except_no_raise(a,b):
""" """
>>> double_except_no_raise(TypeError, ValueError) >>> double_except_no_raise(TypeError, ValueError)
...@@ -179,6 +209,10 @@ def normal_and_bare_except_raise(x, a): ...@@ -179,6 +209,10 @@ def normal_and_bare_except_raise(x, a):
2 2
>>> normal_and_bare_except_raise(ValueError('test'), TypeError) >>> normal_and_bare_except_raise(ValueError('test'), TypeError)
3 3
>>> normal_and_bare_except_raise(TypeError('test'), (TypeError, ValueError))
2
>>> normal_and_bare_except_raise(ValueError('test'), (TypeError, ValueError))
2
>>> normal_and_bare_except_raise(None, TypeError) >>> normal_and_bare_except_raise(None, TypeError)
1 1
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment