Commit ae714eac authored by Stefan Behnel's avatar Stefan Behnel

merged in latest cython-devel

parents 91d8ecbc d0d88e68
...@@ -27,8 +27,6 @@ Options: ...@@ -27,8 +27,6 @@ Options:
-z, --pre-import <module> If specified, assume undeclared names in this -z, --pre-import <module> If specified, assume undeclared names in this
module. Emulates the behavior of putting module. Emulates the behavior of putting
"from <module> import *" at the top of the file. "from <module> import *" at the top of the file.
--incref-local-binop Force local an extra incref on local variables before
performing any binary operations.
--cleanup <level> Release interned objects on python exit, for memory debugging. --cleanup <level> Release interned objects on python exit, for memory debugging.
Level indicates aggressiveness, default 0 releases nothing. Level indicates aggressiveness, default 0 releases nothing.
-w, --working <directory> Sets the working directory for Cython (the directory modules -w, --working <directory> Sets the working directory for Cython (the directory modules
...@@ -108,8 +106,6 @@ def parse_command_line(args): ...@@ -108,8 +106,6 @@ def parse_command_line(args):
Options.embed_pos_in_docstring = 1 Options.embed_pos_in_docstring = 1
elif option in ("-z", "--pre-import"): elif option in ("-z", "--pre-import"):
Options.pre_import = pop_arg() Options.pre_import = pop_arg()
elif option == "--incref-local-binop":
Options.incref_local_binop = 1
elif option == "--cleanup": elif option == "--cleanup":
Options.generate_cleanup_code = int(pop_arg()) Options.generate_cleanup_code = int(pop_arg())
elif option in ("-D", "--no-docstrings"): elif option in ("-D", "--no-docstrings"):
......
...@@ -1518,22 +1518,24 @@ class IteratorNode(ExprNode): ...@@ -1518,22 +1518,24 @@ class IteratorNode(ExprNode):
def generate_result_code(self, code): def generate_result_code(self, code):
is_builtin_sequence = self.sequence.type is list_type or \ is_builtin_sequence = self.sequence.type is list_type or \
self.sequence.type is tuple_type self.sequence.type is tuple_type
may_be_a_sequence = is_builtin_sequence or not self.sequence.type.is_builtin_type
if is_builtin_sequence: if is_builtin_sequence:
code.putln( code.putln(
"if (likely(%s != Py_None)) {" % self.sequence.py_result()) "if (likely(%s != Py_None)) {" % self.sequence.py_result())
else: elif may_be_a_sequence:
code.putln( code.putln(
"if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % ( "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
self.sequence.py_result(), self.sequence.py_result(),
self.sequence.py_result())) self.sequence.py_result()))
code.putln( if may_be_a_sequence:
"%s = 0; %s = %s; __Pyx_INCREF(%s);" % ( code.putln(
self.counter_cname, "%s = 0; %s = %s; __Pyx_INCREF(%s);" % (
self.result(), self.counter_cname,
self.sequence.py_result(), self.result(),
self.result())) self.sequence.py_result(),
code.putln("} else {") self.result()))
code.putln("} else {")
if is_builtin_sequence: if is_builtin_sequence:
code.putln( code.putln(
'PyErr_SetString(PyExc_TypeError, "\'NoneType\' object is not iterable"); %s' % 'PyErr_SetString(PyExc_TypeError, "\'NoneType\' object is not iterable"); %s' %
...@@ -1545,7 +1547,8 @@ class IteratorNode(ExprNode): ...@@ -1545,7 +1547,8 @@ class IteratorNode(ExprNode):
self.sequence.py_result(), self.sequence.py_result(),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
code.putln("}") if may_be_a_sequence:
code.putln("}")
class NextNode(AtomicExprNode): class NextNode(AtomicExprNode):
...@@ -1564,12 +1567,15 @@ class NextNode(AtomicExprNode): ...@@ -1564,12 +1567,15 @@ class NextNode(AtomicExprNode):
self.is_temp = 1 self.is_temp = 1
def generate_result_code(self, code): def generate_result_code(self, code):
if self.iterator.sequence.type is list_type: sequence_type = self.iterator.sequence.type
if sequence_type is list_type:
type_checks = [(list_type, "List")] type_checks = [(list_type, "List")]
elif self.iterator.sequence.type is tuple_type: elif sequence_type is tuple_type:
type_checks = [(tuple_type, "Tuple")] type_checks = [(tuple_type, "Tuple")]
else: elif not sequence_type.is_builtin_type:
type_checks = [(list_type, "List"), (tuple_type, "Tuple")] type_checks = [(list_type, "List"), (tuple_type, "Tuple")]
else:
type_checks = []
for py_type, prefix in type_checks: for py_type, prefix in type_checks:
if len(type_checks) > 1: if len(type_checks) > 1:
...@@ -1781,6 +1787,12 @@ class IndexNode(ExprNode): ...@@ -1781,6 +1787,12 @@ class IndexNode(ExprNode):
self.is_buffer_access = False self.is_buffer_access = False
self.base.analyse_types(env) self.base.analyse_types(env)
if self.base.type.is_error:
# Do not visit child tree if base is undeclared to avoid confusing
# error messages
self.type = PyrexTypes.error_type
return
# Handle the case where base is a literal char* (and we expect a string, not an int) # Handle the case where base is a literal char* (and we expect a string, not an int)
if isinstance(self.base, BytesNode): if isinstance(self.base, BytesNode):
self.base = self.base.coerce_to_pyobject(env) self.base = self.base.coerce_to_pyobject(env)
...@@ -3086,7 +3098,7 @@ class AttributeNode(ExprNode): ...@@ -3086,7 +3098,7 @@ class AttributeNode(ExprNode):
self.put_nonecheck(code) self.put_nonecheck(code)
select_code = self.result() select_code = self.result()
if self.type.is_pyobject: if self.type.is_pyobject and self.use_managed_ref:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
code.put_giveref(rhs.py_result()) code.put_giveref(rhs.py_result())
code.put_gotref(select_code) code.put_gotref(select_code)
...@@ -4541,8 +4553,6 @@ class BinopNode(ExprNode): ...@@ -4541,8 +4553,6 @@ class BinopNode(ExprNode):
self.coerce_operands_to_pyobjects(env) self.coerce_operands_to_pyobjects(env)
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
if Options.incref_local_binop and self.operand1.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_temp(env)
else: else:
self.analyse_c_operation(env) self.analyse_c_operation(env)
......
...@@ -138,7 +138,7 @@ class Context(object): ...@@ -138,7 +138,7 @@ class Context(object):
IntroduceBufferAuxiliaryVars(self), IntroduceBufferAuxiliaryVars(self),
_check_c_declarations, _check_c_declarations,
AnalyseExpressionsTransform(self), AnalyseExpressionsTransform(self),
OptimizeBuiltinCalls(), OptimizeBuiltinCalls(self),
IterationTransform(), IterationTransform(),
SwitchTransform(), SwitchTransform(),
DropRefcountingTransform(), DropRefcountingTransform(),
......
...@@ -2515,13 +2515,30 @@ refnanny_utility_code = UtilityCode(proto=""" ...@@ -2515,13 +2515,30 @@ refnanny_utility_code = UtilityCode(proto="""
main_method = UtilityCode( main_method = UtilityCode(
impl = """ impl = """
#if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS)) #ifdef __FreeBSD__
#include <floatingpoint.h>
#endif
#if PY_MAJOR_VERSION < 3
int main(int argc, char** argv) { int main(int argc, char** argv) {
#else #elif defined(WIN32) || defined(MS_WINDOWS)
int wmain(int argc, wchar_t **argv) { int wmain(int argc, wchar_t **argv) {
#else
static int __Pyx_main(int argc, wchar_t **argv) {
#endif #endif
int r = 0; int r = 0;
PyObject* m = NULL; PyObject* m = NULL;
/* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP
* exceptions by default. Here we disable them.
*/
#ifdef __FreeBSD__
fp_except_t m;
m = fpgetmask();
fpsetmask(m & ~FP_X_OFL);
#endif
Py_SetProgramName(argv[0]); Py_SetProgramName(argv[0]);
Py_Initialize(); Py_Initialize();
PySys_SetArgv(argc, argv); PySys_SetArgv(argc, argv);
...@@ -2529,17 +2546,157 @@ int wmain(int argc, wchar_t **argv) { ...@@ -2529,17 +2546,157 @@ int wmain(int argc, wchar_t **argv) {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
init%(module_name)s(); init%(module_name)s();
#else #else
m = PyInit_%(module_name)s(name); m = PyInit_%(module_name)s();
#endif #endif
if (PyErr_Occurred() != NULL) { if (PyErr_Occurred() != NULL) {
r = 1; r = 1;
PyErr_Print(); /* This exits with the right code if SystemExit. */ PyErr_Print(); /* This exits with the right code if SystemExit. */
#if PY_MAJOR_VERSION < 3
if (Py_FlushLine()) PyErr_Clear(); if (Py_FlushLine()) PyErr_Clear();
#endif
} }
Py_XDECREF(m); Py_XDECREF(m);
Py_Finalize(); Py_Finalize();
return r; return r;
} }
#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS)
#include <locale.h>
static wchar_t*
__Pyx_char2wchar(char* arg)
{
wchar_t *res;
#ifdef HAVE_BROKEN_MBSTOWCS
/* Some platforms have a broken implementation of
* mbstowcs which does not count the characters that
* would result from conversion. Use an upper bound.
*/
size_t argsize = strlen(arg);
#else
size_t argsize = mbstowcs(NULL, arg, 0);
#endif
size_t count;
unsigned char *in;
wchar_t *out;
#ifdef HAVE_MBRTOWC
mbstate_t mbs;
#endif
if (argsize != (size_t)-1) {
res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t));
if (!res)
goto oom;
count = mbstowcs(res, arg, argsize+1);
if (count != (size_t)-1) {
wchar_t *tmp;
/* Only use the result if it contains no
surrogate characters. */
for (tmp = res; *tmp != 0 &&
(*tmp < 0xd800 || *tmp > 0xdfff); tmp++)
;
if (*tmp == 0)
return res;
}
free(res);
}
/* Conversion failed. Fall back to escaping with surrogateescape. */
#ifdef HAVE_MBRTOWC
/* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
/* Overallocate; as multi-byte characters are in the argument, the
actual output could use less memory. */
argsize = strlen(arg) + 1;
res = malloc(argsize*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
memset(&mbs, 0, sizeof mbs);
while (argsize) {
size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
if (converted == 0)
/* Reached end of string; null char stored. */
break;
if (converted == (size_t)-2) {
/* Incomplete character. This should never happen,
since we provide everything that we have -
unless there is a bug in the C library, or I
misunderstood how mbrtowc works. */
fprintf(stderr, "unexpected mbrtowc result -2\\n");
return NULL;
}
if (converted == (size_t)-1) {
/* Conversion error. Escape as UTF-8b, and start over
in the initial shift state. */
*out++ = 0xdc00 + *in++;
argsize--;
memset(&mbs, 0, sizeof mbs);
continue;
}
if (*out >= 0xd800 && *out <= 0xdfff) {
/* Surrogate character. Escape the original
byte sequence with surrogateescape. */
argsize -= converted;
while (converted--)
*out++ = 0xdc00 + *in++;
continue;
}
/* successfully converted some bytes */
in += converted;
argsize -= converted;
out++;
}
#else
/* Cannot use C locale for escaping; manually escape as if charset
is ASCII (i.e. escape all bytes > 128. This will still roundtrip
correctly in the locale's charset, which must be an ASCII superset. */
res = malloc((strlen(arg)+1)*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
while(*in)
if(*in < 128)
*out++ = *in++;
else
*out++ = 0xdc00 + *in++;
*out = 0;
#endif
return res;
oom:
fprintf(stderr, "out of memory\\n");
return NULL;
}
int
main(int argc, char **argv)
{
wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
/* We need a second copies, as Python might modify the first one. */
wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
int i, res;
char *oldloc;
if (!argv_copy || !argv_copy2) {
fprintf(stderr, "out of memory\\n");
return 1;
}
oldloc = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
argv_copy2[i] = argv_copy[i] = __Pyx_char2wchar(argv[i]);
if (!argv_copy[i])
return 1;
}
setlocale(LC_ALL, oldloc);
free(oldloc);
res = __Pyx_main(argc, argv_copy);
for (i = 0; i < argc; i++) {
free(argv_copy2[i]);
}
free(argv_copy);
free(argv_copy2);
return res;
}
#endif
""") """)
packed_struct_utility_code = UtilityCode(proto=""" packed_struct_utility_code = UtilityCode(proto="""
......
...@@ -3165,8 +3165,6 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -3165,8 +3165,6 @@ class InPlaceAssignmentNode(AssignmentNode):
self.dup = self.create_dup_node(env) # re-assigns lhs to a shallow copy self.dup = self.create_dup_node(env) # re-assigns lhs to a shallow copy
self.rhs.analyse_types(env) self.rhs.analyse_types(env)
self.lhs.analyse_target_types(env) self.lhs.analyse_target_types(env)
if Options.incref_local_binop and self.dup.type.is_pyobject:
self.dup = self.dup.coerce_to_temp(env)
import ExprNodes import ExprNodes
if self.lhs.type.is_pyobject: if self.lhs.type.is_pyobject:
self.rhs = self.rhs.coerce_to_pyobject(env) self.rhs = self.rhs.coerce_to_pyobject(env)
......
This diff is collapsed.
...@@ -10,12 +10,6 @@ gcc_branch_hints = 1 ...@@ -10,12 +10,6 @@ gcc_branch_hints = 1
pre_import = None pre_import = None
docstrings = True docstrings = True
# This is a SAGE-specific option that will
# cause Cython to incref local variables before
# performing a binary operation on them, for
# safe detection of inplace operators.
incref_local_binop = 0
# Decref global variables in this module on exit for garbage collection. # Decref global variables in this module on exit for garbage collection.
# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects # 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects
# Mostly for reducing noise for Valgrind, only executes at process exit # Mostly for reducing noise for Valgrind, only executes at process exit
......
from Cython.Compiler.Visitor import VisitorTransform, CythonTransform, TreeVisitor from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
from Cython.Compiler.Visitor import CythonTransform, EnvTransform
from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import * from Cython.Compiler.ExprNodes import *
...@@ -983,21 +984,6 @@ class GilCheck(VisitorTransform): ...@@ -983,21 +984,6 @@ class GilCheck(VisitorTransform):
return node return node
class EnvTransform(CythonTransform):
"""
This transformation keeps a stack of the environments.
"""
def __call__(self, root):
self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root)
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
return node
class TransformBuiltinMethods(EnvTransform): class TransformBuiltinMethods(EnvTransform):
def visit_SingleAssignmentNode(self, node): def visit_SingleAssignmentNode(self, node):
......
...@@ -621,8 +621,8 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *); ...@@ -621,8 +621,8 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, zero = 0; const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > zero; const int is_unsigned = neg_one > const_zero;
if (sizeof(%(type)s) < sizeof(long)) { if (sizeof(%(type)s) < sizeof(long)) {
long val = __Pyx_PyInt_AsLong(x); long val = __Pyx_PyInt_AsLong(x);
if (unlikely(val != (long)(%(type)s)val)) { if (unlikely(val != (long)(%(type)s)val)) {
...@@ -646,8 +646,8 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *); ...@@ -646,8 +646,8 @@ static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject *);
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) { static INLINE %(type)s __Pyx_PyInt_As%(SignWord)s%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, zero = 0; const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > zero; const int is_unsigned = neg_one > const_zero;
#if PY_VERSION_HEX < 0x03000000 #if PY_VERSION_HEX < 0x03000000
if (likely(PyInt_Check(x))) { if (likely(PyInt_Check(x))) {
long val = PyInt_AS_LONG(x); long val = PyInt_AS_LONG(x);
...@@ -687,8 +687,8 @@ static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *); ...@@ -687,8 +687,8 @@ static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *);
""", """,
impl=""" impl="""
static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) { static INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) {
const %(type)s neg_one = (%(type)s)-1, zero = 0; const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > zero; const int is_unsigned = neg_one > const_zero;
if (sizeof(%(type)s) == sizeof(char)) { if (sizeof(%(type)s) == sizeof(char)) {
if (is_unsigned) if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedChar(x); return (%(type)s)__Pyx_PyInt_AsUnsignedChar(x);
...@@ -734,8 +734,8 @@ static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s); ...@@ -734,8 +734,8 @@ static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s);
""", """,
impl=""" impl="""
static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) { static INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
const %(type)s neg_one = (%(type)s)-1, zero = 0; const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
const int is_unsigned = neg_one > zero; const int is_unsigned = neg_one > const_zero;
if (sizeof(%(type)s) < sizeof(long)) { if (sizeof(%(type)s) < sizeof(long)) {
return PyInt_FromLong((long)val); return PyInt_FromLong((long)val);
} else if (sizeof(%(type)s) == sizeof(long)) { } else if (sizeof(%(type)s) == sizeof(long)) {
...@@ -875,6 +875,7 @@ class CComplexType(CNumericType): ...@@ -875,6 +875,7 @@ class CComplexType(CNumericType):
CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed) CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed)
self.binops = {} self.binops = {}
self.from_parts = "%s_from_parts" % self.specalization_name() self.from_parts = "%s_from_parts" % self.specalization_name()
self.default_value = "%s(0, 0)" % self.from_parts
def __eq__(self, other): def __eq__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType): if isinstance(self, CComplexType) and isinstance(other, CComplexType):
......
...@@ -187,8 +187,8 @@ class FixedSlot(SlotDescriptor): ...@@ -187,8 +187,8 @@ class FixedSlot(SlotDescriptor):
# #
# value string # value string
def __init__(self, slot_name, value, py3k=True): def __init__(self, slot_name, value, py3k=True, py2=True, ifdef=None):
SlotDescriptor.__init__(self, slot_name, py3k=py3k) SlotDescriptor.__init__(self, slot_name, py3k=py3k, py2=py2, ifdef=ifdef)
self.value = value self.value = value
def slot_code(self, scope): def slot_code(self, scope):
...@@ -198,8 +198,8 @@ class FixedSlot(SlotDescriptor): ...@@ -198,8 +198,8 @@ class FixedSlot(SlotDescriptor):
class EmptySlot(FixedSlot): class EmptySlot(FixedSlot):
# Descriptor for a type slot whose value is always 0. # Descriptor for a type slot whose value is always 0.
def __init__(self, slot_name, py3k=True): def __init__(self, slot_name, py3k=True, py2=True, ifdef=None):
FixedSlot.__init__(self, slot_name, "0", py3k=py3k) FixedSlot.__init__(self, slot_name, "0", py3k=py3k, py2=py2, ifdef=ifdef)
class MethodSlot(SlotDescriptor): class MethodSlot(SlotDescriptor):
...@@ -692,6 +692,8 @@ slot_table = ( ...@@ -692,6 +692,8 @@ slot_table = (
EmptySlot("tp_cache"), EmptySlot("tp_cache"),
EmptySlot("tp_subclasses"), EmptySlot("tp_subclasses"),
EmptySlot("tp_weaklist"), EmptySlot("tp_weaklist"),
EmptySlot("tp_del"),
EmptySlot("tp_version_tag", ifdef="PY_VERSION_HEX >= 0x02060000"),
) )
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
......
...@@ -306,6 +306,22 @@ class ScopeTrackingTransform(CythonTransform): ...@@ -306,6 +306,22 @@ class ScopeTrackingTransform(CythonTransform):
def visit_CStructOrUnionDefNode(self, node): def visit_CStructOrUnionDefNode(self, node):
return self.visit_scope(node, 'struct') return self.visit_scope(node, 'struct')
class EnvTransform(CythonTransform):
"""
This transformation keeps a stack of the environments.
"""
def __call__(self, root):
self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root)
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
return node
class RecursiveNodeReplacer(VisitorTransform): class RecursiveNodeReplacer(VisitorTransform):
""" """
Recursively replace all occurrences of a node in a subtree by Recursively replace all occurrences of a node in a subtree by
......
...@@ -26,6 +26,7 @@ cdef extern from "Python.h": ...@@ -26,6 +26,7 @@ cdef extern from "Python.h":
cdef extern from "numpy/arrayobject.h": cdef extern from "numpy/arrayobject.h":
ctypedef Py_intptr_t npy_intp ctypedef Py_intptr_t npy_intp
ctypedef size_t npy_uintp
cdef enum NPY_TYPES: cdef enum NPY_TYPES:
NPY_BOOL NPY_BOOL
...@@ -193,7 +194,7 @@ cdef extern from "numpy/arrayobject.h": ...@@ -193,7 +194,7 @@ cdef extern from "numpy/arrayobject.h":
cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
ndim = PyArray_NDIM(self) ndim = PyArray_NDIM(self)
if sizeof(npy_intp) != sizeof(Py_ssize_t): if sizeof(npy_intp) != sizeof(Py_ssize_t):
copy_shape = 1 copy_shape = 1
else: else:
...@@ -735,7 +736,8 @@ ctypedef double complex complex128_t ...@@ -735,7 +736,8 @@ ctypedef double complex complex128_t
# numpy.int corresponds to 'l' and numpy.long to 'q' # numpy.int corresponds to 'l' and numpy.long to 'q'
ctypedef npy_long int_t ctypedef npy_long int_t
ctypedef npy_longlong long_t ctypedef npy_longlong long_t
ctypedef npy_intp intp_t
ctypedef npy_uintp uintp_t
ctypedef npy_ulong uint_t ctypedef npy_ulong uint_t
ctypedef npy_ulonglong ulong_t ctypedef npy_ulonglong ulong_t
......
# Makefile for creating our standalone Cython program # Makefile for creating our standalone Cython program
PYVERSION=2.3 PYVERSION=$(shell python -c "import sys; print sys.version[:3]")
PYPREFIX=/usr PYPREFIX=$(shell python -c "import sys; print sys.prefix")
INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION) INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION)
embedded: embedded.o embedded: embedded.o
gcc -o $@ $^ -lpython$(PYVERSION) gcc -o $@ $^ -lpython$(PYVERSION)
embedded.o: embedded.c embedded.o: embedded.c
gcc -c $^ $(INCLUDES) gcc -c $^ $(INCLUDES)
embedded.c: embedded.pyx embedded.c: embedded.pyx
@python ../../cython.py --embed embedded.pyx @python ../../cython.py --embed embedded.pyx
all: embedded all: embedded
clean: clean:
@echo Cleaning Demos/embed @echo Cleaning Demos/embed
@rm -f *~ *.o *.so core core.* *.c embedded @rm -f *~ *.o *.so core core.* *.c embedded test.output
test: clean all
./embedded > test.output
python assert_equal.py embedded.output test.output
import sys
if open(sys.argv[1]).read() != open(sys.argv[2]).read():
print "Files differ"
sys.exit(1)
else:
print "Files identical"
__main__
Hi, I'm embedded.
CC = gcc CC = gcc
CYTHON = ./../bin/cython CYTHON = ../../bin/cython
CYTHON_FREEZE = ../../bin/cython_freeze.py CYTHON_FREEZE = ../../bin/cython_freeze
PYTHON = python
RST2HTML = rst2html
CFLAGS = -fPIC -g -O2 -Wall -Wextra PY_LDFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join([g("LINKFORSHARED"), "-L"+g("LIBPL")]) + "\n")')
CPPFLAGS = -I /usr/include/python2.6 PY_CPPFLAGS = $(shell $(PYTHON) -c 'from distutils.sysconfig import *; import sys; sys.stdout.write("-I"+get_python_inc() + "\n")')
LDFLAGS = -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions PY_LDLIBS = $(shell $(PYTHON) -c 'from distutils.sysconfig import get_config_var as g; import sys; sys.stdout.write(" ".join(["-lpython"+g("VERSION"), g("SYSLIBS"), g("LIBS"), g("LOCALMODLIBS")]) + "\n")')
LDLIBS = /usr/lib/python2.6/config/libpython2.6.a \
-lm -ldl -pthread -lutil -lz CFLAGS = -fPIC -fno-strict-aliasing -g -O2 -Wall -Wextra
CPPFLAGS = $(PY_CPPFLAGS)
LDFLAGS = $(PY_LDFLAGS)
LDLIBS = $(PY_LDLIBS)
# Name of executable # Name of executable
TARGET = nCr TARGETS = nCr python
# List of Cython source files, with main module first. # List of Cython source files, with main module first.
CYTHON_SOURCE = combinatorics.pyx cmath.pyx CYTHON_SOURCE = combinatorics.pyx cmath.pyx
CYTHON_SECONDARY = $(CYTHON_SOURCE:.pyx=.c) $(TARGETS:=.c)
all : $(TARGET) all : $(TARGETS)
html : README.html
$(TARGET) : $(TARGET).o $(CYTHON_SOURCE:.pyx=.o) $(TARGETS) : % : %.o $(CYTHON_SOURCE:.pyx=.o)
$(TARGET).c : nCr.c :
$(CYTHON_FREEZE) $(CYTHON_SOURCE:.pyx=) > $@ $(CYTHON_FREEZE) $(CYTHON_SOURCE:.pyx=) > $@
python.c :
$(CYTHON_FREEZE) --pymain $(CYTHON_SOURCE:.pyx=) > $@
%.c : %.pyx %.c : %.pyx
$(CYTHON) $(CYTHONFLAGS) $^ $(CYTHON) $(CYTHONFLAGS) $^
%.html : %.txt
$(RST2HTML) $^ $@
clean: clean:
$(RM) *.o *.c $(TARGET) $(RM) *.o $(CYTHON_SECONDARY) $(TARGETS) README.html
.PHONY: clean .PHONY: clean
.SECONDARY: $(CYTHON_SOURCE:.pyx=.c) .SECONDARY: $(CYTHON_SECONDARY)
NAME NAME
==== ====
cython_freeze.py - create a C file for embedding Cython modules cython_freeze - create a C file for embedding Cython modules
SYNOPSIS SYNOPSIS
======== ========
cython_freeze.py module [...] cython_freeze [-o outfile] [-p] module [...]
DESCRIPTION DESCRIPTION
=========== ===========
**cython_freeze.py** generates a C source file to embed a Python interpreter **cython_freeze** generates a C source file to embed a Python interpreter
with one or more Cython modules built in. This allows one to create a single with one or more Cython modules built in. This allows one to create a single
executable from Cython code, without having to have separate shared objects executable from Cython code, without having to have separate shared objects
for each Cython module. for each Cython module. A major advantage of this approach is that it allows
debuging with gprof(1), which does not work with shared objects.
A major advantage of this approach is that it allows debuging with gprof(1), Unless ``-p`` is given, the first module's ``__name__`` is set to
which does not work with shared objects. ``"__main__"`` and is imported on startup; if ``-p`` is given, a normal Python
interpreter is built, with the given modules built into the binary.
Note that this method differs from ``cython --embed``. The ``--embed`` options Note that this method differs from ``cython --embed``. The ``--embed`` options
modifies the resulting C source file to include a ``main()`` function, so it modifies the resulting C source file to include a ``main()`` function, so it
...@@ -28,10 +30,17 @@ simplicity. This module, on the other hand, can be used with multiple ...@@ -28,10 +30,17 @@ simplicity. This module, on the other hand, can be used with multiple
modules, but it requires another C source file to be created. modules, but it requires another C source file to be created.
OPTIONS
=======
-o FILE, --outfile=FILE write output to FILE instead of standard output
-p, --pymain do not automatically run the first module as __main__
EXAMPLE EXAMPLE
======= =======
In the example directory, there exist two Cython modules: In the Demos/freeze directory, there exist two Cython modules:
cmath.pyx cmath.pyx
A module that interfaces with the -lm library. A module that interfaces with the -lm library.
...@@ -47,12 +56,12 @@ The provided Makefile creates an executable, *nCr*, using combinatorics as the ...@@ -47,12 +56,12 @@ The provided Makefile creates an executable, *nCr*, using combinatorics as the
"main" module. It basically performs the following (ignoring the compiler "main" module. It basically performs the following (ignoring the compiler
flags):: flags)::
$ cython_freeze.py combintorics cmath > nCr.c $ cython_freeze combinatorics cmath > nCr.c
$ cython combinatorics.pyx $ cython combinatorics.pyx
$ cython cmath.pyx $ cython cmath.pyx
$ gcc nCr.c -o nCr.o $ gcc -c nCr.c
$ gcc combinatorics.c -o combinatorics.o $ gcc -c combinatorics.c
$ gcc cmath.c -o cmath.o $ gcc -c cmath.c
$ gcc nCr.o combinatorics.o cmath.o -o nCr $ gcc nCr.o combinatorics.o cmath.o -o nCr
Because the combinatorics module was listed first, its ``__name__`` is set Because the combinatorics module was listed first, its ``__name__`` is set
...@@ -65,7 +74,27 @@ contains a Python interpreter and both Cython modules. :: ...@@ -65,7 +74,27 @@ contains a Python interpreter and both Cython modules. ::
$ ./nCr 15812351235 12 $ ./nCr 15812351235 12
5.10028093999e+113 5.10028093999e+113
You may wish to build a normal Python interpreter, rather than having one
module as "main". This may happen if you want to use your module from an
interactive shell or from another script, yet you still want it statically
linked so you can profile it with gprof. To do this, add the ``--pymain``
flag to ``cython_freeze``. In the Makefile, the *python* executable is built
like this. ::
$ cython_freeze --pymain combinatorics cmath -o python.c
$ gcc -c python.c
$ gcc python.o combinatorics.o cmath.o -o python
Now ``python`` is a normal Python interpreter, but the cmath and combinatorics
modules will be built into the executable. ::
$ ./python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:58:18)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> cmath.factorial(155)
4.7891429014634364e+273
PREREQUISITES PREREQUISITES
......
...@@ -19,6 +19,6 @@ if __name__ == "__main__": ...@@ -19,6 +19,6 @@ if __name__ == "__main__":
import sys import sys
if len(sys.argv) != 2: if len(sys.argv) != 2:
sys.stderr.write("USAGE: %s n\nPrints n!.\n" % sys.argv[0]) sys.stderr.write("USAGE: %s n\nPrints n!.\n" % sys.argv[0])
sys.exit(1) sys.exit(2)
n = map(float, sys.argv[1:]) n, = map(float, sys.argv[1:])
print factorial(n) print factorial(n)
...@@ -9,6 +9,6 @@ if __name__ == "__main__": ...@@ -9,6 +9,6 @@ if __name__ == "__main__":
import sys import sys
if len(sys.argv) != 3: if len(sys.argv) != 3:
sys.stderr.write("USAGE: %s n r\nPrints n-choose-r.\n" % sys.argv[0]) sys.stderr.write("USAGE: %s n r\nPrints n-choose-r.\n" % sys.argv[0])
sys.exit(1) sys.exit(2)
n, r = map(float, sys.argv[1:]) n, r = map(float, sys.argv[1:])
print nCr(n, r) print nCr(n, r)
...@@ -9,13 +9,13 @@ clean: ...@@ -9,13 +9,13 @@ clean:
@echo Cleaning Source @echo Cleaning Source
@rm -fr build @rm -fr build
@rm -f *.pyc */*.pyc */*/*.pyc @rm -f *.pyc */*.pyc */*/*.pyc
@rm -f *.so */*.so */*/*.so
@rm -f *.pyd */*.pyd */*/*.pyd
@rm -f *~ */*~ */*/*~ @rm -f *~ */*~ */*/*~
@rm -f core */core @rm -f core */core
@rm -f Cython/Compiler/Parsing.{c,so,pyd} @rm -f Cython/Compiler/*.c
@rm -f Cython/Compiler/Scanning.{c,so,pyd} @rm -f Cython/Plex/*.c
@rm -f Cython/Compiler/Visitor.{c,so,pyd} @rm -f Cython/Runtime/refnanny.c
@rm -f Cython/Runtime/refnanny.{c,so,pyd}
@rm -f Cython/Plex/Scanners.{c,so,pyd}
@(cd Demos; $(MAKE) clean) @(cd Demos; $(MAKE) clean)
testclean: testclean:
......
This diff is collapsed.
#!/usr/bin/env python
"""
Create a C file for embedding one or more Cython source files.
Requires Cython 0.11.2 (or perhaps newer).
See Demos/freeze/README.txt for more details.
"""
import optparse
usage= '%prog [-o outfile] [-p] module [module ...]'
description = 'Create a C file for embedding Cython modules.'
p = optparse.OptionParser(usage=usage, description=description)
p.add_option('-o', '--output', metavar='FILE',
help='write output to FILE instead of standard output')
p.add_option('-p', '--pymain', action='store_true', default=False,
help='do not automatically run the first module as __main__')
options, args = p.parse_args()
if len(args) < 1:
p.print_help()
p.exit(1)
if options.output:
import sys
old_stdout = sys.stdout
sys.stdout = open(options.output, 'w')
def format_modname(name):
if name.endswith('.pyx'):
name = name[:-4]
elif name.endswith('.py'):
name = name[:-3]
return name.replace('.','_')
modules = [format_modname(x) for x in args]
print """\
#include <Python.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __FreeBSD__
#include <floatingpoint.h>
#endif
#if PY_MAJOR_VERSION < 3
# define MODINIT(name) init ## name
#else
# define MODINIT(name) PyInit_ ## name
#endif
"""
for name in modules:
print "PyMODINIT_FUNC MODINIT(%s) (void);" % name
print """
static struct _inittab inittab[] = {"""
for name in modules:
print ' {"%(name)s", MODINIT(%(name)s)},' % {'name' : name}
print """ {NULL, NULL}
};
""",
if not options.pymain:
print "\nextern int __pyx_module_is_main_%s;" % modules[0]
print """
#if PY_MAJOR_VERSION < 3
int main(int argc, char** argv) {
#elif defined(WIN32) || defined(MS_WINDOWS)
int wmain(int argc, wchar_t **argv) {
#else
static int python_main(int argc, wchar_t **argv) {
#endif
""",
if not options.pymain:
print """\
PyObject *m = NULL;
int r = 0;
""",
print """\
/* 754 requires that FP exceptions run in "no stop" mode by default,
* and until C vendors implement C99's ways to control FP exceptions,
* Python requires non-stop mode. Alas, some platforms enable FP
* exceptions by default. Here we disable them.
*/
#ifdef __FreeBSD__
fp_except_t m;
m = fpgetmask();
fpsetmask(m & ~FP_X_OFL);
#endif
if (PyImport_ExtendInittab(inittab)) {
fprintf(stderr, "No memory\\n");
exit(1);
}
""",
if options.pymain:
print """\
return Py_Main(argc, argv);
}
"""
else:
print """\
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
__pyx_module_is_main_%(main)s = 1;
m = PyImport_ImportModule(inittab[0].name);
if (!m) {
r = 1;
PyErr_Print(); /* This exits with the right code if SystemExit. */
#if PY_MAJOR_VERSION < 3
if (Py_FlushLine())
PyErr_Clear();
#endif
}
Py_XDECREF(m);
Py_Finalize();
return r;
}
""" % {'main' : modules[0]},
print r"""
#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS)
static wchar_t*
char2wchar(char* arg)
{
wchar_t *res;
#ifdef HAVE_BROKEN_MBSTOWCS
/* Some platforms have a broken implementation of
* mbstowcs which does not count the characters that
* would result from conversion. Use an upper bound.
*/
size_t argsize = strlen(arg);
#else
size_t argsize = mbstowcs(NULL, arg, 0);
#endif
size_t count;
unsigned char *in;
wchar_t *out;
#ifdef HAVE_MBRTOWC
mbstate_t mbs;
#endif
if (argsize != (size_t)-1) {
res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t));
if (!res)
goto oom;
count = mbstowcs(res, arg, argsize+1);
if (count != (size_t)-1) {
wchar_t *tmp;
/* Only use the result if it contains no
surrogate characters. */
for (tmp = res; *tmp != 0 &&
(*tmp < 0xd800 || *tmp > 0xdfff); tmp++)
;
if (*tmp == 0)
return res;
}
free(res);
}
/* Conversion failed. Fall back to escaping with surrogateescape. */
#ifdef HAVE_MBRTOWC
/* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
/* Overallocate; as multi-byte characters are in the argument, the
actual output could use less memory. */
argsize = strlen(arg) + 1;
res = malloc(argsize*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
memset(&mbs, 0, sizeof mbs);
while (argsize) {
size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
if (converted == 0)
/* Reached end of string; null char stored. */
break;
if (converted == (size_t)-2) {
/* Incomplete character. This should never happen,
since we provide everything that we have -
unless there is a bug in the C library, or I
misunderstood how mbrtowc works. */
fprintf(stderr, "unexpected mbrtowc result -2\n");
return NULL;
}
if (converted == (size_t)-1) {
/* Conversion error. Escape as UTF-8b, and start over
in the initial shift state. */
*out++ = 0xdc00 + *in++;
argsize--;
memset(&mbs, 0, sizeof mbs);
continue;
}
if (*out >= 0xd800 && *out <= 0xdfff) {
/* Surrogate character. Escape the original
byte sequence with surrogateescape. */
argsize -= converted;
while (converted--)
*out++ = 0xdc00 + *in++;
continue;
}
/* successfully converted some bytes */
in += converted;
argsize -= converted;
out++;
}
#else
/* Cannot use C locale for escaping; manually escape as if charset
is ASCII (i.e. escape all bytes > 128. This will still roundtrip
correctly in the locale's charset, which must be an ASCII superset. */
res = malloc((strlen(arg)+1)*sizeof(wchar_t));
if (!res) goto oom;
in = (unsigned char*)arg;
out = res;
while(*in)
if(*in < 128)
*out++ = *in++;
else
*out++ = 0xdc00 + *in++;
*out = 0;
#endif
return res;
oom:
fprintf(stderr, "out of memory\n");
return NULL;
}
int
main(int argc, char **argv)
{
wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
/* We need a second copies, as Python might modify the first one. */
wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
int i, res;
char *oldloc;
if (!argv_copy || !argv_copy2) {
fprintf(stderr, "out of memory\n");
return 1;
}
oldloc = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "");
for (i = 0; i < argc; i++) {
argv_copy2[i] = argv_copy[i] = char2wchar(argv[i]);
if (!argv_copy[i])
return 1;
}
setlocale(LC_ALL, oldloc);
free(oldloc);
res = python_main(argc, argv_copy);
for (i = 0; i < argc; i++) {
free(argv_copy2[i]);
}
free(argv_copy);
free(argv_copy2);
return res;
}
#endif"""
#!/usr/bin/env python
"""
Create a C file for embedding one or more Cython source files.
Requires Cython 0.11.2 (or perhaps newer).
See README.rst for more details.
"""
import sys
if len(sys.argv) < 2:
print >>sys.stderr, "USAGE: %s module [module ...]" % sys.argv[0]
sys.exit(1)
def format_modname(name):
if name.endswith('.pyx'):
name = name[:-4]
elif name.endswith('.py'):
name = name[:-3]
return name.replace('.','_')
modules = [format_modname(x) for x in sys.argv[1:]]
print """
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#if PY_MAJOR_VERSION < 3
# define MODINIT(name) init ## name
#else
# define MODINIT(name) PyInit_ ## name
#endif
"""
for name in modules:
print "PyMODINIT_FUNC MODINIT(%s) (void);" % name
print """
static struct _inittab inittab[] = {"""
for name in modules:
print ' {"%(name)s", MODINIT(%(name)s)},' % {'name' : name}
print """ {NULL, NULL}
};
extern int __pyx_module_is_main_%(main)s;
#if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS))
int main(int argc, char** argv) {
#else
int wmain(int argc, wchar_t **argv) {
#endif
int r = 0;
PyObject *m = NULL;
if (PyImport_ExtendInittab(inittab)) {
fprintf(stderr, "No memory\\n");
exit(1);
}
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
__pyx_module_is_main_%(main)s = 1;
m = PyImport_ImportModule(inittab[0].name);
if (!m) {
r = 1;
PyErr_Print(); /* This exits with the right code if SystemExit. */
if (Py_FlushLine()); PyErr_Clear();
}
Py_XDECREF(m);
Py_Finalize();
return r;
}
""" % {'main' : modules[0]}
...@@ -127,6 +127,10 @@ class TestBuilder(object): ...@@ -127,6 +127,10 @@ class TestBuilder(object):
continue continue
suite.addTest( suite.addTest(
self.handle_directory(path, filename)) self.handle_directory(path, filename))
if sys.platform not in ['win32'] and sys.version_info[0] < 3:
# Non-Windows makefile, can't run Cython under Py3.
if [1 for selector in self.selectors if selector("embedded")]:
suite.addTest(unittest.makeSuite(EmbedTest))
return suite return suite
def handle_directory(self, path, context): def handle_directory(self, path, context):
...@@ -429,6 +433,7 @@ is_private_field = re.compile('^_[^_]').match ...@@ -429,6 +433,7 @@ is_private_field = re.compile('^_[^_]').match
class _FakeClass(object): class _FakeClass(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.shortDescription = lambda x: kwargs.get('module_name')
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
try: # Py2.7+ and Py3.2+ try: # Py2.7+ and Py3.2+
...@@ -555,6 +560,28 @@ def collect_doctests(path, module_prefix, suite, selectors): ...@@ -555,6 +560,28 @@ def collect_doctests(path, module_prefix, suite, selectors):
except ValueError: # no tests except ValueError: # no tests
pass pass
# TODO: Support cython_freeze needed here as well.
# TODO: Windows support.
class EmbedTest(unittest.TestCase):
working_dir = "Demos/embed"
def setUp(self):
self.old_dir = os.getcwd()
os.chdir(self.working_dir)
os.system("make clean > /dev/null")
def tearDown(self):
try:
os.system("make clean > /dev/null")
except:
pass
os.chdir(self.old_dir)
def test_embed(self):
self.assert_(os.system("make test > make.output") == 0)
class MissingDependencyExcluder: class MissingDependencyExcluder:
def __init__(self, deps): def __init__(self, deps):
# deps: { module name : matcher func } # deps: { module name : matcher func }
......
cdef f(void=None):
pass
cdef struct foo:
int void
cdef class Foo:
cdef int void
cdef extern void spam(char *s)
cdef struct Grail:
char silly[42]
cdef void eggs():
cdef char silly[42]
cdef Grail grail
spam(silly)
spam(grail.silly)
eggs()
...@@ -3,5 +3,8 @@ ctypedef struct Foo: ...@@ -3,5 +3,8 @@ ctypedef struct Foo:
cdef Foo f(): cdef Foo f():
blarg = 1 + 2 blarg = 1 + 2
cdef Foo foo
foo.blarg = blarg
return foo
f() f()
...@@ -5,27 +5,33 @@ __doc__ = u""" ...@@ -5,27 +5,33 @@ __doc__ = u"""
>>> x >>> x
46 46
>>> add_pyrange(10)
46
>>> add_py(10)
46
>>> add_c(10)
46
""" """
def add_pyrange(max): def add_pyrange(max):
"""
>>> add_pyrange(10)
46
"""
x = 1 x = 1
for i in range(max): for i in range(max):
x = x + i x = x + i
return x return x
def add_py(max): def add_py(max):
"""
>>> add_py(10)
46
"""
x = 1 x = 1
for i from 0 <= i < max: for i from 0 <= i < max:
x = x + i x = x + i
return x return x
def add_c(max): def add_c(max):
"""
>>> add_c(10)
46
"""
cdef int x,i cdef int x,i
x = 1 x = 1
for i from 0 <= i < max: for i from 0 <= i < max:
......
__doc__ = u""" def f():
"""
>>> f() >>> f()
(30, 22) (30, 22)
""" """
def f():
cdef int int1, int2, int3 cdef int int1, int2, int3
cdef char *ptr1, *ptr2 = "test", *ptr3 = "toast" cdef char *ptr1, *ptr2 = "test", *ptr3 = "toast"
int2 = 10 int2 = 10
......
__doc__ = u""" def f(int a):
"""
>>> f(5) >>> f(5)
5 5
""" """
def f(int a):
cdef int i,j cdef int i,j
cdef int *p cdef int *p
i = a i = a
......
__doc__ = u"""
>>> func1(None)
>>> func1(*[None])
>>> func1(arg=None)
Traceback (most recent call last):
...
TypeError: func1() takes no keyword arguments
>>> func2(None)
>>> func2(*[None])
>>> func2(arg=None)
Traceback (most recent call last):
...
TypeError: func2() takes no keyword arguments
>>> func3(None)
>>> func3(*[None])
>>> func3(arg=None)
>>> A().meth1(None)
>>> A().meth1(*[None])
>>> A().meth1(arg=None)
Traceback (most recent call last):
...
TypeError: meth1() takes no keyword arguments
>>> A().meth2(None)
>>> A().meth2(*[None])
>>> A().meth2(arg=None)
Traceback (most recent call last):
...
TypeError: meth2() takes no keyword arguments
>>> A().meth3(None)
>>> A().meth3(*[None])
>>> A().meth3(arg=None)
"""
cimport cython cimport cython
def func1(arg): def func1(arg):
"""
>>> func1(None)
>>> func1(*[None])
>>> func1(arg=None)
Traceback (most recent call last):
...
TypeError: func1() takes no keyword arguments
"""
pass pass
@cython.always_allow_keywords(False) @cython.always_allow_keywords(False)
def func2(arg): def func2(arg):
"""
>>> func2(None)
>>> func2(*[None])
>>> func2(arg=None)
Traceback (most recent call last):
...
TypeError: func2() takes no keyword arguments
"""
pass pass
@cython.always_allow_keywords(True) @cython.always_allow_keywords(True)
def func3(arg): def func3(arg):
"""
>>> func3(None)
>>> func3(*[None])
>>> func3(arg=None)
"""
pass pass
cdef class A: cdef class A:
"""
>>> A().meth1(None)
>>> A().meth1(*[None])
>>> A().meth1(arg=None)
Traceback (most recent call last):
...
TypeError: meth1() takes no keyword arguments
>>> A().meth2(None)
>>> A().meth2(*[None])
>>> A().meth2(arg=None)
Traceback (most recent call last):
...
TypeError: meth2() takes no keyword arguments
>>> A().meth3(None)
>>> A().meth3(*[None])
>>> A().meth3(arg=None)
"""
def meth1(self, arg): def meth1(self, arg):
pass pass
......
__doc__ = u""" a,b = 'a *','b *' # use non-interned strings
>>> a,b = 'a *','b *' # use non-interned strings
>>> and2_assign(2,3) == (2 and 3)
True
>>> and2_assign('a', 'b') == ('a' and 'b')
True
>>> and2_assign(a, b) == (a and b)
True
>>> and2(2,3) == (2 and 3)
True
>>> and2(0,2) == (0 and 2)
True
>>> and2('a', 'b') == ('a' and 'b')
True
>>> and2(a, b) == (a and b)
True
>>> and2('', 'b') == ('' and 'b')
True
>>> and2([], [1]) == ([] and [1])
True
>>> and2([], [a]) == ([] and [a])
True
>>> and3(0,1,2) == (0 and 1 and 2)
True
>>> and3([],(),[1]) == ([] and () and [1])
True
>>> and2_no_result(2,3)
>>> and2_no_result(0,2)
>>> and2_no_result('a','b')
>>> and2_no_result(a,b)
>>> a and b
'b *'
"""
def and2_assign(a,b): def and2_assign(a,b):
"""
>>> a,b = 'a *','b *' # use non-interned strings
>>> and2_assign(2,3) == (2 and 3)
True
>>> and2_assign('a', 'b') == ('a' and 'b')
True
>>> and2_assign(a, b) == (a and b)
True
"""
c = a and b c = a and b
return c return c
def and2(a,b): def and2(a,b):
"""
>>> and2(2,3) == (2 and 3)
True
>>> and2(0,2) == (0 and 2)
True
>>> and2('a', 'b') == ('a' and 'b')
True
>>> and2(a, b) == (a and b)
True
>>> and2('', 'b') == ('' and 'b')
True
>>> and2([], [1]) == ([] and [1])
True
>>> and2([], [a]) == ([] and [a])
True
"""
return a and b return a and b
def and3(a,b,c): def and3(a,b,c):
"""
>>> and3(0,1,2) == (0 and 1 and 2)
True
>>> and3([],(),[1]) == ([] and () and [1])
True
"""
d = a and b and c d = a and b and c
return d return d
def and2_no_result(a,b): def and2_no_result(a,b):
"""
>>> and2_no_result(2,3)
>>> and2_no_result(0,2)
>>> and2_no_result('a','b')
>>> and2_no_result(a,b)
>>> a and b
'b *'
"""
a and b a and b
__doc__ = u"""
>>> test_append([])
None
None
None
got error
[1, 2, (3, 4)]
>>> _ = test_append(A())
appending
1
appending
2
appending
(3, 4)
got error
>>> test_append(B())
None
None
None
None
[1, 2, (3, 4), 5, 6]
"""
class A: class A:
def append(self, x): def append(self, x):
print u"appending" print u"appending"
...@@ -32,6 +9,28 @@ class B(list): ...@@ -32,6 +9,28 @@ class B(list):
list.append(self, arg) list.append(self, arg)
def test_append(L): def test_append(L):
"""
>>> test_append([])
None
None
None
got error
[1, 2, (3, 4)]
>>> _ = test_append(A())
appending
1
appending
2
appending
(3, 4)
got error
>>> test_append(B())
None
None
None
None
[1, 2, (3, 4), 5, 6]
"""
print L.append(1) print L.append(1)
print L.append(2) print L.append(2)
print L.append((3,4)) print L.append((3,4))
...@@ -40,4 +39,3 @@ def test_append(L): ...@@ -40,4 +39,3 @@ def test_append(L):
except TypeError: except TypeError:
print u"got error" print u"got error"
return L return L
__doc__ = u"""
>>> f0()
(1, 2)
>>> g0()
(1, 2)
>>> f1()
[1, 2]
>>> g1()
[1, 2]
>>> f2()
{1: 2}
>>> g2()
{1: 2}
>>> f3() #doctest: +ELLIPSIS
<argdefault.Foo object at ...>
>>> g3() #doctest: +ELLIPSIS
<argdefault.Foo object at ...>
>>> f4() #doctest: +ELLIPSIS
<argdefault.Bar object at ...>
>>> g4() #doctest: +ELLIPSIS
<argdefault.Bar object at ...>
>>> f5() #doctest: +ELLIPSIS
<argdefault.Bla object at ...>
>>> g5() #doctest: +ELLIPSIS
<argdefault.Bla object at ...>
>>> f6()
7
>>> g6()
7
"""
GLB0 = (1, 2) GLB0 = (1, 2)
def f0(arg=GLB0): def f0(arg=GLB0):
"""
>>> f0()
(1, 2)
"""
return arg return arg
def g0(arg=(1, 2)): def g0(arg=(1, 2)):
"""
>>> g0()
(1, 2)
"""
return arg return arg
GLB1 = [1, 2] GLB1 = [1, 2]
def f1(arg=GLB1): def f1(arg=GLB1):
"""
>>> f1()
[1, 2]
"""
return arg return arg
def g1(arg=[1, 2]): def g1(arg=[1, 2]):
"""
>>> g1()
[1, 2]
"""
return arg return arg
cdef GLB2 = {1: 2} cdef GLB2 = {1: 2}
def f2(arg=GLB2): def f2(arg=GLB2):
"""
>>> f2()
{1: 2}
"""
return arg return arg
def g2(arg={1: 2}): def g2(arg={1: 2}):
"""
>>> g2()
{1: 2}
"""
return arg return arg
...@@ -60,8 +47,16 @@ class Foo(object): ...@@ -60,8 +47,16 @@ class Foo(object):
pass pass
cdef GLB3 = Foo() cdef GLB3 = Foo()
def f3(arg=GLB3): def f3(arg=GLB3):
"""
>>> f3() #doctest: +ELLIPSIS
<argdefault.Foo object at ...>
"""
return arg return arg
def g3(arg=Foo()): def g3(arg=Foo()):
"""
>>> g3() #doctest: +ELLIPSIS
<argdefault.Foo object at ...>
"""
return arg return arg
...@@ -69,8 +64,16 @@ cdef class Bar: ...@@ -69,8 +64,16 @@ cdef class Bar:
pass pass
cdef Bar GLB4 = Bar() cdef Bar GLB4 = Bar()
def f4(arg=GLB4): def f4(arg=GLB4):
"""
>>> f4() #doctest: +ELLIPSIS
<argdefault.Bar object at ...>
"""
return arg return arg
def g4(arg=Bar()): def g4(arg=Bar()):
"""
>>> g4() #doctest: +ELLIPSIS
<argdefault.Bar object at ...>
"""
return arg return arg
...@@ -78,13 +81,29 @@ cdef class Bla: ...@@ -78,13 +81,29 @@ cdef class Bla:
pass pass
cdef Bla GLB5 = Bla() cdef Bla GLB5 = Bla()
def f5(Bla arg=GLB5): def f5(Bla arg=GLB5):
"""
>>> f5() #doctest: +ELLIPSIS
<argdefault.Bla object at ...>
"""
return arg return arg
def g5(Bla arg=Bla()): def g5(Bla arg=Bla()):
"""
>>> g5() #doctest: +ELLIPSIS
<argdefault.Bla object at ...>
"""
return arg return arg
cdef int GLB6 = 7 cdef int GLB6 = 7
def f6(int arg=GLB6): def f6(int arg=GLB6):
"""
>>> f6()
7
"""
return arg return arg
def g6(int arg=7): def g6(int arg=7):
"""
>>> g6()
7
"""
return arg return arg
__doc__ = u"""
>>> test_literal_list_slice_all()
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start()
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_end()
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_end()
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_param(4)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_param(3)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_param(5)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_end_param(5)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_end_param(4)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_end_param(6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_end_param(2,7)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_end_param(3,7)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_start_end_param(1,7)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_end_param(2,6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_start_end_param(2,8)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_end_param(3,6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 3
>>> test_literal_list_slice_start_end_param(1,8)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 7
>>> test_ptr_literal_list_slice_all()
(1, 2, 3, 4, 5)
>>> test_ptr_literal_list_slice_start()
(1, 2, 3, 4, 5)
>>> test_ptr_literal_list_slice_end()
(1, 2, 3, 4, 5)
"""
# this doesn't work - it would reassign the array address! # this doesn't work - it would reassign the array address!
# #
#def test_literal_list(): #def test_literal_list():
...@@ -63,54 +6,124 @@ ValueError: Assignment to slice of wrong length, expected 5, got 7 ...@@ -63,54 +6,124 @@ ValueError: Assignment to slice of wrong length, expected 5, got 7
# return (a[0], a[1], a[2], a[3], a[4]) # return (a[0], a[1], a[2], a[3], a[4])
def test_literal_list_slice_all(): def test_literal_list_slice_all():
"""
>>> test_literal_list_slice_all()
(1, 2, 3, 4, 5)
"""
cdef int a[5] # = [5,4,3,2,1] cdef int a[5] # = [5,4,3,2,1]
a[:] = [1,2,3,4,5] a[:] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
def test_literal_list_slice_start(): def test_literal_list_slice_start():
"""
>>> test_literal_list_slice_start()
(1, 2, 3, 4, 5)
"""
cdef int a[7] # = [7,6,5,4,3,2,1] cdef int a[7] # = [7,6,5,4,3,2,1]
a[2:] = [1,2,3,4,5] a[2:] = [1,2,3,4,5]
return (a[2], a[3], a[4], a[5], a[6]) return (a[2], a[3], a[4], a[5], a[6])
def test_literal_list_slice_end(): def test_literal_list_slice_end():
"""
>>> test_literal_list_slice_end()
(1, 2, 3, 4, 5)
"""
cdef int a[7] # = [7,6,5,4,3,2,1] cdef int a[7] # = [7,6,5,4,3,2,1]
a[:5] = [1,2,3,4,5] a[:5] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
def test_literal_list_slice_start_end(): def test_literal_list_slice_start_end():
"""
>>> test_literal_list_slice_start_end()
(1, 2, 3, 4, 5)
"""
cdef int a[9] # = [9,8,7,6,5,4,3,2,1] cdef int a[9] # = [9,8,7,6,5,4,3,2,1]
a[2:7] = [1,2,3,4,5] a[2:7] = [1,2,3,4,5]
return (a[2], a[3], a[4], a[5], a[6]) return (a[2], a[3], a[4], a[5], a[6])
def test_literal_list_slice_start_param(s): def test_literal_list_slice_start_param(s):
"""
>>> test_literal_list_slice_start_param(4)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_param(3)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_param(5)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
"""
cdef int a[9] # = [9,8,7,6,5,4,3,2,1] cdef int a[9] # = [9,8,7,6,5,4,3,2,1]
a[s:] = [1,2,3,4,5] a[s:] = [1,2,3,4,5]
return (a[4], a[5], a[6], a[7], a[8]) return (a[4], a[5], a[6], a[7], a[8])
# return a[s:] # return a[s:]
def test_literal_list_slice_end_param(e): def test_literal_list_slice_end_param(e):
"""
>>> test_literal_list_slice_end_param(5)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_end_param(4)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_end_param(6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
"""
cdef int a[9] # = [9,8,7,6,5,4,3,2,1] cdef int a[9] # = [9,8,7,6,5,4,3,2,1]
a[:e] = [1,2,3,4,5] a[:e] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
# return a[:e] # return a[:e]
def test_literal_list_slice_start_end_param(s,e): def test_literal_list_slice_start_end_param(s,e):
"""
>>> test_literal_list_slice_start_end_param(2,7)
(1, 2, 3, 4, 5)
>>> test_literal_list_slice_start_end_param(3,7)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_start_end_param(1,7)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_end_param(2,6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 4
>>> test_literal_list_slice_start_end_param(2,8)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 6
>>> test_literal_list_slice_start_end_param(3,6)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 3
>>> test_literal_list_slice_start_end_param(1,8)
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 5, got 7
"""
cdef int a[9] # = [9,8,7,6,5,4,3,2,1] cdef int a[9] # = [9,8,7,6,5,4,3,2,1]
a[s:e] = [1,2,3,4,5] a[s:e] = [1,2,3,4,5]
return (a[2], a[3], a[4], a[5], a[6]) return (a[2], a[3], a[4], a[5], a[6])
# return a[s:e] # return a[s:e]
def test_ptr_literal_list_slice_all(): def test_ptr_literal_list_slice_all():
"""
>>> test_ptr_literal_list_slice_all()
(1, 2, 3, 4, 5)
"""
cdef int *a = [6,5,4,3,2] cdef int *a = [6,5,4,3,2]
a[:] = [1,2,3,4,5] a[:] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
def test_ptr_literal_list_slice_start(): def test_ptr_literal_list_slice_start():
"""
>>> test_ptr_literal_list_slice_start()
(1, 2, 3, 4, 5)
"""
cdef int *a = [6,5,4,3,2,1] cdef int *a = [6,5,4,3,2,1]
a[1:] = [1,2,3,4,5] a[1:] = [1,2,3,4,5]
return (a[1], a[2], a[3], a[4], a[5]) return (a[1], a[2], a[3], a[4], a[5])
def test_ptr_literal_list_slice_end(): def test_ptr_literal_list_slice_end():
"""
>>> test_ptr_literal_list_slice_end()
(1, 2, 3, 4, 5)
"""
cdef int *a = [6,5,4,3,2,1] cdef int *a = [6,5,4,3,2,1]
a[:5] = [1,2,3,4,5] a[:5] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
......
__doc__ = u""" def f():
"""
>>> f() >>> f()
42 42
""" """
def f():
a = 42 a = 42
return a return a
__doc__ = u""" def f(a, b, int i):
"""
>>> f(1, 2, 1) >>> f(1, 2, 1)
>>> f(0, 2, 1) >>> f(0, 2, 1)
Traceback (most recent call last): Traceback (most recent call last):
...@@ -9,17 +10,16 @@ __doc__ = u""" ...@@ -9,17 +10,16 @@ __doc__ = u"""
>>> f(1, 2, 0) >>> f(1, 2, 0)
Traceback (most recent call last): Traceback (most recent call last):
AssertionError AssertionError
"""
>>> g(1, "works")
>>> g(0, "fails")
Traceback (most recent call last):
AssertionError: fails
"""
def f(a, b, int i):
assert a assert a
assert a+b assert a+b
assert i assert i
def g(a, b): def g(a, b):
"""
>>> g(1, "works")
>>> g(0, "fails")
Traceback (most recent call last):
AssertionError: fails
"""
assert a, b assert a, b
...@@ -109,5 +109,3 @@ cdef class MyCdefClass: ...@@ -109,5 +109,3 @@ cdef class MyCdefClass:
>>> True >>> True
False False
""" """
__doc__ = u""" def f(obj2):
"""
>>> f(20) >>> f(20)
'20' '20'
>>> f('test') >>> f('test')
"'test'" "'test'"
"""
>>> g()
'42'
"""
def f(obj2):
obj1 = `obj2` obj1 = `obj2`
return obj1 return obj1
def g(): def g():
"""
>>> g()
'42'
"""
obj1 = `42` obj1 = `42`
return obj1 return obj1
cdef cf(default=None):
return default
cpdef cpf(default=None):
"""
>>> cpf()
None
>>> cpf(1)
1
>>> cpf(default=2)
2
"""
default = cf(default)
return default
def pf(default=None):
"""
>>> pf()
None
>>> pf(1)
1
>>> pf(default=2)
2
"""
return default
cdef struct foo:
int void
int default
def test_struct():
"""
>>> test_struct()
(1, 2)
"""
cdef foo foo_struct
foo_struct.void = 1
foo_struct.default = 2
return foo_struct.void, foo_struct.default
cdef class Foo:
cdef int void
cdef int default
def test_class():
"""
>>> test_class()
(1, 2)
"""
cdef Foo foo_instance = Foo()
foo_instance.void = 1
foo_instance.default = 2
return foo_instance.void, foo_instance.default
__doc__ = u"""
>>> viking(5)
5
"""
cdef class Spam: cdef class Spam:
cdef eggs(self, a): cdef eggs(self, a):
return a return a
...@@ -11,4 +6,8 @@ cdef Spam spam(): ...@@ -11,4 +6,8 @@ cdef Spam spam():
return Spam() return Spam()
def viking(a): def viking(a):
"""
>>> viking(5)
5
"""
return spam().eggs(a) return spam().eggs(a)
__doc__ = u""" def test():
"""
>>> test() >>> test()
neg False neg False
pos True pos True
...@@ -6,9 +7,7 @@ __doc__ = u""" ...@@ -6,9 +7,7 @@ __doc__ = u"""
pos pos
neg neg
pos pos
""" """
def test():
cdef long neg = -1 cdef long neg = -1
cdef unsigned long pos = -2 # will be a large positive number cdef unsigned long pos = -2 # will be a large positive number
...@@ -22,4 +21,3 @@ def test(): ...@@ -22,4 +21,3 @@ def test():
print D[neg] print D[neg]
print D[pos] print D[pos]
__doc__ = u"""
>>> call_test()
False
True
False
True
True
True
True
"""
cdef test(bint value): cdef test(bint value):
print value print value
def call_test(): def call_test():
"""
>>> call_test()
False
True
False
True
True
True
True
"""
test(False) test(False)
test(True) test(True)
test(0) test(0)
......
__doc__ = u""" def foo(obj1, obj2, obj3, obj4, obj5):
"""
>>> foo(True, False, 23, 'test', 1) >>> foo(True, False, 23, 'test', 1)
(0.0, 1.0, False, False) (0.0, 1.0, False, False)
""" """
def foo(obj1, obj2, obj3, obj4, obj5):
cdef int bool1, bool2 cdef int bool1, bool2
cdef float bool3, bool4 cdef float bool3, bool4
cdef char *ptr1, *ptr2, *ptr0 cdef char *ptr1, *ptr2, *ptr0
......
...@@ -1392,4 +1392,3 @@ def buffer_nogil(): ...@@ -1392,4 +1392,3 @@ def buffer_nogil():
with nogil: with nogil:
buf[1] = 10 buf[1] = 10
return buf[1] return buf[1]
...@@ -4,11 +4,13 @@ __doc__ = u""" ...@@ -4,11 +4,13 @@ __doc__ = u"""
Traceback (most recent call last): Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute 'append' AttributeError: 'NoneType' object has no attribute 'append'
>>> append_to_none()
Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute 'append'
""" """
def append_to_none(): def append_to_none():
"""
>>> append_to_none()
Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute 'append'
"""
cdef list l = None cdef list l = None
l.append(2) l.append(2)
__doc__ = u"""
>>> test_c('abc')
fileabc
typeabc
>>> print(test_file_py('abc'))
abc
>>> print(range('abc'))
rangeabc
"""
def test_file_py(file): def test_file_py(file):
assert isinstance(file, (str, unicode)), \ assert isinstance(file, (str, unicode)), \
u"not a string, found '%s' instead" % file.__class__.__name__ u"not a string, found '%s' instead" % file.__class__.__name__
...@@ -28,5 +17,14 @@ cdef type(arg): ...@@ -28,5 +17,14 @@ cdef type(arg):
def test_c(arg): def test_c(arg):
"""
>>> test_c('abc')
fileabc
typeabc
>>> print(test_file_py('abc'))
abc
>>> print(range('abc'))
rangeabc
"""
print test_file_c(arg) print test_file_c(arg)
print type(arg) print type(arg)
__doc__ = u""" cdef class A:
"""
>>> A().test(3) >>> A().test(3)
9 9
""" """
cdef class A:
cdef int (*func_ptr)(int) cdef int (*func_ptr)(int)
......
__doc__ = u"""
>>> test_pos_args(h)
1 2 3 * 0 0
1 2 9 * 2 0
1 2 7 * 2 0
9 8 7 * 0 0
7 8 9 * 0 0
>>> test_kw_args(h)
1 2 3 * 0 0
1 2 9 * 2 1
1 2 7 * 2 1
1 2 9 * 2 2
1 2 9 * 2 2
1 2 9 * 2 3
>>> test_kw_args(e)
2 1
5 1
5 1
5 2
5 2
5 3
>>> test_kw(e)
0 1
0 2
0 2
0 1
>>> test_kw(g)
1
2
2
1
>>> test_pos_args(f)
3
5
5
3
3
>>> test_noargs(e)
0 0
>>> test_noargs(f)
0
>>> test_noargs(g)
0
# and some errors:
>>> test_noargs(h)
Traceback (most recent call last):
TypeError: h() takes at least 3 positional arguments (0 given)
>>> h(1,2, d=5)
Traceback (most recent call last):
TypeError: h() takes at least 3 positional arguments (2 given)
>>> f(1,2, d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
>>> f(1, d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
>>> f(d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
>>> g(1,2, d=5)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (2 given)
>>> g(1,2)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (2 given)
>>> g(1)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (1 given)
>>> test_int_kwargs(e)
Traceback (most recent call last):
TypeError: e() keywords must be strings
>>> test_int_kwargs(f)
Traceback (most recent call last):
TypeError: f() keywords must be strings
>>> test_int_kwargs(g)
Traceback (most recent call last):
TypeError: g() keywords must be strings
>>> test_int_kwargs(h)
Traceback (most recent call last):
TypeError: h() keywords must be strings
>>> d()
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1)
1 1 0 0
>>> d(1,2)
1 2 0 0
>>> d(1,2,3)
1 2 1 0
>>> d(key=None)
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1, key=None)
1 1 0 1
>>> d(1,2, key=None)
1 2 0 1
>>> d(1,2,3, key=None)
1 2 1 1
>>> c()
10 20 0
>>> c(1)
1 20 0
>>> c(1,2)
1 2 0
>>> c(key=None)
10 20 1
>>> c(1, key=None)
1 20 1
>>> c(1,2, key=None)
1 2 1
"""
def c(a=10, b=20, **kwds): def c(a=10, b=20, **kwds):
"""
>>> c()
10 20 0
>>> c(1)
1 20 0
>>> c(1,2)
1 2 0
>>> c(key=None)
10 20 1
>>> c(1, key=None)
1 20 1
>>> c(1,2, key=None)
1 2 1
"""
print a, b, len(kwds) print a, b, len(kwds)
def d(a, b=1, *args, **kwds): def d(a, b=1, *args, **kwds):
"""
>>> d()
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1)
1 1 0 0
>>> d(1,2)
1 2 0 0
>>> d(1,2,3)
1 2 1 0
>>> d(key=None)
Traceback (most recent call last):
TypeError: d() takes at least 1 positional argument (0 given)
>>> d(1, key=None)
1 1 0 1
>>> d(1,2, key=None)
1 2 0 1
>>> d(1,2,3, key=None)
1 2 1 1
"""
print a, b, len(args), len(kwds) print a, b, len(args), len(kwds)
def e(*args, **kwargs): def e(*args, **kwargs):
print len(args), len(kwargs) print len(args), len(kwargs)
def f(*args): def f(*args):
"""
>>> f(1,2, d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
>>> f(1, d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
>>> f(d=5)
Traceback (most recent call last):
TypeError: f() got an unexpected keyword argument 'd'
"""
print len(args) print len(args)
def g(**kwargs): def g(**kwargs):
"""
>>> g(1,2, d=5)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (2 given)
>>> g(1,2)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (2 given)
>>> g(1)
Traceback (most recent call last):
TypeError: g() takes exactly 0 positional arguments (1 given)
"""
print len(kwargs) print len(kwargs)
def h(a, b, c, *args, **kwargs): def h(a, b, c, *args, **kwargs):
"""
>>> h(1,2, d=5)
Traceback (most recent call last):
TypeError: h() takes at least 3 positional arguments (2 given)
"""
print a, b, c, u'*', len(args), len(kwargs) print a, b, c, u'*', len(args), len(kwargs)
args = (9,8,7) args = (9,8,7)
...@@ -153,6 +86,22 @@ else: ...@@ -153,6 +86,22 @@ else:
kwargs = {"test" : u"toast"} kwargs = {"test" : u"toast"}
def test_kw_args(f): def test_kw_args(f):
"""
>>> test_kw_args(h)
1 2 3 * 0 0
1 2 9 * 2 1
1 2 7 * 2 1
1 2 9 * 2 2
1 2 9 * 2 2
1 2 9 * 2 3
>>> test_kw_args(e)
2 1
5 1
5 1
5 2
5 2
5 3
"""
f(1,2, c=3) f(1,2, c=3)
f(1,2, d=3, *args) f(1,2, d=3, *args)
f(1,2, d=3, *(7,8,9)) f(1,2, d=3, *(7,8,9))
...@@ -161,6 +110,20 @@ def test_kw_args(f): ...@@ -161,6 +110,20 @@ def test_kw_args(f):
f(1,2, d=3, *args, e=5, **kwargs) f(1,2, d=3, *args, e=5, **kwargs)
def test_pos_args(f): def test_pos_args(f):
"""
>>> test_pos_args(h)
1 2 3 * 0 0
1 2 9 * 2 0
1 2 7 * 2 0
9 8 7 * 0 0
7 8 9 * 0 0
>>> test_pos_args(f)
3
5
5
3
3
"""
f(1,2,3) f(1,2,3)
f(1,2, *args) f(1,2, *args)
f(1,2, *(7,8,9)) f(1,2, *(7,8,9))
...@@ -168,13 +131,52 @@ def test_pos_args(f): ...@@ -168,13 +131,52 @@ def test_pos_args(f):
f(*(7,8,9)) f(*(7,8,9))
def test_kw(f): def test_kw(f):
"""
>>> test_kw(e)
0 1
0 2
0 2
0 1
>>> test_kw(g)
1
2
2
1
"""
f(c=3) f(c=3)
f(d=3, e=5) f(d=3, e=5)
f(d=3, **kwargs) f(d=3, **kwargs)
f(**kwargs) f(**kwargs)
def test_noargs(f): def test_noargs(f):
"""
>>> test_noargs(e)
0 0
>>> test_noargs(f)
0
>>> test_noargs(g)
0
# and some errors:
>>> test_noargs(h)
Traceback (most recent call last):
TypeError: h() takes at least 3 positional arguments (0 given)
"""
f() f()
def test_int_kwargs(f): def test_int_kwargs(f):
"""
>>> test_int_kwargs(e)
Traceback (most recent call last):
TypeError: e() keywords must be strings
>>> test_int_kwargs(f)
Traceback (most recent call last):
TypeError: f() keywords must be strings
>>> test_int_kwargs(g)
Traceback (most recent call last):
TypeError: g() keywords must be strings
>>> test_int_kwargs(h)
Traceback (most recent call last):
TypeError: h() keywords must be strings
"""
f(a=1,b=2,c=3, **{10:20,30:40}) f(a=1,b=2,c=3, **{10:20,30:40})
cimport cython
############################################################
# tests for char* slicing
cdef char* cstring = "abcABCqtp"
def slice_charptr_end():
"""
>>> print(str(slice_charptr_end()).replace("b'", "'"))
('a', 'abc', 'abcABCqtp')
"""
return cstring[:1], cstring[:3], cstring[:9]
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def slice_charptr_decode():
"""
>>> print(str(slice_charptr_decode()).replace("u'", "'"))
('a', 'abc', 'abcABCqtp')
"""
return (cstring[:1].decode('UTF-8'),
cstring[:3].decode('UTF-8'),
cstring[:9].decode('UTF-8'))
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def slice_charptr_decode_unbound():
"""
>>> print(str(slice_charptr_decode_unbound()).replace("u'", "'"))
('a', 'abc', 'abcABCqtp')
"""
return (bytes.decode(cstring[:1], 'UTF-8'),
bytes.decode(cstring[:3], 'UTF-8', 'replace'),
bytes.decode(cstring[:9], 'UTF-8'))
@cython.test_assert_path_exists("//PythonCapiCallNode")
@cython.test_fail_if_path_exists("//AttributeNode")
def slice_charptr_decode_errormode():
"""
>>> print(str(slice_charptr_decode_errormode()).replace("u'", "'"))
('a', 'abc', 'abcABCqtp')
"""
return (cstring[:1].decode('UTF-8', 'strict'),
cstring[:3].decode('UTF-8', 'replace'),
cstring[:9].decode('UTF-8', 'unicode_escape'))
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//SliceIndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_charptr_for_loop_py():
"""
>>> slice_charptr_for_loop_py()
['a', 'b', 'c']
['b', 'c', 'A', 'B']
['B', 'C', 'q', 't', 'p']
"""
print str([ c for c in cstring[:3] ]).replace(" b'", " '").replace("[b'", "['")
print str([ c for c in cstring[1:5] ]).replace(" b'", " '").replace("[b'", "['")
print str([ c for c in cstring[4:9] ]).replace(" b'", " '").replace("[b'", "['")
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_charptr_for_loop_c():
"""
>>> slice_charptr_for_loop_c()
['a', 'b', 'c']
['b', 'c', 'A', 'B']
['B', 'C', 'q', 't', 'p']
"""
cdef char c
print [ chr(c) for c in cstring[:3] ]
print [ chr(c) for c in cstring[1:5] ]
print [ chr(c) for c in cstring[4:9] ]
## @cython.test_assert_path_exists("//ForFromStatNode",
## "//ForFromStatNode//IndexNode")
## @cython.test_fail_if_path_exists("//ForInStatNode")
## def slice_charptr_for_loop_c_step():
## """
## >>> slice_charptr_for_loop_c()
## ['c', 'b', 'a']
## ['b', 'c', 'A', 'B']
## ['p', 't', 'q', 'C', 'B']
## """
## cdef char c
## print [ chr(c) for c in cstring[:3:-1] ]
## print [ chr(c) for c in cstring[1:5:2] ]
## print [ chr(c) for c in cstring[4:9:-1] ]
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_charptr_for_loop_c_dynamic_bounds():
"""
>>> slice_charptr_for_loop_c()
['a', 'b', 'c']
['b', 'c', 'A', 'B']
['B', 'C', 'q', 't', 'p']
"""
cdef char c
print [ chr(c) for c in cstring[0:return3()] ]
print [ chr(c) for c in cstring[return1():return5()] ]
print [ chr(c) for c in cstring[return4():return9()] ]
cdef return1(): return 1
cdef return3(): return 3
cdef return4(): return 4
cdef return5(): return 5
cdef return9(): return 9
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//SliceIndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_charptr_for_loop_py_enumerate():
"""
>>> slice_charptr_for_loop_py_enumerate()
[(0, 'a'), (1, 'b'), (2, 'c')]
[(0, 'b'), (1, 'c'), (2, 'A'), (3, 'B')]
[(0, 'B'), (1, 'C'), (2, 'q'), (3, 't'), (4, 'p')]
"""
print str([ (i,c) for i,c in enumerate(cstring[:3]) ]).replace(" b'", " '")
print str([ (i,c) for i,c in enumerate(cstring[1:5]) ]).replace(" b'", " '")
print str([ (i,c) for i,c in enumerate(cstring[4:9]) ]).replace(" b'", " '")
@cython.test_assert_path_exists("//ForFromStatNode",
"//ForFromStatNode//IndexNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def slice_charptr_for_loop_c_enumerate():
"""
>>> slice_charptr_for_loop_c_enumerate()
[(0, 97), (1, 98), (2, 99)]
[(0, 98), (1, 99), (2, 65), (3, 66)]
[(0, 66), (1, 67), (2, 113), (3, 116), (4, 112)]
"""
cdef int c,i
print [ (i,c) for i,c in enumerate(cstring[:3]) ]
print [ (i,c) for i,c in enumerate(cstring[1:5]) ]
print [ (i,c) for i,c in enumerate(cstring[4:9]) ]
############################################################
# tests for int* slicing
## cdef int cints[6]
## for i in range(6):
## cints[i] = i
## @cython.test_assert_path_exists("//ForFromStatNode",
## "//ForFromStatNode//IndexNode")
## @cython.test_fail_if_path_exists("//ForInStatNode")
## def slice_intptr_for_loop_c():
## """
## >>> slice_intptr_for_loop_c()
## [0, 1, 2]
## [1, 2, 3, 4]
## [4, 5]
## """
## cdef int i
## print [ i for i in cints[:3] ]
## print [ i for i in cints[1:5] ]
## print [ i for i in cints[4:6] ]
__doc__ = u"""
>>> test1()
2
>>> test2()
0
>>> test3()
(2, 3)
"""
def test1(): def test1():
"""
>>> test1()
2
"""
cdef int x[2][2] cdef int x[2][2]
x[0][0] = 1 x[0][0] = 1
x[0][1] = 2 x[0][1] = 2
...@@ -20,6 +15,10 @@ cdef int* f(int x[2][2]): ...@@ -20,6 +15,10 @@ cdef int* f(int x[2][2]):
def test2(): def test2():
"""
>>> test2()
0
"""
cdef int a1[5] cdef int a1[5]
cdef int a2[2+3] cdef int a2[2+3]
return sizeof(a1) - sizeof(a2) return sizeof(a1) - sizeof(a2)
...@@ -29,6 +28,10 @@ cdef enum: ...@@ -29,6 +28,10 @@ cdef enum:
MY_SIZE_B = 3 MY_SIZE_B = 3
def test3(): def test3():
"""
>>> test3()
(2, 3)
"""
cdef int a[MY_SIZE_A] cdef int a[MY_SIZE_A]
cdef int b[MY_SIZE_B] cdef int b[MY_SIZE_B]
return sizeof(a)/sizeof(int), sizeof(b)/sizeof(int) return sizeof(a)/sizeof(int), sizeof(b)/sizeof(int)
__doc__ = u"""
>>> foo(True)
True
>>> foo(False)
False
>>> foo('abc') # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
>>> call_cfoo(True)
True
>>> call_cfoo(False)
False
>>> call_cfoo('abc') # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
"""
def foo(bool a): def foo(bool a):
"""
>>> foo(True)
True
>>> foo(False)
False
>>> foo('abc') # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
"""
return a == True return a == True
def call_cfoo(a): def call_cfoo(a):
"""
>>> call_cfoo(True)
True
>>> call_cfoo(False)
False
>>> call_cfoo('abc') # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
"""
return cfoo(a) return cfoo(a)
cdef cfoo(bool a): cdef cfoo(bool a):
......
__doc__ = u"""
>>> cdiv_decorator(-12, 5)
-2
>>> pydiv_decorator(-12, 5)
-3
"""
cimport cython cimport cython
@cython.cdivision(True) @cython.cdivision(True)
cpdef cdiv_decorator(int a, int b): cpdef cdiv_decorator(int a, int b):
"""
>>> cdiv_decorator(-12, 5)
-2
"""
return a / b return a / b
@cython.cdivision(False) @cython.cdivision(False)
cpdef pydiv_decorator(int a, int b): cpdef pydiv_decorator(int a, int b):
"""
>>> pydiv_decorator(-12, 5)
-3
"""
return a / b return a / b
...@@ -7,12 +7,6 @@ __doc__ = u""" ...@@ -7,12 +7,6 @@ __doc__ = u"""
>>> a.foo(10, u'yes') >>> a.foo(10, u'yes')
(True, u'yes') (True, u'yes')
>>> call0()
(True, u'yo')
>>> call1()
(False, u'yo')
>>> call2()
(False, u'go')
""" """
import sys import sys
...@@ -25,13 +19,25 @@ cdef class A: ...@@ -25,13 +19,25 @@ cdef class A:
return a, b return a, b
def call0(): def call0():
"""
>>> call0()
(True, u'yo')
"""
a = A() a = A()
return a.foo() return a.foo()
def call1(): def call1():
"""
>>> call1()
(False, u'yo')
"""
a = A() a = A()
return a.foo(False) return a.foo(False)
def call2(): def call2():
"""
>>> call2()
(False, u'go')
"""
a = A() a = A()
return a.foo(False, u"go") return a.foo(False, u"go")
__doc__ = u'''
>>> no_cdef()
>>> with_cdef()
>>> test_list(list(range(11)), -2, None)
[0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10]
>>> test_list(list(range(11)), "invalid index", None) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: list indices must be integers...
'''
def no_cdef(): def no_cdef():
"""
>>> no_cdef()
"""
lst = list(range(11)) lst = list(range(11))
ob = 10L ob = 10L
lst[ob] = -10 lst[ob] = -10
...@@ -17,6 +9,9 @@ def no_cdef(): ...@@ -17,6 +9,9 @@ def no_cdef():
dd[ob] = -10 dd[ob] = -10
def with_cdef(): def with_cdef():
"""
>>> with_cdef()
"""
cdef list lst = list(range(11)) cdef list lst = list(range(11))
ob = 10L ob = 10L
lst[ob] = -10 lst[ob] = -10
...@@ -24,5 +19,13 @@ def with_cdef(): ...@@ -24,5 +19,13 @@ def with_cdef():
dd[ob] = -10 dd[ob] = -10
def test_list(list L, object i, object a): def test_list(list L, object i, object a):
"""
>>> test_list(list(range(11)), -2, None)
[0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10]
>>> test_list(list(range(11)), "invalid index", None) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: list indices must be integers...
"""
L[i] = a L[i] = a
return L return L
__doc__ = u"""
>>> test(1, 2)
4 1 2 2 0 7 8
"""
cdef int g = 7 cdef int g = 7
def test(x, int y): def test(x, int y):
"""
>>> test(1, 2)
4 1 2 2 0 7 8
"""
if True: if True:
before = 0 before = 0
cdef int a = 4, b = x, c = y, *p = &y cdef int a = 4, b = x, c = y, *p = &y
......
__doc__ = u"""
>>> call2()
>>> call3()
>>> call4()
>>> test_foo()
2
3
7
26
"""
# the calls: # the calls:
def call2(): def call2():
"""
>>> call2()
"""
b(1,2) b(1,2)
def call3(): def call3():
"""
>>> call3()
"""
b(1,2,3) b(1,2,3)
def call4(): def call4():
"""
>>> call4()
"""
b(1,2,3,4) b(1,2,3,4)
# the called function: # the called function:
...@@ -30,6 +28,13 @@ cdef int foo(int a, int b=1, int c=1): ...@@ -30,6 +28,13 @@ cdef int foo(int a, int b=1, int c=1):
return a+b*c return a+b*c
def test_foo(): def test_foo():
"""
>>> test_foo()
2
3
7
26
"""
print foo(1) print foo(1)
print foo(1, 2) print foo(1, 2)
print foo(1, 2, 3) print foo(1, 2, 3)
......
...@@ -36,46 +36,20 @@ True ...@@ -36,46 +36,20 @@ True
>>> import warnings >>> import warnings
>>> warnings.showwarning = simple_warn >>> warnings.showwarning = simple_warn
>>> mod_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-7
>>> div_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-1
>>> complex_expression(-150, 20, 19, -7)
verbose_call(20)
division with oppositely signed operands, C and Python semantics differ
verbose_call(19)
division with oppositely signed operands, C and Python semantics differ
-2
>>> mod_div_zero_int(25, 10, 2)
verbose_call(5)
2
>>> print(mod_div_zero_int(25, 10, 0))
verbose_call(5)
integer division or modulo by zero
>>> print(mod_div_zero_int(25, 0, 0))
integer division or modulo by zero
>>> mod_div_zero_float(25, 10, 2)
2.5
>>> print(mod_div_zero_float(25, 10, 0))
float division
>>> print(mod_div_zero_float(25, 0, 0))
float divmod()
>>> py_div_long(-5, -1)
5
>>> import sys
>>> maxint = getattr(sys, ((sys.version_info[0] >= 3) and 'maxsize' or 'maxint'))
>>> py_div_long(-maxint-1, -1)
Traceback (most recent call last):
...
OverflowError: value too large to perform division
""" """
def _all(seq):
for x in seq:
if not x:
return False
return True
try:
all
except NameError:
all = _all
cimport cython cimport cython
@cython.cdivision(False) @cython.cdivision(False)
...@@ -125,16 +99,34 @@ def test_cdiv_cmod(short a, short b): ...@@ -125,16 +99,34 @@ def test_cdiv_cmod(short a, short b):
@cython.cdivision(True) @cython.cdivision(True)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def mod_int_c_warn(int a, int b): def mod_int_c_warn(int a, int b):
"""
>>> mod_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-7
"""
return a % b return a % b
@cython.cdivision(True) @cython.cdivision(True)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def div_int_c_warn(int a, int b): def div_int_c_warn(int a, int b):
"""
>>> div_int_c_warn(-17, 10)
division with oppositely signed operands, C and Python semantics differ
-1
"""
return a // b return a // b
@cython.cdivision(False) @cython.cdivision(False)
@cython.cdivision_warnings(True) @cython.cdivision_warnings(True)
def complex_expression(int a, int b, int c, int d): def complex_expression(int a, int b, int c, int d):
"""
>>> complex_expression(-150, 20, 19, -7)
verbose_call(20)
division with oppositely signed operands, C and Python semantics differ
verbose_call(19)
division with oppositely signed operands, C and Python semantics differ
-2
"""
return (a // verbose_call(b)) % (verbose_call(c) // d) return (a // verbose_call(b)) % (verbose_call(c) // d)
cdef int verbose_call(int x): cdef int verbose_call(int x):
...@@ -146,6 +138,16 @@ cdef int verbose_call(int x): ...@@ -146,6 +138,16 @@ cdef int verbose_call(int x):
@cython.cdivision(False) @cython.cdivision(False)
def mod_div_zero_int(int a, int b, int c): def mod_div_zero_int(int a, int b, int c):
"""
>>> mod_div_zero_int(25, 10, 2)
verbose_call(5)
2
>>> print(mod_div_zero_int(25, 10, 0))
verbose_call(5)
integer division or modulo by zero
>>> print(mod_div_zero_int(25, 0, 0))
integer division or modulo by zero
"""
try: try:
return verbose_call(a % b) / c return verbose_call(a % b) / c
except ZeroDivisionError, ex: except ZeroDivisionError, ex:
...@@ -153,6 +155,14 @@ def mod_div_zero_int(int a, int b, int c): ...@@ -153,6 +155,14 @@ def mod_div_zero_int(int a, int b, int c):
@cython.cdivision(False) @cython.cdivision(False)
def mod_div_zero_float(float a, float b, float c): def mod_div_zero_float(float a, float b, float c):
"""
>>> mod_div_zero_float(25, 10, 2)
2.5
>>> print(mod_div_zero_float(25, 10, 0))
float division
>>> print(mod_div_zero_float(25, 0, 0))
float divmod()
"""
try: try:
return (a % b) / c return (a % b) / c
except ZeroDivisionError, ex: except ZeroDivisionError, ex:
...@@ -160,4 +170,14 @@ def mod_div_zero_float(float a, float b, float c): ...@@ -160,4 +170,14 @@ def mod_div_zero_float(float a, float b, float c):
@cython.cdivision(False) @cython.cdivision(False)
def py_div_long(long a, long b): def py_div_long(long a, long b):
"""
>>> py_div_long(-5, -1)
5
>>> import sys
>>> maxint = getattr(sys, ((sys.version_info[0] >= 3) and 'maxsize' or 'maxint'))
>>> py_div_long(-maxint-1, -1)
Traceback (most recent call last):
...
OverflowError: value too large to perform division
"""
return a / b return a / b
__doc__ = u"""
>>> test()
"""
cdef void ftang(): cdef void ftang():
cdef int x cdef int x
x = 0 x = 0
...@@ -16,6 +12,9 @@ cdef spam(int i, obj, object object): ...@@ -16,6 +12,9 @@ cdef spam(int i, obj, object object):
c = 0 c = 0
def test(): def test():
"""
>>> test()
"""
ftang() ftang()
foo(0, c'f') foo(0, c'f')
spam(25, None, None) spam(25, None, None)
__doc__ = u"""
>>> global_c_and_s()
99
abcdef
>>> local_c_and_s()
98
bcdefg
"""
cdef char c = 'c' cdef char c = 'c'
cdef char* s = 'abcdef' cdef char* s = 'abcdef'
def global_c_and_s(): def global_c_and_s():
"""
>>> global_c_and_s()
99
abcdef
"""
pys = s pys = s
print c print c
print (pys.decode(u'ASCII')) print (pys.decode(u'ASCII'))
def local_c_and_s(): def local_c_and_s():
"""
>>> local_c_and_s()
98
bcdefg
"""
cdef char c = 'b' cdef char c = 'b'
cdef char* s = 'bcdefg' cdef char* s = 'bcdefg'
pys = s pys = s
......
...@@ -13,11 +13,13 @@ __doc__ = u""" ...@@ -13,11 +13,13 @@ __doc__ = u"""
>>> (int1, long1) == f() >>> (int1, long1) == f()
True True
>>> f()
(45, 111)
""" """
def f(): def f():
"""
>>> f()
(45, 111)
"""
cdef int int1, int2, int3 cdef int int1, int2, int3
cdef char char1 cdef char char1
cdef long long1, long2 cdef long long1, long2
......
__doc__ = u""" def single_py(a, b):
"""
>>> single_py(1, 2) >>> single_py(1, 2)
True True
>>> single_py(2, 1) >>> single_py(2, 1)
False False
"""
return a < b
def cascaded_py(a, b, c):
"""
>>> cascaded_py(1, 2, 3) >>> cascaded_py(1, 2, 3)
True True
>>> cascaded_py(1, 2, -1) >>> cascaded_py(1, 2, -1)
False False
>>> cascaded_py(10, 2, 3) >>> cascaded_py(10, 2, 3)
False False
"""
return a < b < c
def single_c(int a, int b):
"""
>>> single_c(1, 2) >>> single_c(1, 2)
True True
>>> single_c(2, 1) >>> single_c(2, 1)
False False
"""
return a < b
def cascaded_c(double a, double b, double c):
"""
>>> cascaded_c(1, 2, 3) >>> cascaded_c(1, 2, 3)
True True
>>> cascaded_c(1, 2, -1) >>> cascaded_c(1, 2, -1)
False False
>>> cascaded_c(10, 2, 3) >>> cascaded_c(10, 2, 3)
False False
""" """
def single_py(a, b):
return a < b
def cascaded_py(a, b, c):
return a < b < c
def single_c(int a, int b):
return a < b
def cascaded_c(double a, double b, double c):
return a < b < c return a < b < c
def typed_cmp(list L): def typed_cmp(list L):
......
cdef char* cstring = "abcdefg"
cdef void spam(char *target):
cdef char* s = cstring
while s[0]:
target[0] = s[0]
s += 1
target += 1
target[0] = c'\0'
cdef struct Grail:
char silly[42]
def eggs():
"""
>>> print(str(eggs()).replace("b'", "'"))
('abcdefg', 'abcdefg')
"""
cdef char silly[42]
cdef Grail grail
spam(silly)
spam(grail.silly)
return silly, grail.silly
__doc__ = u""" #cdef extern from "complex.h":
# pass
cimport cython
def test_object_conversion(o):
"""
>>> test_object_conversion(2) >>> test_object_conversion(2)
((2+0j), (2+0j), (2+0j)) ((2+0j), (2+0j), (2+0j))
>>> test_object_conversion(2j - 0.5) >>> test_object_conversion(2j - 0.5)
((-0.5+2j), (-0.5+2j), (-0.5+2j)) ((-0.5+2j), (-0.5+2j), (-0.5+2j))
"""
cdef float complex a = o
cdef double complex b = o
cdef long double complex c = o
return (a, b, c)
def test_arithmetic(double complex z, double complex w):
"""
>>> test_arithmetic(2j, 4j) >>> test_arithmetic(2j, 4j)
(2j, -2j, 6j, -2j, (-8+0j), (0.5+0j)) (2j, -2j, 6j, -2j, (-8+0j), (0.5+0j))
>>> test_arithmetic(6+12j, 3j) >>> test_arithmetic(6+12j, 3j)
((6+12j), (-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j)) ((6+12j), (-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j))
>>> test_arithmetic(5-10j, 3+4j) >>> test_arithmetic(5-10j, 3+4j)
((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j)) ((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
## XXX this is not working
## >>> test_div_by_zero(4j)
## -0.25j
## >>> test_div_by_zero(0)
## Traceback (most recent call last):
## ...
## ZeroDivisionError: float division
"""
return +z, -z, z+w, z-w, z*w, z/w
## XXX this is not working ## XXX this is not working
## >>> test_div_by_zero(4j) ## @cython.cdivision(False)
## -0.25j ## def test_div_by_zero(double complex z):
## >>> test_div_by_zero(0) ## return 1/z
## Traceback (most recent call last):
## ...
## ZeroDivisionError: float division
def test_coercion(int a, float b, double c, float complex d, double complex e):
"""
>>> test_coercion(1, 1.5, 2.5, 4+1j, 10j) >>> test_coercion(1, 1.5, 2.5, 4+1j, 10j)
(1+0j) (1+0j)
(1.5+0j) (1.5+0j)
...@@ -26,7 +48,17 @@ __doc__ = u""" ...@@ -26,7 +48,17 @@ __doc__ = u"""
(4+1j) (4+1j)
10j 10j
(9+21j) (9+21j)
"""
cdef double complex z
z = a; print z
z = b; print z
z = c; print z
z = d; print z
z = e; print z
return z + a + b + c + d + e
def test_compare(double complex a, double complex b):
"""
>>> test_compare(3, 3) >>> test_compare(3, 3)
(True, False) (True, False)
>>> test_compare(3j, 3j) >>> test_compare(3j, 3j)
...@@ -35,89 +67,79 @@ __doc__ = u""" ...@@ -35,89 +67,79 @@ __doc__ = u"""
(False, True) (False, True)
>>> test_compare(3, 4) >>> test_compare(3, 4)
(False, True) (False, True)
"""
return a == b, a != b
def test_compare_coerce(double complex a, int b):
"""
>>> test_compare_coerce(3, 4) >>> test_compare_coerce(3, 4)
(False, True) (False, True)
>>> test_compare_coerce(4+1j, 4) >>> test_compare_coerce(4+1j, 4)
(False, True) (False, True)
>>> test_compare_coerce(4, 4) >>> test_compare_coerce(4, 4)
(True, False) (True, False)
"""
return a == b, a != b
def test_literal():
"""
>>> test_literal() >>> test_literal()
(5j, (1-2.5j)) (5j, (1-2.5j))
"""
return 5j, 1-2.5j
def test_real_imag(double complex z):
"""
>>> test_real_imag(1-3j) >>> test_real_imag(1-3j)
(1.0, -3.0) (1.0, -3.0)
>>> test_real_imag(5) >>> test_real_imag(5)
(5.0, 0.0) (5.0, 0.0)
>>> test_real_imag(1.5j) >>> test_real_imag(1.5j)
(0.0, 1.5) (0.0, 1.5)
"""
return z.real, z.imag
def test_real_imag_assignment(object a, double b):
"""
>>> test_real_imag_assignment(1, 2) >>> test_real_imag_assignment(1, 2)
(1+2j) (1+2j)
>>> test_real_imag_assignment(1.5, -3.5) >>> test_real_imag_assignment(1.5, -3.5)
(1.5-3.5j) (1.5-3.5j)
"""
>>> test_conjugate(2+3j)
(2-3j)
>>> test_conjugate_double(2+3j)
(2-3j)
"""
#cdef extern from "complex.h":
# pass
cimport cython
def test_object_conversion(o):
cdef float complex a = o
cdef double complex b = o
cdef long double complex c = o
return (a, b, c)
def test_arithmetic(double complex z, double complex w):
return +z, -z, z+w, z-w, z*w, z/w
## XXX this is not working
## @cython.cdivision(False)
## def test_div_by_zero(double complex z):
## return 1/z
def test_coercion(int a, float b, double c, float complex d, double complex e):
cdef double complex z
z = a; print z
z = b; print z
z = c; print z
z = d; print z
z = e; print z
return z + a + b + c + d + e
def test_compare(double complex a, double complex b):
return a == b, a != b
def test_compare_coerce(double complex a, int b):
return a == b, a != b
def test_literal():
return 5j, 1-2.5j
def test_real_imag(double complex z):
return z.real, z.imag
def test_real_imag_assignment(object a, double b):
cdef double complex z cdef double complex z
z.real = a z.real = a
z.imag = b z.imag = b
return z return z
def test_conjugate(float complex z): def test_conjugate(float complex z):
"""
>>> test_conjugate(2+3j)
(2-3j)
"""
return z.conjugate() return z.conjugate()
def test_conjugate_double(double complex z): def test_conjugate_double(double complex z):
"""
>>> test_conjugate_double(2+3j)
(2-3j)
"""
return z.conjugate() return z.conjugate()
ctypedef double complex cdouble ctypedef double complex cdouble
def test_conjugate_typedef(cdouble z): def test_conjugate_typedef(cdouble z):
return z.conjugate() return z.conjugate()
ctypedef double mydouble
def test_coerce_typedef_multiply(mydouble x, double complex z):
"""
>>> test_coerce_typedef_multiply(3, 1j)
(3j)
"""
return x * z
cpdef double complex complex_retval():
"""
>>> complex_retval()
1j
"""
return 1j
...@@ -8,4 +8,3 @@ if sys.version_info[0] >= 3: ...@@ -8,4 +8,3 @@ if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u" u'", u" '") __doc__ = __doc__.replace(u" u'", u" '")
spam = u"C string 1" + u"C string 2" spam = u"C string 1" + u"C string 2"
__doc__ = u"""
>>> add() == 1+2+3+4
True
>>> add_var(10) == 1+2+10+3+4
True
>>> neg() == -1 -2 - (-3+4)
True
>>> long_int_mix() == 1 + (2 * 3) // 2
True
>>> if IS_PY3: type(long_int_mix()) is int
... else: type(long_int_mix()) is long
True
>>> char_int_mix() == 1 + (ord(' ') * 3) // 2 + ord('A')
True
>>> int_cast() == 1 + 2 * 6000
True
>>> mul() == 1*60*1000
True
>>> arithm() == 9*2+3*8//6-10
True
>>> parameters() == _func(-1 -2, - (-3+4), 1*2*3)
True
>>> lists() == [1,2,3] + [4,5,6]
True
"""
import sys import sys
IS_PY3 = sys.version_info[0] >= 3 IS_PY3 = sys.version_info[0] >= 3
...@@ -31,31 +5,74 @@ def _func(a,b,c): ...@@ -31,31 +5,74 @@ def _func(a,b,c):
return a+b+c return a+b+c
def add(): def add():
"""
>>> add() == 1+2+3+4
True
"""
return 1+2+3+4 return 1+2+3+4
def add_var(a): def add_var(a):
"""
>>> add_var(10) == 1+2+10+3+4
True
"""
return 1+2 +a+ 3+4 return 1+2 +a+ 3+4
def neg(): def neg():
"""
>>> neg() == -1 -2 - (-3+4)
True
"""
return -1 -2 - (-3+4) return -1 -2 - (-3+4)
def long_int_mix(): def long_int_mix():
"""
>>> long_int_mix() == 1 + (2 * 3) // 2
True
>>> if IS_PY3: type(long_int_mix()) is int
... else: type(long_int_mix()) is long
True
"""
return 1L + (2 * 3L) // 2 return 1L + (2 * 3L) // 2
def char_int_mix(): def char_int_mix():
"""
>>> char_int_mix() == 1 + (ord(' ') * 3) // 2 + ord('A')
True
"""
return 1L + (c' ' * 3L) // 2 + c'A' return 1L + (c' ' * 3L) // 2 + c'A'
def int_cast(): def int_cast():
"""
>>> int_cast() == 1 + 2 * 6000
True
"""
return <int>(1 + 2 * 6000) return <int>(1 + 2 * 6000)
def mul(): def mul():
"""
>>> mul() == 1*60*1000
True
"""
return 1*60*1000 return 1*60*1000
def arithm(): def arithm():
"""
>>> arithm() == 9*2+3*8//6-10
True
"""
return 9*2+3*8//6-10 return 9*2+3*8//6-10
def parameters(): def parameters():
"""
>>> parameters() == _func(-1 -2, - (-3+4), 1*2*3)
True
"""
return _func(-1 -2, - (-3+4), 1*2*3) return _func(-1 -2, - (-3+4), 1*2*3)
def lists(): def lists():
"""
>>> lists() == [1,2,3] + [4,5,6]
True
"""
return [1,2,3] + [4,5,6] return [1,2,3] + [4,5,6]
__doc__ = """ cdef class A:
"""
>>> A().is_True() >>> A().is_True()
True True
>>> A().is_False() >>> A().is_False()
False False
"""
>>> B().is_True()
True
>>> B().is_False()
False
"""
cdef class A:
cpdef is_True(self): cpdef is_True(self):
return True return True
cpdef is_False(self): cpdef is_False(self):
return not self.is_True() return not self.is_True()
class B(A): class B(A):
"""
>>> B().is_True()
True
>>> B().is_False()
False
"""
def is_True(self): def is_True(self):
return True return True
__doc__ = """
>>> f()
{'x': 1}
"""
cimport crashT245_pxd cimport crashT245_pxd
def f(): def f():
"""
>>> f()
{'x': 1}
"""
cdef crashT245_pxd.MyStruct s cdef crashT245_pxd.MyStruct s
s.x = 1 s.x = 1
print s print s
__doc__ = u"""
>>> test_i()
>>> test_c()
>>> test_p()
>>> test_g()
"""
cdef struct Grail cdef struct Grail
cdef struct Spam: cdef struct Spam:
...@@ -41,19 +34,31 @@ cdef void eggs_g(Spam s): ...@@ -41,19 +34,31 @@ cdef void eggs_g(Spam s):
spam = ham spam = ham
def test_i(): def test_i():
"""
>>> test_i()
"""
spam.i = 1 spam.i = 1
eggs_i(spam) eggs_i(spam)
def test_c(): def test_c():
"""
>>> test_c()
"""
spam.c = c'a' spam.c = c'a'
eggs_c(spam) eggs_c(spam)
def test_p(): def test_p():
"""
>>> test_p()
"""
cdef float f cdef float f
spam.p[0] = &f spam.p[0] = &f
eggs_p(spam) eggs_p(spam)
def test_g(): def test_g():
"""
>>> test_g()
"""
cdef Grail l cdef Grail l
spam.g = &l spam.g = &l
eggs_g(spam) eggs_g(spam)
__doc__ = u"""
>>> f()
1
>>> g()
2
>>> h()
3
"""
DEF NO = 0 DEF NO = 0
DEF YES = 1 DEF YES = 1
def f(): def f():
"""
>>> f()
1
"""
cdef int i cdef int i
IF YES: IF YES:
i = 1 i = 1
...@@ -21,6 +16,10 @@ def f(): ...@@ -21,6 +16,10 @@ def f():
return i return i
def g(): def g():
"""
>>> g()
2
"""
cdef int i cdef int i
IF NO: IF NO:
i = 1 i = 1
...@@ -31,6 +30,10 @@ def g(): ...@@ -31,6 +30,10 @@ def g():
return i return i
def h(): def h():
"""
>>> h()
3
"""
cdef int i cdef int i
IF NO: IF NO:
i = 1 i = 1
......
This diff is collapsed.
This diff is collapsed.
__doc__ = u"""
>>> f()
"""
def f(): def f():
"""
>>> f()
"""
cdef char a_char cdef char a_char
cdef short a_short cdef short a_short
cdef int i1, i2 cdef int i1, i2
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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