Commit a2236526 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Merge (++, see details)

Also fixed a bug that the merge revealed.
Also added CythonTransform.current_directives.
parents d2f4df7a e05e7c05
...@@ -11,3 +11,5 @@ build/ ...@@ -11,3 +11,5 @@ build/
*.orig *.orig
*.rej *.rej
*.dep *.dep
tags
import re
from Cython.Compiler.Visitor import CythonTransform
from Cython.Compiler.Nodes import DefNode, CFuncDefNode
from Cython.Compiler.Errors import CompileError
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler import Options
class EmbedSignature(CythonTransform):
SPECIAL_METHOD_RE = re.compile(r'__\w+__')
def __init__(self, context):
super(EmbedSignature, self).__init__(context)
self.denv = None # XXX
self.is_in_class = False
self.class_name = None
def _fmt_basic_c_type_modifiers(self, ctype):
longness = ctype.longness
modifiers = ''
if longness < 0:
modifiers = 'short '
elif longness > 0:
modifiers = 'long ' * longness
signed = ctype.signed
if signed == 0:
modifiers = 'unsigned ' + modifiers
elif signed == 2:
modifiers = 'signed ' + modifiers
return modifiers[:-1] # strip final space
def _fmt_arg_type(self, arg):
try:
base_type = arg.base_type
arg_type = base_type.name
except AttributeError:
return ''
if base_type.is_basic_c_type:
modifiers = self._fmt_basic_c_type_modifiers(base_type)
if modifiers:
arg_type = '%s %s' % (modifiers, arg_type)
return arg_type
def _fmt_arg_name(self, arg):
try:
return arg.declarator.name
except AttributeError:
return arg.declarator.base.name
def _fmt_arg_defv(self, arg):
if not arg.default:
return None
try:
denv = self.denv # XXX
ctval = arg.default.compile_time_value(self.denv)
return '%s' % ctval
except Exception:
try:
return arg.default.name # XXX
except AttributeError:
return '<???>'
def _fmt_arg(self, arg):
arg_type = self._fmt_arg_type(arg)
arg_name = self._fmt_arg_name(arg)
arg_defv = self._fmt_arg_defv(arg)
doc = arg_name
if arg_type:
doc = ('%s ' % arg_type) + doc
if arg_defv:
doc = doc + ('=%s' % arg_defv)
return doc
def _fmt_arglist(self, args,
npargs=0, pargs=None,
nkargs=0, kargs=None):
arglist = []
for arg in args:
arg_doc = self._fmt_arg(arg)
arglist.append(arg_doc)
if pargs:
arglist.insert(npargs, '*%s' % pargs.name)
elif nkargs:
arglist.insert(npargs, '*')
if kargs:
arglist.append('**%s' % kargs.name)
return arglist
def _fmt_ret_type(self, ret):
ret_type = ret.name
if ret_type is None:
return ''
modifiers = self._fmt_basic_c_type_modifiers(ret)
if modifiers:
ret_type = '%s %s' % (modifiers, ret_type)
return ret_type
def _fmt_signature(self, cls_name, func_name, args,
npargs=0, pargs=None,
nkargs=0, kargs=None,
return_type=None):
arglist = self._fmt_arglist(args,
npargs, pargs,
nkargs, kargs)
arglist_doc = ', '.join(arglist)
func_doc = '%s(%s)' % (func_name, arglist_doc)
if cls_name:
func_doc = '%s.%s' % (cls_name, func_doc)
if return_type:
ret_doc = self._fmt_ret_type(return_type)
if ret_doc:
func_doc = '%s -> %s' % (func_doc, ret_doc)
return func_doc
def _embed_signature(self, signature, node_doc):
if node_doc:
return signature + '\n' + node_doc
else:
return signature
def __call__(self, node):
if not Options.docstrings:
return node
else:
return super(EmbedSignature, self).__call__(node)
def visit_ClassDefNode(self, node):
oldincls = self.is_in_class
oldname = self.class_name
self.is_in_class = True
try:
# PyClassDefNode
self.class_name = node.name
except AttributeError:
# CClassDefNode
self.class_name = node.class_name
self.visitchildren(node)
self.is_in_class = oldincls
self.class_name = oldname
return node
def visit_FuncDefNode(self, node):
if not self.current_directives['embedsignature']:
return node
signature = None
if type(node) is DefNode: # def FOO(...):
special_method = (self.is_in_class and \
self.SPECIAL_METHOD_RE.match(node.name))
if not special_method:
nkargs = getattr(node, 'num_kwonly_args', 0)
npargs = len(node.args) - nkargs
signature = self._fmt_signature(
self.class_name, node.name, node.args,
npargs, node.star_arg,
nkargs, node.starstar_arg,
return_type=None)
elif type(node) is CFuncDefNode:
if node.overridable: # cpdef FOO(...):
signature = self._fmt_signature(
self.class_name, node.declarator.base.name,
node.declarator.args,
return_type=node.base_type)
else: # should not fall here ...
assert False
if signature:
new_doc = self._embed_signature(signature, node.doc)
node.doc = EncodedString(new_doc) # XXX
return node
...@@ -92,7 +92,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform): ...@@ -92,7 +92,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform):
mode = entry.type.mode mode = entry.type.mode
if mode == 'full': if mode == 'full':
suboffsetvars = [var(Naming.bufsuboffset_prefix, i, "-1") for i in range(entry.type.ndim)] suboffsetvars = [var(Naming.bufsuboffset_prefix, i, "-1") for i in range(entry.type.ndim)]
elif mode == 'strided': else:
suboffsetvars = None suboffsetvars = None
entry.buffer_aux = Symtab.BufferAux(bufinfo, stridevars, shapevars, suboffsetvars) entry.buffer_aux = Symtab.BufferAux(bufinfo, stridevars, shapevars, suboffsetvars)
...@@ -121,7 +121,7 @@ ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option' ...@@ -121,7 +121,7 @@ ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option'
ERR_BUF_TOO_MANY = 'Too many buffer options' ERR_BUF_TOO_MANY = 'Too many buffer options'
ERR_BUF_DUP = '"%s" buffer option already supplied' ERR_BUF_DUP = '"%s" buffer option already supplied'
ERR_BUF_MISSING = '"%s" missing' ERR_BUF_MISSING = '"%s" missing'
ERR_BUF_MODE = 'Only allowed buffer modes are "full" or "strided" (as a compile-time string)' ERR_BUF_MODE = 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)'
ERR_BUF_NDIM = 'ndim must be a non-negative integer' ERR_BUF_NDIM = 'ndim must be a non-negative integer'
ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct' ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct'
...@@ -175,7 +175,7 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee ...@@ -175,7 +175,7 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee
raise CompileError(globalpos, ERR_BUF_NDIM) raise CompileError(globalpos, ERR_BUF_NDIM)
mode = options.get("mode") mode = options.get("mode")
if mode and not (mode in ('full', 'strided')): if mode and not (mode in ('full', 'strided', 'c', 'fortran')):
raise CompileError(globalpos, ERR_BUF_MODE) raise CompileError(globalpos, ERR_BUF_MODE)
return options return options
...@@ -188,10 +188,15 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee ...@@ -188,10 +188,15 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee
def get_flags(buffer_aux, buffer_type): def get_flags(buffer_aux, buffer_type):
flags = 'PyBUF_FORMAT' flags = 'PyBUF_FORMAT'
if buffer_type.mode == 'full': mode = buffer_type.mode
if mode == 'full':
flags += '| PyBUF_INDIRECT' flags += '| PyBUF_INDIRECT'
elif buffer_type.mode == 'strided': elif mode == 'strided':
flags += '| PyBUF_STRIDES' flags += '| PyBUF_STRIDES'
elif mode == 'c':
flags += '| PyBUF_C_CONTIGUOUS'
elif mode == 'fortran':
flags += '| PyBUF_F_CONTIGUOUS'
else: else:
assert False assert False
if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE" if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE"
...@@ -242,9 +247,7 @@ def put_acquire_arg_buffer(entry, code, pos): ...@@ -242,9 +247,7 @@ def put_acquire_arg_buffer(entry, code, pos):
# entry.buffer_aux.buffer_info_var.cname)) # entry.buffer_aux.buffer_info_var.cname))
def get_release_buffer_code(entry): def get_release_buffer_code(entry):
return "__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s)" % ( return "__Pyx_SafeReleaseBuffer(&%s)" % entry.buffer_aux.buffer_info_var.cname
entry.cname,
entry.buffer_aux.buffer_info_var.cname)
def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
is_initialized, pos, code): is_initialized, pos, code):
...@@ -274,8 +277,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, ...@@ -274,8 +277,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
if is_initialized: if is_initialized:
# Release any existing buffer # Release any existing buffer
code.putln('__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s);' % ( code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct)
lhs_cname, bufstruct))
# Acquire # Acquire
retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type) retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type)
code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname)) code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
...@@ -370,28 +372,43 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, options, pos, cod ...@@ -370,28 +372,43 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, options, pos, cod
code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape.cname)) code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape.cname))
# Create buffer lookup and return it # Create buffer lookup and return it
# This is done via utility macros/inline functions, which vary
# according to the access mode used.
params = [] params = []
nd = entry.type.ndim nd = entry.type.ndim
if entry.type.mode == 'full': mode = entry.type.mode
if mode == 'full':
for i, s, o in zip(index_cnames, bufaux.stridevars, bufaux.suboffsetvars): for i, s, o in zip(index_cnames, bufaux.stridevars, bufaux.suboffsetvars):
params.append(i) params.append(i)
params.append(s.cname) params.append(s.cname)
params.append(o.cname) params.append(o.cname)
funcname = "__Pyx_BufPtrFull%dd" % nd funcname = "__Pyx_BufPtrFull%dd" % nd
funcgen = buf_lookup_full_code funcgen = buf_lookup_full_code
else: else:
if mode == 'strided':
funcname = "__Pyx_BufPtrStrided%dd" % nd
funcgen = buf_lookup_strided_code
elif mode == 'c':
funcname = "__Pyx_BufPtrCContig%dd" % nd
funcgen = buf_lookup_c_code
elif mode == 'fortran':
funcname = "__Pyx_BufPtrFortranContig%dd" % nd
funcgen = buf_lookup_fortran_code
else:
assert False
for i, s in zip(index_cnames, bufaux.stridevars): for i, s in zip(index_cnames, bufaux.stridevars):
params.append(i) params.append(i)
params.append(s.cname) params.append(s.cname)
funcname = "__Pyx_BufPtrStrided%dd" % nd
funcgen = buf_lookup_strided_code
# Make sure the utility code is available # Make sure the utility code is available
code.globalstate.use_generated_code(funcgen, name=funcname, nd=nd) code.globalstate.use_generated_code(funcgen, name=funcname, nd=nd)
ptrcode = "%s(%s.buf, %s)" % (funcname, bufstruct, ", ".join(params)) ptr_type = entry.type.buffer_ptr_type
return entry.type.buffer_ptr_type.cast_code(ptrcode) ptrcode = "%s(%s, %s.buf, %s)" % (funcname,
ptr_type.declaration_code(""),
bufstruct,
", ".join(params))
return ptrcode
def use_empty_bufstruct_code(env, max_ndim): def use_empty_bufstruct_code(env, max_ndim):
...@@ -402,33 +419,59 @@ def use_empty_bufstruct_code(env, max_ndim): ...@@ -402,33 +419,59 @@ def use_empty_bufstruct_code(env, max_ndim):
env.use_utility_code([code, ""], "empty_bufstruct_code") env.use_utility_code([code, ""], "empty_bufstruct_code")
def buf_lookup_strided_code(proto, defin, name, nd):
"""
Generates a buffer lookup function for the right number
of dimensions. The function gives back a void* at the right location.
"""
# _i_ndex, _s_tride
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)])
proto.putln("#define %s(buf, %s) ((char*)buf + %s)" % (name, args, offset))
def buf_lookup_full_code(proto, defin, name, nd): def buf_lookup_full_code(proto, defin, name, nd):
""" """
Generates a buffer lookup function for the right number Generates a buffer lookup function for the right number
of dimensions. The function gives back a void* at the right location. of dimensions. The function gives back a void* at the right location.
""" """
# _i_ndex, _s_tride, sub_o_ffset # _i_ndex, _s_tride, sub_o_ffset
args = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)]) macroargs = ", ".join(["i%d, s%d, o%d" % (i, i, i) for i in range(nd)])
proto.putln("static INLINE void* %s(void* buf, %s);" % (name, args)) proto.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name, macroargs, name, macroargs))
funcargs = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)])
proto.putln("static INLINE void* %s_imp(void* buf, %s);" % (name, funcargs))
defin.putln(dedent(""" defin.putln(dedent("""
static INLINE void* %s(void* buf, %s) { static INLINE void* %s_imp(void* buf, %s) {
char* ptr = (char*)buf; char* ptr = (char*)buf;
""") % (name, args) + "".join([dedent("""\ """) % (name, funcargs) + "".join([dedent("""\
ptr += s%d * i%d; ptr += s%d * i%d;
if (o%d >= 0) ptr = *((char**)ptr) + o%d; if (o%d >= 0) ptr = *((char**)ptr) + o%d;
""") % (i, i, i, i) for i in range(nd)] """) % (i, i, i, i) for i in range(nd)]
) + "\nreturn ptr;\n}") ) + "\nreturn ptr;\n}")
def buf_lookup_strided_code(proto, defin, name, nd):
"""
Generates a buffer lookup function for the right number
of dimensions. The function gives back a void* at the right location.
"""
# _i_ndex, _s_tride
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)])
proto.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name, args, offset))
def buf_lookup_c_code(proto, defin, name, nd):
"""
Similar to strided lookup, but can assume that the last dimension
doesn't need a multiplication as long as.
Still we keep the same signature for now.
"""
if nd == 1:
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
else:
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd - 1)])
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, nd - 1))
def buf_lookup_fortran_code(proto, defin, name, nd):
"""
Like C lookup, but the first index is optimized instead.
"""
if nd == 1:
proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name)
else:
args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)])
offset = " + ".join(["i%d * s%d" % (i, i) for i in range(1, nd)])
proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, 0))
# #
# Utils for creating type string checkers # Utils for creating type string checkers
...@@ -537,12 +580,11 @@ def get_getbuffer_code(dtype, code): ...@@ -537,12 +580,11 @@ def get_getbuffer_code(dtype, code):
} }
ts = buf->format; ts = buf->format;
ts = __Pyx_ConsumeWhitespace(ts); ts = __Pyx_ConsumeWhitespace(ts);
ts = __Pyx_BufferTypestringCheckEndian(ts);
if (!ts) goto fail; if (!ts) goto fail;
ts = __Pyx_ConsumeWhitespace(ts);
ts = %(itemchecker)s(ts); ts = %(itemchecker)s(ts);
if (!ts) goto fail; if (!ts) goto fail;
ts = __Pyx_ConsumeWhitespace(ts); ts = __Pyx_ConsumeWhitespace(ts);
if (!ts) goto fail;
if (*ts != 0) { if (*ts != 0) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Expected non-struct buffer data type (expected end, got '%%s')", ts); "Expected non-struct buffer data type (expected end, got '%%s')", ts);
...@@ -569,6 +611,9 @@ def buffer_type_checker(dtype, code): ...@@ -569,6 +611,9 @@ def buffer_type_checker(dtype, code):
return funcname return funcname
def use_py2_buffer_functions(env): def use_py2_buffer_functions(env):
# Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2.
# For >= 2.6 we do double mode -- use the new buffer interface on objects
# which has the right tp_flags set, but emulation otherwise.
codename = "PyObject_GetBuffer" # just a representative unique key codename = "PyObject_GetBuffer" # just a representative unique key
# Search all types for __getbuffer__ overloads # Search all types for __getbuffer__ overloads
...@@ -589,8 +634,12 @@ def use_py2_buffer_functions(env): ...@@ -589,8 +634,12 @@ def use_py2_buffer_functions(env):
find_buffer_types(env) find_buffer_types(env)
code = dedent(""" code = dedent("""
#if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER) #if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
#if PY_VERSION_HEX >= 0x02060000
if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)
return PyObject_GetBuffer(obj, view, flags);
#endif
""") """)
if len(types) > 0: if len(types) > 0:
clause = "if" clause = "if"
...@@ -606,7 +655,9 @@ def use_py2_buffer_functions(env): ...@@ -606,7 +655,9 @@ def use_py2_buffer_functions(env):
code += dedent(""" code += dedent("""
} }
static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view) { static void __Pyx_ReleaseBuffer(Py_buffer *view) {
PyObject* obj = view->obj;
if (obj) {
""") """)
if len(types) > 0: if len(types) > 0:
clause = "if" clause = "if"
...@@ -615,18 +666,21 @@ def use_py2_buffer_functions(env): ...@@ -615,18 +666,21 @@ def use_py2_buffer_functions(env):
code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release) code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release)
clause = "else if" clause = "else if"
code += dedent(""" code += dedent("""
Py_DECREF(obj);
view->obj = NULL;
}
} }
#endif #endif
""") """)
env.use_utility_code([dedent("""\ env.use_utility_code([dedent("""\
#if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER) #if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view); static void __Pyx_ReleaseBuffer(Py_buffer *view);
#else #else
#define __Pyx_GetBuffer PyObject_GetBuffer #define __Pyx_GetBuffer PyObject_GetBuffer
#define __Pyx_ReleaseBuffer PyObject_ReleaseBuffer #define __Pyx_ReleaseBuffer PyBuffer_Release
#endif #endif
"""), code], codename) """), code], codename)
...@@ -655,20 +709,20 @@ static void __Pyx_RaiseBufferIndexError(int axis) { ...@@ -655,20 +709,20 @@ static void __Pyx_RaiseBufferIndexError(int axis) {
# exporter. # exporter.
# #
acquire_utility_code = ["""\ acquire_utility_code = ["""\
static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info); static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf); /*proto*/ static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf); /*proto*/
static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts); /*proto*/ static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts); /*proto*/
static INLINE const char* __Pyx_BufferTypestringCheckEndian(const char* ts); /*proto*/
static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim); /*proto*/ static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim); /*proto*/
""", """ """, """
static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info) { static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
if (info->buf == NULL) return; if (info->buf == NULL) return;
if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL; if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL;
__Pyx_ReleaseBuffer(obj, info); __Pyx_ReleaseBuffer(info);
} }
static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) {
buf->buf = NULL; buf->buf = NULL;
buf->obj = NULL;
buf->strides = __Pyx_zeros; buf->strides = __Pyx_zeros;
buf->shape = __Pyx_zeros; buf->shape = __Pyx_zeros;
buf->suboffsets = __Pyx_minusones; buf->suboffsets = __Pyx_minusones;
...@@ -677,39 +731,22 @@ static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { ...@@ -677,39 +731,22 @@ static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) {
static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts) { static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts) {
while (1) { while (1) {
switch (*ts) { switch (*ts) {
case '@':
case 10: case 10:
case 13: case 13:
case ' ': case ' ':
++ts; ++ts;
default: break;
return ts;
}
}
}
static INLINE const char* __Pyx_BufferTypestringCheckEndian(const char* ts) {
int num = 1;
int little_endian = ((char*)&num)[0];
int ok = 1;
switch (*ts) {
case '@':
case '=': case '=':
++ts; break;
case '<': case '<':
if (little_endian) ++ts;
else ok = 0;
break;
case '>': case '>':
case '!': case '!':
if (!little_endian) ++ts; PyErr_SetString(PyExc_ValueError, "Buffer acquisition error: Only native byte order, size and alignment supported.");
else ok = 0;
break;
}
if (!ok) {
PyErr_Format(PyExc_ValueError, "Buffer has wrong endianness (rejecting on '%s')", ts);
return NULL; return NULL;
} default:
return ts; return ts;
}
}
} }
static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim) { static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim) {
......
...@@ -104,14 +104,15 @@ builtin_types_table = [ ...@@ -104,14 +104,15 @@ builtin_types_table = [
builtin_structs_table = [ builtin_structs_table = [
('Py_buffer', 'Py_buffer', ('Py_buffer', 'Py_buffer',
[("buf", PyrexTypes.c_void_ptr_type), [("buf", PyrexTypes.c_void_ptr_type),
("obj", PyrexTypes.py_object_type),
("len", PyrexTypes.c_py_ssize_t_type), ("len", PyrexTypes.c_py_ssize_t_type),
("itemsize", PyrexTypes.c_py_ssize_t_type),
("readonly", PyrexTypes.c_bint_type), ("readonly", PyrexTypes.c_bint_type),
("format", PyrexTypes.c_char_ptr_type),
("ndim", PyrexTypes.c_int_type), ("ndim", PyrexTypes.c_int_type),
("format", PyrexTypes.c_char_ptr_type),
("shape", PyrexTypes.c_py_ssize_t_ptr_type), ("shape", PyrexTypes.c_py_ssize_t_ptr_type),
("strides", PyrexTypes.c_py_ssize_t_ptr_type), ("strides", PyrexTypes.c_py_ssize_t_ptr_type),
("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type), ("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
("itemsize", PyrexTypes.c_py_ssize_t_type),
("internal", PyrexTypes.c_void_ptr_type), ("internal", PyrexTypes.c_void_ptr_type),
]) ])
] ]
......
...@@ -36,7 +36,7 @@ Options: ...@@ -36,7 +36,7 @@ Options:
-D, --no-docstrings Remove docstrings. -D, --no-docstrings Remove docstrings.
-a, --annotate Produce a colorized HTML version of the source. -a, --annotate Produce a colorized HTML version of the source.
--convert-range Convert for loops using range() function to for...from loops. --line-directives Produce #line directives pointing to the .pyx source
--cplus Output a c++ rather than c file. --cplus Output a c++ rather than c file.
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
""" """
...@@ -114,6 +114,8 @@ def parse_command_line(args): ...@@ -114,6 +114,8 @@ def parse_command_line(args):
Options.annotate = True Options.annotate = True
elif option == "--convert-range": elif option == "--convert-range":
Options.convert_range = True Options.convert_range = True
elif option == "--line-directives":
options.emit_linenums = True
elif option in ("-X", "--directive"): elif option in ("-X", "--directive"):
try: try:
options.pragma_overrides = Options.parse_option_list(pop_arg()) options.pragma_overrides = Options.parse_option_list(pop_arg())
......
...@@ -167,13 +167,14 @@ class GlobalState(object): ...@@ -167,13 +167,14 @@ class GlobalState(object):
directives = {} directives = {}
def __init__(self, rootwriter): def __init__(self, rootwriter, emit_linenums=False):
self.filename_table = {} self.filename_table = {}
self.filename_list = [] self.filename_list = []
self.input_file_contents = {} self.input_file_contents = {}
self.used_utility_code = set() self.used_utility_code = set()
self.declared_cnames = {} self.declared_cnames = {}
self.pystring_table_needed = False self.pystring_table_needed = False
self.emit_linenums = emit_linenums
def initwriters(self, rootwriter): def initwriters(self, rootwriter):
self.utilprotowriter = rootwriter.new_writer() self.utilprotowriter = rootwriter.new_writer()
...@@ -384,6 +385,8 @@ class GlobalState(object): ...@@ -384,6 +385,8 @@ class GlobalState(object):
writer.insert(self.utilprotowriter) writer.insert(self.utilprotowriter)
def put_utility_code_defs(self, writer): def put_utility_code_defs(self, writer):
if self.emit_linenums:
writer.write('\n#line 1 "cython_utility"\n')
writer.insert(self.utildefwriter) writer.insert(self.utildefwriter)
...@@ -421,19 +424,21 @@ class CCodeWriter(object): ...@@ -421,19 +424,21 @@ class CCodeWriter(object):
# generation (labels and temps state etc.) # generation (labels and temps state etc.)
# globalstate GlobalState contains state global for a C file (input file info, # globalstate GlobalState contains state global for a C file (input file info,
# utility code, declared constants etc.) # utility code, declared constants etc.)
# emit_linenums boolean whether or not to write #line pragmas
def __init__(self, create_from=None, buffer=None, copy_formatting=False): def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
if buffer is None: buffer = StringIOTree() if buffer is None: buffer = StringIOTree()
self.buffer = buffer self.buffer = buffer
self.marker = None self.marker = None
self.last_marker_line = 0 self.last_marker_line = 0
self.source_desc = ""
self.funcstate = None self.funcstate = None
self.level = 0 self.level = 0
self.bol = 1 self.bol = 1
if create_from is None: if create_from is None:
# Root CCodeWriter # Root CCodeWriter
self.globalstate = GlobalState(self) self.globalstate = GlobalState(self, emit_linenums=emit_linenums)
self.globalstate.initwriters(self) self.globalstate.initwriters(self)
# ^^^ need seperate step because this will reference self.globalstate # ^^^ need seperate step because this will reference self.globalstate
else: else:
...@@ -443,6 +448,10 @@ class CCodeWriter(object): ...@@ -443,6 +448,10 @@ class CCodeWriter(object):
if copy_formatting: if copy_formatting:
self.level = create_from.level self.level = create_from.level
self.bol = create_from.bol self.bol = create_from.bol
if emit_linenums is None:
self.emit_linenums = self.globalstate.emit_linenums
else:
self.emit_linenums = emit_linenums
def create_new(self, create_from, buffer, copy_formatting): def create_new(self, create_from, buffer, copy_formatting):
# polymorphic constructor -- very slightly more versatile # polymorphic constructor -- very slightly more versatile
...@@ -510,6 +519,8 @@ class CCodeWriter(object): ...@@ -510,6 +519,8 @@ class CCodeWriter(object):
def putln(self, code = ""): def putln(self, code = ""):
if self.marker and self.bol: if self.marker and self.bol:
self.emit_marker() self.emit_marker()
if self.emit_linenums and self.last_marker_line != 0:
self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
if code: if code:
self.put(code) self.put(code)
self.write("\n"); self.write("\n");
...@@ -586,7 +597,8 @@ class CCodeWriter(object): ...@@ -586,7 +597,8 @@ class CCodeWriter(object):
marker = u'"%s":%d\n%s\n' % ( marker = u'"%s":%d\n%s\n' % (
source_desc.get_escaped_description(), line, u'\n'.join(lines)) source_desc.get_escaped_description(), line, u'\n'.join(lines))
self.marker = (line, marker) self.marker = (line, marker)
if self.emit_linenums:
self.source_desc = source_desc.get_escaped_description()
def put_label(self, lbl): def put_label(self, lbl):
if lbl in self.funcstate.labels_used: if lbl in self.funcstate.labels_used:
......
...@@ -1423,7 +1423,7 @@ class IndexNode(ExprNode): ...@@ -1423,7 +1423,7 @@ class IndexNode(ExprNode):
elif not skip_child_analysis: elif not skip_child_analysis:
self.index.analyse_types(env) self.index.analyse_types(env)
if self.base.type.is_pyobject: if self.base.type.is_pyobject:
if self.index.type.is_int: if self.index.type.is_int and not self.index.type.is_longlong:
self.original_index_type = self.index.type self.original_index_type = self.index.type
self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
if getting: if getting:
...@@ -1886,6 +1886,9 @@ class SimpleCallNode(CallNode): ...@@ -1886,6 +1886,9 @@ class SimpleCallNode(CallNode):
arg_code = actual_arg.result_as(formal_arg.type) arg_code = actual_arg.result_as(formal_arg.type)
arg_list_code.append(arg_code) arg_list_code.append(arg_code)
if func_type.is_overridable:
arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
if func_type.optional_arg_count: if func_type.optional_arg_count:
if expected_nargs == actual_nargs: if expected_nargs == actual_nargs:
optional_args = 'NULL' optional_args = 'NULL'
...@@ -1897,9 +1900,9 @@ class SimpleCallNode(CallNode): ...@@ -1897,9 +1900,9 @@ class SimpleCallNode(CallNode):
arg_list_code.append(actual_arg.result_code) arg_list_code.append(actual_arg.result_code)
result = "%s(%s)" % (self.function.result_code, result = "%s(%s)" % (self.function.result_code,
join(arg_list_code, ", ")) join(arg_list_code, ", "))
if self.wrapper_call or \ # if self.wrapper_call or \
self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable: # self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result) # result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
return result return result
def generate_result_code(self, code): def generate_result_code(self, code):
...@@ -2641,7 +2644,7 @@ class ListComprehensionAppendNode(ExprNode): ...@@ -2641,7 +2644,7 @@ class ListComprehensionAppendNode(ExprNode):
self.is_temp = 1 self.is_temp = 1
def generate_result_code(self, code): def generate_result_code(self, code):
code.putln("%s = PyList_Append(%s, %s); %s" % code.putln("%s = PyList_Append(%s, (PyObject*)%s); %s" %
(self.result_code, (self.result_code,
self.target.result_code, self.target.result_code,
self.expr.result_code, self.expr.result_code,
......
...@@ -80,6 +80,7 @@ class Context: ...@@ -80,6 +80,7 @@ class Context:
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives from ParseTreeTransforms import InterpretCompilerDirectives
from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, OptimizeRefcounting from Optimize import FlattenInListTransform, SwitchTransform, OptimizeRefcounting
from Buffer import IntroduceBufferAuxiliaryVars from Buffer import IntroduceBufferAuxiliaryVars
from ModuleNode import check_c_classes from ModuleNode import check_c_classes
...@@ -96,6 +97,7 @@ class Context: ...@@ -96,6 +97,7 @@ class Context:
PostParse(self), PostParse(self),
_specific_post_parse, _specific_post_parse,
InterpretCompilerDirectives(self, self.pragma_overrides), InterpretCompilerDirectives(self, self.pragma_overrides),
EmbedSignature(self),
FlattenInListTransform(), FlattenInListTransform(),
WithTransform(self), WithTransform(self),
DecoratorTransform(self), DecoratorTransform(self),
...@@ -727,7 +729,8 @@ default_options = dict( ...@@ -727,7 +729,8 @@ default_options = dict(
timestamps = None, timestamps = None,
verbose = 0, verbose = 0,
quiet = 0, quiet = 0,
pragma_overrides = {} pragma_overrides = {},
emit_linenums = False,
) )
if sys.platform == "mac": if sys.platform == "mac":
from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# #
import os, time import os, time
from cStringIO import StringIO
from PyrexTypes import CPtrType from PyrexTypes import CPtrType
import Future import Future
...@@ -44,6 +43,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -44,6 +43,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# directives Top-level compiler directives # directives Top-level compiler directives
child_attrs = ["body"] child_attrs = ["body"]
directives = None
def analyse_declarations(self, env): def analyse_declarations(self, env):
if Options.embed_pos_in_docstring: if Options.embed_pos_in_docstring:
...@@ -242,7 +242,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -242,7 +242,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.annotate or options.annotate: if Options.annotate or options.annotate:
code = Annotate.AnnotationCCodeWriter() code = Annotate.AnnotationCCodeWriter()
else: else:
code = Code.CCodeWriter() code = Code.CCodeWriter(emit_linenums=options.emit_linenums)
h_code = code.insertion_point() h_code = code.insertion_point()
self.generate_module_preamble(env, modules, h_code) self.generate_module_preamble(env, modules, h_code)
...@@ -432,14 +432,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -432,14 +432,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("") code.putln("")
code.putln(" typedef struct {") code.putln(" typedef struct {")
code.putln(" void *buf;") code.putln(" void *buf;")
code.putln(" PyObject *obj;")
code.putln(" Py_ssize_t len;") code.putln(" Py_ssize_t len;")
code.putln(" Py_ssize_t itemsize;")
code.putln(" int readonly;") code.putln(" int readonly;")
code.putln(" const char *format;")
code.putln(" int ndim;") code.putln(" int ndim;")
code.putln(" char *format;")
code.putln(" Py_ssize_t *shape;") code.putln(" Py_ssize_t *shape;")
code.putln(" Py_ssize_t *strides;") code.putln(" Py_ssize_t *strides;")
code.putln(" Py_ssize_t *suboffsets;") code.putln(" Py_ssize_t *suboffsets;")
code.putln(" Py_ssize_t itemsize;")
code.putln(" void *internal;") code.putln(" void *internal;")
code.putln(" } Py_buffer;") code.putln(" } Py_buffer;")
code.putln("") code.putln("")
...@@ -463,6 +464,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -463,6 +464,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #define Py_TPFLAGS_HAVE_INDEX 0") code.putln(" #define Py_TPFLAGS_HAVE_INDEX 0")
code.putln("#endif") code.putln("#endif")
code.putln("#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)")
code.putln(" #define Py_TPFLAGS_HAVE_NEWBUFFER 0")
code.putln("#endif")
code.putln("#if PY_MAJOR_VERSION >= 3") code.putln("#if PY_MAJOR_VERSION >= 3")
code.putln(" #define PyBaseString_Type PyUnicode_Type") code.putln(" #define PyBaseString_Type PyUnicode_Type")
code.putln(" #define PyString_Type PyBytes_Type") code.putln(" #define PyString_Type PyBytes_Type")
...@@ -761,10 +766,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -761,10 +766,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
dll_linkage = dll_linkage) dll_linkage = dll_linkage)
if entry.visibility == 'private': if entry.visibility == 'private':
storage_class = "static " storage_class = "static "
elif entry.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro
else: else:
storage_class = "" storage_class = "%s " % Naming.extern_c_macro
code.putln("%s%s; /*proto*/" % ( code.putln("%s%s; /*proto*/" % (
storage_class, storage_class,
header)) header))
...@@ -872,7 +875,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -872,7 +875,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
else: else:
code.put_init_var_to_py_none(entry, "p->%s") code.put_init_var_to_py_none(entry, "p->%s")
entry = scope.lookup_here("__new__") entry = scope.lookup_here("__new__")
if entry: if entry and entry.is_special:
if entry.trivial_signature: if entry.trivial_signature:
cinit_args = "o, %s, NULL" % Naming.empty_tuple cinit_args = "o, %s, NULL" % Naming.empty_tuple
else: else:
...@@ -1958,11 +1961,11 @@ builtin_module_name_utility_code = [ ...@@ -1958,11 +1961,11 @@ builtin_module_name_utility_code = [
import_module_utility_code = [ import_module_utility_code = [
""" """
static PyObject *__Pyx_ImportModule(char *name); /*proto*/ static PyObject *__Pyx_ImportModule(const char *name); /*proto*/
""",""" ""","""
#ifndef __PYX_HAVE_RT_ImportModule #ifndef __PYX_HAVE_RT_ImportModule
#define __PYX_HAVE_RT_ImportModule #define __PYX_HAVE_RT_ImportModule
static PyObject *__Pyx_ImportModule(char *name) { static PyObject *__Pyx_ImportModule(const char *name) {
PyObject *py_name = 0; PyObject *py_name = 0;
PyObject *py_module = 0; PyObject *py_module = 0;
...@@ -1987,29 +1990,32 @@ bad: ...@@ -1987,29 +1990,32 @@ bad:
type_import_utility_code = [ type_import_utility_code = [
""" """
static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size); /*proto*/ static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, long size); /*proto*/
""",""" ""","""
#ifndef __PYX_HAVE_RT_ImportType #ifndef __PYX_HAVE_RT_ImportType
#define __PYX_HAVE_RT_ImportType #define __PYX_HAVE_RT_ImportType
static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name,
long size) long size)
{ {
PyObject *py_module = 0; PyObject *py_module = 0;
PyObject *result = 0; PyObject *result = 0;
PyObject *py_name = 0; PyObject *py_name = 0;
py_module = __Pyx_ImportModule(module_name);
if (!py_module)
goto bad;
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
py_name = PyString_FromString(module_name); py_name = PyString_FromString(class_name);
#else #else
py_name = PyUnicode_FromString(module_name); py_name = PyUnicode_FromString(class_name);
#endif #endif
if (!py_name) if (!py_name)
goto bad; goto bad;
result = PyObject_GetAttr(py_module, py_name);
py_module = __Pyx_ImportModule(module_name); Py_DECREF(py_name);
if (!py_module) py_name = 0;
goto bad; Py_DECREF(py_module);
result = PyObject_GetAttrString(py_module, class_name); py_module = 0;
if (!result) if (!result)
goto bad; goto bad;
if (!PyType_Check(result)) { if (!PyType_Check(result)) {
...@@ -2026,7 +2032,7 @@ static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, ...@@ -2026,7 +2032,7 @@ static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name,
} }
return (PyTypeObject *)result; return (PyTypeObject *)result;
bad: bad:
Py_XDECREF(py_name); Py_XDECREF(py_module);
Py_XDECREF(result); Py_XDECREF(result);
return 0; return 0;
} }
......
...@@ -44,7 +44,7 @@ vtabstruct_prefix = pyrex_prefix + "vtabstruct_" ...@@ -44,7 +44,7 @@ vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
opt_arg_prefix = pyrex_prefix + "opt_args_" opt_arg_prefix = pyrex_prefix + "opt_args_"
args_cname = pyrex_prefix + "args" args_cname = pyrex_prefix + "args"
kwdlist_cname = pyrex_prefix + "argnames" pykwdlist_cname = pyrex_prefix + "pyargnames"
obj_base_cname = pyrex_prefix + "base" obj_base_cname = pyrex_prefix + "base"
builtins_cname = pyrex_prefix + "b" builtins_cname = pyrex_prefix + "b"
preimport_cname = pyrex_prefix + "i" preimport_cname = pyrex_prefix + "i"
...@@ -76,7 +76,6 @@ print_function_kwargs = pyrex_prefix + "print_kwargs" ...@@ -76,7 +76,6 @@ print_function_kwargs = pyrex_prefix + "print_kwargs"
cleanup_cname = pyrex_prefix + "module_cleanup" cleanup_cname = pyrex_prefix + "module_cleanup"
pymoduledef_cname = pyrex_prefix + "moduledef" pymoduledef_cname = pyrex_prefix + "moduledef"
optional_args_cname = pyrex_prefix + "optional_args" optional_args_cname = pyrex_prefix + "optional_args"
no_opt_args = pyrex_prefix + "no_opt_args"
import_star = pyrex_prefix + "import_star" import_star = pyrex_prefix + "import_star"
import_star_set = pyrex_prefix + "import_star_set" import_star_set = pyrex_prefix + "import_star_set"
cur_scope_cname = pyrex_prefix + "cur_scope" cur_scope_cname = pyrex_prefix + "cur_scope"
...@@ -95,6 +94,10 @@ exc_lineno_name = pyrex_prefix + "exc_lineno" ...@@ -95,6 +94,10 @@ exc_lineno_name = pyrex_prefix + "exc_lineno"
exc_vars = (exc_type_name, exc_value_name, exc_tb_name) exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
exc_save_vars = (pyrex_prefix + 'save_exc_type',
pyrex_prefix + 'save_exc_value',
pyrex_prefix + 'save_exc_tb')
api_name = pyrex_prefix + "capi__" api_name = pyrex_prefix + "capi__"
h_guard_prefix = "__PYX_HAVE__" h_guard_prefix = "__PYX_HAVE__"
......
...@@ -905,6 +905,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -905,6 +905,9 @@ class FuncDefNode(StatNode, BlockNode):
lenv = self.local_scope lenv = self.local_scope
is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
self.entry.scope.is_c_class_scope)
# Generate C code for header and body of function # Generate C code for header and body of function
code.enter_cfunc_scope() code.enter_cfunc_scope()
code.return_from_error_cleanup_label = code.new_label() code.return_from_error_cleanup_label = code.new_label()
...@@ -947,6 +950,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -947,6 +950,9 @@ class FuncDefNode(StatNode, BlockNode):
acquire_gil = self.need_gil_acquisition(lenv) acquire_gil = self.need_gil_acquisition(lenv)
if acquire_gil: if acquire_gil:
code.putln("PyGILState_STATE _save = PyGILState_Ensure();") code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
# ----- Automatic lead-ins for certain special functions
if is_getbuffer_slot:
self.getbuffer_init(code)
# ----- Fetch arguments # ----- Fetch arguments
self.generate_argument_parsing_code(env, code) self.generate_argument_parsing_code(env, code)
# If an argument is assigned to in the body, we must # If an argument is assigned to in the body, we must
...@@ -958,6 +964,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -958,6 +964,8 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.var_entries: for entry in lenv.var_entries:
if entry.type.is_pyobject and entry.init_to_none and entry.used: if entry.type.is_pyobject and entry.init_to_none and entry.used:
code.put_init_var_to_py_none(entry) code.put_init_var_to_py_none(entry)
# ----- Initialise local buffer auxiliary variables
for entry in lenv.var_entries + lenv.arg_entries:
if entry.type.is_buffer and entry.buffer_aux.buffer_info_var.used: if entry.type.is_buffer and entry.buffer_aux.buffer_info_var.used:
code.putln("%s.buf = NULL;" % entry.buffer_aux.buffer_info_var.cname) code.putln("%s.buf = NULL;" % entry.buffer_aux.buffer_info_var.cname)
# ----- Check and convert arguments # ----- Check and convert arguments
...@@ -990,12 +998,13 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -990,12 +998,13 @@ class FuncDefNode(StatNode, BlockNode):
# so need to save and restore error state # so need to save and restore error state
buffers_present = len(lenv.buffer_entries) > 0 buffers_present = len(lenv.buffer_entries) > 0
if buffers_present: if buffers_present:
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;") code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
code.putln("PyErr_Fetch(&__pyx_type, &__pyx_value, &__pyx_tb);") code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
for entry in lenv.buffer_entries: for entry in lenv.buffer_entries:
code.putln("%s;" % Buffer.get_release_buffer_code(entry)) code.putln("%s;" % Buffer.get_release_buffer_code(entry))
#code.putln("%s = 0;" % entry.cname) #code.putln("%s = 0;" % entry.cname)
code.putln("PyErr_Restore(__pyx_type, __pyx_value, __pyx_tb);}") code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
err_val = self.error_value() err_val = self.error_value()
exc_check = self.caller_will_check_exceptions() exc_check = self.caller_will_check_exceptions()
...@@ -1008,6 +1017,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1008,6 +1017,7 @@ class FuncDefNode(StatNode, BlockNode):
'__Pyx_WriteUnraisable("%s");' % '__Pyx_WriteUnraisable("%s");' %
self.entry.qualified_name) self.entry.qualified_name)
env.use_utility_code(unraisable_exception_utility_code) env.use_utility_code(unraisable_exception_utility_code)
env.use_utility_code(restore_exception_utility_code)
default_retval = self.return_type.default_value default_retval = self.return_type.default_value
if err_val is None and default_retval: if err_val is None and default_retval:
err_val = default_retval err_val = default_retval
...@@ -1016,17 +1026,27 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1016,17 +1026,27 @@ class FuncDefNode(StatNode, BlockNode):
"%s = %s;" % ( "%s = %s;" % (
Naming.retval_cname, Naming.retval_cname,
err_val)) err_val))
if buffers_present:
# Else, non-error return will be an empty clause if is_getbuffer_slot:
self.getbuffer_error_cleanup(code)
# If we are using the non-error cleanup section we should
# jump past it if we have an error. The if-test below determine
# whether this section is used.
if buffers_present or is_getbuffer_slot:
code.put_goto(code.return_from_error_cleanup_label) code.put_goto(code.return_from_error_cleanup_label)
# ----- Non-error return cleanup # ----- Non-error return cleanup
# PS! If adding something here, modify the conditions for the # If you add anything here, remember to add a condition to the
# goto statement in error cleanup above # if-test above in the error block (so that it can jump past this
# block).
code.put_label(code.return_label) code.put_label(code.return_label)
for entry in lenv.buffer_entries: for entry in lenv.buffer_entries:
if entry.used: if entry.used:
code.putln("%s;" % Buffer.get_release_buffer_code(entry)) code.putln("%s;" % Buffer.get_release_buffer_code(entry))
if is_getbuffer_slot:
self.getbuffer_normal_cleanup(code)
# ----- Return cleanup for both error and no-error return # ----- Return cleanup for both error and no-error return
code.put_label(code.return_from_error_cleanup_label) code.put_label(code.return_from_error_cleanup_label)
if not Options.init_local_none: if not Options.init_local_none:
...@@ -1038,7 +1058,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1038,7 +1058,6 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
if entry.type.is_pyobject and lenv.control_flow.get_state((entry.name, 'source')) != 'arg': if entry.type.is_pyobject and lenv.control_flow.get_state((entry.name, 'source')) != 'arg':
code.put_var_decref(entry) code.put_var_decref(entry)
self.put_stararg_decrefs(code)
if acquire_gil: if acquire_gil:
code.putln("PyGILState_Release(_save);") code.putln("PyGILState_Release(_save);")
# code.putln("/* TODO: decref scope object */") # code.putln("/* TODO: decref scope object */")
...@@ -1053,10 +1072,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1053,10 +1072,7 @@ class FuncDefNode(StatNode, BlockNode):
code.exit_cfunc_scope() code.exit_cfunc_scope()
if self.py_func: if self.py_func:
self.py_func.generate_function_definitions(env, code) self.py_func.generate_function_definitions(env, code)
self.generate_optarg_wrapper_function(env, code) self.generate_wrapper_functions(code)
def put_stararg_decrefs(self, code):
pass
def declare_argument(self, env, arg): def declare_argument(self, env, arg):
if arg.type.is_void: if arg.type.is_void:
...@@ -1065,7 +1081,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1065,7 +1081,8 @@ class FuncDefNode(StatNode, BlockNode):
error(arg.pos, error(arg.pos,
"Argument type '%s' is incomplete" % arg.type) "Argument type '%s' is incomplete" % arg.type)
return env.declare_arg(arg.name, arg.type, arg.pos) return env.declare_arg(arg.name, arg.type, arg.pos)
def generate_optarg_wrapper_function(self, env, code):
def generate_wrapper_functions(self, code):
pass pass
def generate_execution_code(self, code): def generate_execution_code(self, code):
...@@ -1088,7 +1105,26 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1088,7 +1105,26 @@ class FuncDefNode(StatNode, BlockNode):
if self.assmt: if self.assmt:
self.assmt.generate_execution_code(code) self.assmt.generate_execution_code(code)
#
# Special code for the __getbuffer__ function
#
def getbuffer_init(self, code):
info = self.local_scope.arg_entries[1].cname
# Python 3.0 betas have a bug in memoryview which makes it call
# getbuffer with a NULL parameter. For now we work around this;
# the following line should be removed when this bug is fixed.
code.putln("if (%s == NULL) return 0;" % info)
code.putln("%s->obj = Py_None; Py_INCREF(Py_None);" % info)
def getbuffer_error_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.putln("Py_DECREF(%s->obj); %s->obj = NULL;" %
(info, info))
def getbuffer_normal_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.putln("if (%s->obj == Py_None) { Py_DECREF(Py_None); %s->obj = NULL; }" %
(info, info))
class CFuncDefNode(FuncDefNode): class CFuncDefNode(FuncDefNode):
# C function definition. # C function definition.
...@@ -1103,6 +1139,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1103,6 +1139,7 @@ class CFuncDefNode(FuncDefNode):
# with_gil boolean Acquire GIL around body # with_gil boolean Acquire GIL around body
# type CFuncType # type CFuncType
# py_func wrapper for calling from Python # py_func wrapper for calling from Python
# overridable whether or not this is a cpdef function
child_attrs = ["base_type", "declarator", "body", "py_func"] child_attrs = ["base_type", "declarator", "body", "py_func"]
...@@ -1198,21 +1235,22 @@ class CFuncDefNode(FuncDefNode): ...@@ -1198,21 +1235,22 @@ class CFuncDefNode(FuncDefNode):
if self.overridable: if self.overridable:
self.py_func.analyse_expressions(env) self.py_func.analyse_expressions(env)
def generate_function_header(self, code, with_pymethdef, with_opt_args = 1): def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
arg_decls = [] arg_decls = []
type = self.type type = self.type
visibility = self.entry.visibility visibility = self.entry.visibility
for arg in type.args[:len(type.args)-type.optional_arg_count]: for arg in type.args[:len(type.args)-type.optional_arg_count]:
arg_decls.append(arg.declaration_code()) arg_decls.append(arg.declaration_code())
if with_dispatch and self.overridable:
arg_decls.append(PyrexTypes.c_int_type.declaration_code(Naming.skip_dispatch_cname))
if type.optional_arg_count and with_opt_args: if type.optional_arg_count and with_opt_args:
arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname)) arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
if type.has_varargs: if type.has_varargs:
arg_decls.append("...") arg_decls.append("...")
if not arg_decls: if not arg_decls:
arg_decls = ["void"] arg_decls = ["void"]
if cname is None:
cname = self.entry.func_cname cname = self.entry.func_cname
if not with_opt_args:
cname += Naming.no_opt_args
entity = type.function_header_code(cname, string.join(arg_decls, ", ")) entity = type.function_header_code(cname, string.join(arg_decls, ", "))
if visibility == 'public': if visibility == 'public':
dll_linkage = "DL_EXPORT" dll_linkage = "DL_EXPORT"
...@@ -1290,15 +1328,33 @@ class CFuncDefNode(FuncDefNode): ...@@ -1290,15 +1328,33 @@ class CFuncDefNode(FuncDefNode):
def caller_will_check_exceptions(self): def caller_will_check_exceptions(self):
return self.entry.type.exception_check return self.entry.type.exception_check
def generate_optarg_wrapper_function(self, env, code): def generate_wrapper_functions(self, code):
if self.type.optional_arg_count and \ # If the C signature of a function has changed, we need to generate
self.type.original_sig and not self.type.original_sig.optional_arg_count: # wrappers to put in the slots here.
k = 0
entry = self.entry
func_type = entry.type
while entry.prev_entry is not None:
k += 1
entry = entry.prev_entry
entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
code.putln() code.putln()
self.generate_function_header(code, 0, with_opt_args = 0) self.generate_function_header(code,
0,
with_dispatch = entry.type.is_overridable,
with_opt_args = entry.type.optional_arg_count,
cname = entry.func_cname)
if not self.return_type.is_void: if not self.return_type.is_void:
code.put('return ') code.put('return ')
args = self.type.args args = self.type.args
arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]] arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
if entry.type.is_overridable:
arglist.append(Naming.skip_dispatch_cname)
elif func_type.is_overridable:
arglist.append('0')
if entry.type.optional_arg_count:
arglist.append(Naming.optional_args_cname)
elif func_type.optional_arg_count:
arglist.append('NULL') arglist.append('NULL')
code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist))) code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
code.putln('}') code.putln('}')
...@@ -1381,17 +1437,6 @@ class DefNode(FuncDefNode): ...@@ -1381,17 +1437,6 @@ class DefNode(FuncDefNode):
self.declare_pyfunction(env) self.declare_pyfunction(env)
self.analyse_signature(env) self.analyse_signature(env)
self.return_type = self.entry.signature.return_type() self.return_type = self.entry.signature.return_type()
if self.signature_has_generic_args():
if self.star_arg:
env.use_utility_code(get_stararg_utility_code)
elif self.signature_has_generic_args():
env.use_utility_code(raise_argtuple_too_long_utility_code)
if not self.signature_has_nongeneric_args():
env.use_utility_code(get_keyword_string_check_utility_code)
elif self.starstar_arg:
env.use_utility_code(get_splitkeywords_utility_code)
if self.num_required_kw_args:
env.use_utility_code(get_checkkeywords_utility_code)
def analyse_signature(self, env): def analyse_signature(self, env):
any_type_tests_needed = 0 any_type_tests_needed = 0
...@@ -1512,6 +1557,10 @@ class DefNode(FuncDefNode): ...@@ -1512,6 +1557,10 @@ class DefNode(FuncDefNode):
arg.entry = self.declare_argument(env, arg) arg.entry = self.declare_argument(env, arg)
arg.entry.used = 1 arg.entry.used = 1
arg.entry.is_self_arg = arg.is_self_arg arg.entry.is_self_arg = arg.is_self_arg
if not arg.is_self_arg:
arg.name_entry = env.get_string_const(
arg.name, identifier = True)
env.add_py_string(arg.name_entry, identifier = True)
if arg.hdr_type: if arg.hdr_type:
if arg.is_self_arg or \ if arg.is_self_arg or \
(arg.type.is_extension_type and not arg.hdr_type.is_extension_type): (arg.type.is_extension_type and not arg.hdr_type.is_extension_type):
...@@ -1597,31 +1646,13 @@ class DefNode(FuncDefNode): ...@@ -1597,31 +1646,13 @@ class DefNode(FuncDefNode):
def generate_keyword_list(self, code): def generate_keyword_list(self, code):
if self.signature_has_generic_args() and \ if self.signature_has_generic_args() and \
self.signature_has_nongeneric_args(): self.signature_has_nongeneric_args():
reqd_kw_flags = []
has_reqd_kwds = False
code.put( code.put(
"static char *%s[] = {" % "static PyObject **%s[] = {" %
Naming.kwdlist_cname) Naming.pykwdlist_cname)
for arg in self.args: for arg in self.args:
if arg.is_generic: if arg.is_generic:
code.put( code.put('&%s,' % arg.name_entry.pystring_cname)
'"%s",' % code.putln("0};")
arg.name)
if arg.kw_only and not arg.default:
has_reqd_kwds = 1
flag = "1"
else:
flag = "0"
reqd_kw_flags.append(flag)
code.putln(
"0};")
if has_reqd_kwds:
flags_name = Naming.reqd_kwds_cname
self.reqd_kw_flags_cname = flags_name
code.putln(
"static char %s[] = {%s};" % (
flags_name,
",".join(reqd_kw_flags)))
def generate_argument_parsing_code(self, env, code): def generate_argument_parsing_code(self, env, code):
# Generate PyArg_ParseTuple call for generic # Generate PyArg_ParseTuple call for generic
...@@ -1632,7 +1663,7 @@ class DefNode(FuncDefNode): ...@@ -1632,7 +1663,7 @@ class DefNode(FuncDefNode):
old_error_label = code.new_error_label() old_error_label = code.new_error_label()
our_error_label = code.error_label our_error_label = code.error_label
end_label = code.new_label() end_label = code.new_label("argument_unpacking_done")
has_kwonly_args = self.num_kwonly_args > 0 has_kwonly_args = self.num_kwonly_args > 0
has_star_or_kw_args = self.star_arg is not None \ has_star_or_kw_args = self.star_arg is not None \
...@@ -1648,9 +1679,8 @@ class DefNode(FuncDefNode): ...@@ -1648,9 +1679,8 @@ class DefNode(FuncDefNode):
self.generate_stararg_copy_code(code) self.generate_stararg_copy_code(code)
else: else:
arg_addrs = []
arg_formats = []
positional_args = [] positional_args = []
kw_only_args = []
default_seen = 0 default_seen = 0
for arg in self.args: for arg in self.args:
arg_entry = arg.entry arg_entry = arg.entry
...@@ -1660,44 +1690,37 @@ class DefNode(FuncDefNode): ...@@ -1660,44 +1690,37 @@ class DefNode(FuncDefNode):
"%s = %s;" % ( "%s = %s;" % (
arg_entry.cname, arg_entry.cname,
arg.default_result_code)) arg.default_result_code))
if not default_seen:
arg_formats.append("|")
default_seen = 1 default_seen = 1
if not arg.is_self_arg and not arg.kw_only: if not arg.is_self_arg:
if arg.kw_only:
kw_only_args.append(arg)
else:
positional_args.append(arg) positional_args.append(arg)
elif arg.kw_only: elif arg.kw_only:
if not default_seen: kw_only_args.append(arg)
arg_formats.append("|")
default_seen = 1 default_seen = 1
elif default_seen: elif default_seen:
error(arg.pos, "Non-default argument following default argument") error(arg.pos, "Non-default argument following default argument")
elif not arg.is_self_arg: elif not arg.is_self_arg:
positional_args.append(arg) positional_args.append(arg)
if arg.needs_conversion: if arg.needs_conversion:
arg_addrs.append("&" + arg.hdr_cname)
format = arg.hdr_type.parsetuple_format format = arg.hdr_type.parsetuple_format
else: else:
arg_addrs.append("&" + arg_entry.cname)
format = arg_entry.type.parsetuple_format format = arg_entry.type.parsetuple_format
if format: if not format:
arg_formats.append(format)
else:
error(arg.pos, error(arg.pos,
"Cannot convert Python object argument to type '%s' (when parsing input arguments)" "Cannot convert Python object argument to type '%s' (when parsing input arguments)"
% arg.type) % arg.type)
if has_star_or_kw_args: self.generate_tuple_and_keyword_parsing_code(
self.generate_stararg_getting_code(code) positional_args, kw_only_args, end_label, code)
self.generate_argument_tuple_parsing_code(
positional_args, arg_formats, arg_addrs, code)
code.error_label = old_error_label code.error_label = old_error_label
if code.label_used(our_error_label): if code.label_used(our_error_label):
if not code.label_used(end_label):
code.put_goto(end_label) code.put_goto(end_label)
code.put_label(our_error_label) code.put_label(our_error_label)
if has_star_or_kw_args: if has_star_or_kw_args:
self.put_stararg_decrefs(code)
self.generate_arg_decref(self.star_arg, code) self.generate_arg_decref(self.star_arg, code)
if self.starstar_arg: if self.starstar_arg:
if self.starstar_arg.entry.xdecref_cleanup: if self.starstar_arg.entry.xdecref_cleanup:
...@@ -1706,34 +1729,10 @@ class DefNode(FuncDefNode): ...@@ -1706,34 +1729,10 @@ class DefNode(FuncDefNode):
code.put_var_decref(self.starstar_arg.entry) code.put_var_decref(self.starstar_arg.entry)
code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name) code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
code.putln("return %s;" % self.error_value()) code.putln("return %s;" % self.error_value())
if code.label_used(end_label):
code.put_label(end_label) code.put_label(end_label)
def generate_argument_tuple_parsing_code(self, positional_args, def generate_arg_assignment(self, arg, item, code):
arg_formats, arg_addrs, code):
# Unpack inplace if it's simple
if not self.num_required_kw_args:
min_positional_args = self.num_required_args - self.num_required_kw_args
max_positional_args = len(positional_args)
if len(self.args) > 0 and self.args[0].is_self_arg:
min_positional_args -= 1
if max_positional_args == min_positional_args:
count_cond = "likely(PyTuple_GET_SIZE(%s) == %s)" % (
Naming.args_cname, max_positional_args)
else:
count_cond = "likely(%s <= PyTuple_GET_SIZE(%s)) && likely(PyTuple_GET_SIZE(%s) <= %s)" % (
min_positional_args,
Naming.args_cname,
Naming.args_cname,
max_positional_args)
code.putln(
'if (likely(!%s) && %s) {' % (Naming.kwds_cname, count_cond))
i = 0
closing = 0
for arg in positional_args:
if arg.default:
code.putln('if (PyTuple_GET_SIZE(%s) > %s) {' % (Naming.args_cname, i))
closing += 1
item = "PyTuple_GET_ITEM(%s, %s)" % (Naming.args_cname, i)
if arg.type.is_pyobject: if arg.type.is_pyobject:
if arg.is_generic: if arg.is_generic:
item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item) item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
...@@ -1748,30 +1747,6 @@ class DefNode(FuncDefNode): ...@@ -1748,30 +1747,6 @@ class DefNode(FuncDefNode):
code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos))) code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
else: else:
error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type) error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
i += 1
for _ in range(closing):
code.putln('}')
code.putln(
'}')
code.putln('else {')
argformat = '"%s"' % string.join(arg_formats, "")
pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat, Naming.kwdlist_cname] + arg_addrs
pt_argstring = string.join(pt_arglist, ", ")
code.putln(
'if (unlikely(!PyArg_ParseTupleAndKeywords(%s))) %s' % (
pt_argstring,
code.error_goto(self.pos)))
self.generate_argument_conversion_code(code)
if not self.num_required_kw_args:
code.putln('}')
def put_stararg_decrefs(self, code):
if self.star_arg:
code.put_decref(Naming.args_cname, py_object_type)
if self.starstar_arg:
code.put_xdecref(Naming.kwds_cname, py_object_type)
def generate_arg_xdecref(self, arg, code): def generate_arg_xdecref(self, arg, code):
if arg: if arg:
...@@ -1781,16 +1756,29 @@ class DefNode(FuncDefNode): ...@@ -1781,16 +1756,29 @@ class DefNode(FuncDefNode):
if arg: if arg:
code.put_var_decref(arg.entry) code.put_var_decref(arg.entry)
def arg_address(self, arg):
if arg:
return "&%s" % arg.entry.cname
else:
return 0
def generate_stararg_copy_code(self, code): def generate_stararg_copy_code(self, code):
if not self.star_arg: if not self.star_arg:
self.generate_positional_args_check(code, 0) code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
self.generate_keyword_args_check(code) code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
Naming.args_cname)
code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
self.name.utf8encode(), Naming.args_cname, self.error_value()))
code.putln("}")
code.globalstate.use_utility_code(keyword_string_check_utility_code)
if self.starstar_arg:
if self.star_arg:
kwarg_check = "unlikely(%s)" % Naming.kwds_cname
else:
kwarg_check = "%s" % Naming.kwds_cname
else:
kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
Naming.kwds_cname, Naming.kwds_cname)
code.putln(
"if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
kwarg_check, Naming.kwds_cname, self.name,
bool(self.starstar_arg), self.error_value()))
if self.starstar_arg: if self.starstar_arg:
code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % ( code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
...@@ -1800,7 +1788,6 @@ class DefNode(FuncDefNode): ...@@ -1800,7 +1788,6 @@ class DefNode(FuncDefNode):
code.putln("if (unlikely(!%s)) return %s;" % ( code.putln("if (unlikely(!%s)) return %s;" % (
self.starstar_arg.entry.cname, self.error_value())) self.starstar_arg.entry.cname, self.error_value()))
self.starstar_arg.entry.xdecref_cleanup = 0 self.starstar_arg.entry.xdecref_cleanup = 0
self.starstar_arg = None
if self.star_arg: if self.star_arg:
code.put_incref(Naming.args_cname, py_object_type) code.put_incref(Naming.args_cname, py_object_type)
...@@ -1808,78 +1795,221 @@ class DefNode(FuncDefNode): ...@@ -1808,78 +1795,221 @@ class DefNode(FuncDefNode):
self.star_arg.entry.cname, self.star_arg.entry.cname,
Naming.args_cname)) Naming.args_cname))
self.star_arg.entry.xdecref_cleanup = 0 self.star_arg.entry.xdecref_cleanup = 0
self.star_arg = None
def generate_stararg_getting_code(self, code): def generate_tuple_and_keyword_parsing_code(self, positional_args,
num_kwonly = self.num_kwonly_args kw_only_args, success_label, code):
fixed_args = self.entry.signature.num_fixed_args() argtuple_error_label = code.new_label("argtuple_error")
nargs = len(self.args) - num_kwonly - fixed_args
error_return = "return %s;" % self.error_value()
if self.star_arg: min_positional_args = self.num_required_args - self.num_required_kw_args
star_arg_cname = self.star_arg.entry.cname if len(self.args) > 0 and self.args[0].is_self_arg:
code.putln("if (likely(PyTuple_GET_SIZE(%s) <= %d)) {" % ( min_positional_args -= 1
Naming.args_cname, nargs)) max_positional_args = len(positional_args)
code.put_incref(Naming.args_cname, py_object_type) has_fixed_positional_count = not self.star_arg and \
code.put("%s = %s; " % (star_arg_cname, Naming.empty_tuple)) min_positional_args == max_positional_args
code.put_incref(Naming.empty_tuple, py_object_type)
code.putln("}") code.globalstate.use_utility_code(raise_double_keywords_utility_code)
code.putln("else {") code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
code.putln( if self.num_required_kw_args:
"if (unlikely(__Pyx_SplitStarArg(&%s, %d, &%s) < 0)) return %s;" % ( code.globalstate.use_utility_code(raise_keyword_required_utility_code)
Naming.args_cname,
nargs, if self.starstar_arg or self.star_arg:
star_arg_cname, self.generate_stararg_init_code(max_positional_args, code)
self.error_value()))
code.putln("}") # --- optimised code when we receive keyword arguments
self.star_arg.entry.xdecref_cleanup = 0 if self.num_required_kw_args:
elif self.signature_has_generic_args(): code.putln("if (likely(%s)) {" % Naming.kwds_cname)
# make sure supernumerous positional arguments do not run else:
# into keyword-only arguments and provide a more helpful code.putln("if (unlikely(%s) && (PyDict_Size(%s) > 0)) {" % (
# message than PyArg_ParseTupelAndKeywords() Naming.kwds_cname, Naming.kwds_cname))
self.generate_positional_args_check(code, nargs) self.generate_keyword_unpacking_code(
min_positional_args, max_positional_args,
has_fixed_positional_count,
positional_args, kw_only_args, argtuple_error_label, code)
# --- optimised code when we do not receive any keyword arguments
if min_positional_args > 0 or min_positional_args == max_positional_args:
# Python raises arg tuple related errors first, so we must
# check the length here
if min_positional_args == max_positional_args and not self.star_arg:
compare = '!='
else:
compare = '<'
code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
Naming.args_cname, compare, min_positional_args))
code.put_goto(argtuple_error_label)
if self.num_required_kw_args:
# pure error case: keywords required but not passed
if max_positional_args > min_positional_args and not self.star_arg:
code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % (
Naming.args_cname, max_positional_args))
code.put_goto(argtuple_error_label)
code.putln('} else {')
for i, arg in enumerate(kw_only_args):
if not arg.default:
# required keyword-only argument missing
code.put('__Pyx_RaiseKeywordRequired("%s", *%s[%d]); ' % (
self.name.utf8encode(), Naming.pykwdlist_cname,
len(positional_args) + i))
code.putln(code.error_goto(self.pos))
break
elif min_positional_args == max_positional_args:
# parse the exact number of positional arguments from the
# args tuple
code.putln('} else {')
for i, arg in enumerate(positional_args):
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code)
else:
# parse the positional arguments from the variable length
# args tuple
code.putln('} else {')
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
reversed_args = list(enumerate(positional_args))[::-1]
for i, arg in reversed_args:
if i >= min_positional_args-1:
if min_positional_args > 1:
code.putln('case %2d:' % (i+1)) # pure code beautification
else:
code.put('case %2d: ' % (i+1))
item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
self.generate_arg_assignment(arg, item, code)
if not self.star_arg:
if min_positional_args == 0:
code.put('case 0: ')
code.putln('break;')
code.put('default: ')
code.put_goto(argtuple_error_label)
code.putln('}')
code.putln('}')
handle_error = 0 if code.label_used(argtuple_error_label):
code.put_goto(success_label)
code.put_label(argtuple_error_label)
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
self.name.utf8encode(), has_fixed_positional_count,
min_positional_args, max_positional_args,
Naming.args_cname))
code.putln(code.error_goto(self.pos))
def generate_stararg_init_code(self, max_positional_args, code):
if self.starstar_arg: if self.starstar_arg:
handle_error = 1
code.put(
"if (unlikely(__Pyx_SplitKeywords(&%s, %s, &%s, %s) < 0)) " % (
Naming.kwds_cname,
Naming.kwdlist_cname,
self.starstar_arg.entry.cname,
self.reqd_kw_flags_cname))
self.starstar_arg.entry.xdecref_cleanup = 0 self.starstar_arg.entry.xdecref_cleanup = 0
elif self.num_required_kw_args: code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % (
handle_error = 1 self.starstar_arg.entry.cname,
code.put("if (unlikely(__Pyx_CheckRequiredKeywords(%s, %s, %s) < 0)) " % ( self.starstar_arg.entry.cname,
Naming.kwds_cname, self.error_value()))
Naming.kwdlist_cname, if self.star_arg:
self.reqd_kw_flags_cname)) self.star_arg.entry.xdecref_cleanup = 0
code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
Naming.args_cname,
max_positional_args))
code.put('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s)); ' % (
self.star_arg.entry.cname, Naming.args_cname,
max_positional_args, Naming.args_cname))
if self.starstar_arg:
code.putln("")
code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
code.put_decref(self.starstar_arg.entry.cname, py_object_type)
code.putln('return %s;' % self.error_value())
code.putln('}')
else:
code.putln("if (unlikely(!%s)) return %s;" % (
self.star_arg.entry.cname, self.error_value()))
code.putln('} else {')
code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
code.put_incref(Naming.empty_tuple, py_object_type)
code.putln('}')
def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
has_fixed_positional_count, positional_args,
kw_only_args, argtuple_error_label, code):
all_args = tuple(positional_args) + tuple(kw_only_args)
max_args = len(all_args)
code.putln("PyObject* values[%d] = {%s};" % (
max_args, ('0,'*max_args)[:-1]))
code.putln("Py_ssize_t kw_args = PyDict_Size(%s);" %
Naming.kwds_cname)
if handle_error: # parse the tuple and check that it's not too long
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
if self.star_arg: if self.star_arg:
code.putln("{") code.putln('default:')
code.put_decref(Naming.args_cname, py_object_type) for i in range(max_positional_args-1, -1, -1):
code.put_decref(self.star_arg.entry.cname, py_object_type) code.put('case %2d: ' % (i+1))
code.putln(error_return) code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
code.putln("}") i, Naming.args_cname, i))
code.putln('case 0: break;')
if not self.star_arg:
code.put('default: ') # more arguments than allowed
code.put_goto(argtuple_error_label)
code.putln('}')
# now fill up the arguments with values from the kw dict
code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
for i, arg in enumerate(all_args):
if i <= max_positional_args:
if self.star_arg and i == max_positional_args:
code.putln('default:')
else:
code.putln('case %2d:' % i)
code.putln('values[%d] = PyDict_GetItem(%s, *%s[%d]);' % (
i, Naming.kwds_cname, Naming.pykwdlist_cname, i))
if i < min_positional_args:
code.putln('if (likely(values[%d])) kw_args--;' % i);
if i == 0:
# special case: we know arg 0 is missing
code.put('else ')
code.put_goto(argtuple_error_label)
else: else:
code.putln(error_return) # provide the correct number of values (args or
# kwargs) that were passed into positional
# arguments up to this point
code.putln('else {')
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
self.name.utf8encode(), has_fixed_positional_count,
min_positional_args, max_positional_args, i))
code.putln(code.error_goto(self.pos))
code.putln('}')
else:
code.putln('if (values[%d]) kw_args--;' % i);
if arg.kw_only and not arg.default:
code.putln('else {')
code.put('__Pyx_RaiseKeywordRequired("%s", *%s[%d]); ' %(
self.name.utf8encode(), Naming.pykwdlist_cname, i))
code.putln(code.error_goto(self.pos))
code.putln('}')
code.putln('}')
def generate_positional_args_check(self, code, nargs): code.putln('if (unlikely(kw_args > 0)) {')
code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % ( # non-positional kw args left in the dict: **kwargs or error
Naming.args_cname, nargs)) if self.star_arg:
code.putln("__Pyx_RaiseArgtupleTooLong(%d, PyTuple_GET_SIZE(%s));" % ( code.putln("const Py_ssize_t used_pos_args = (PyTuple_GET_SIZE(%s) < %d) ? PyTuple_GET_SIZE(%s) : %d;" % (
nargs, Naming.args_cname)) Naming.args_cname, max_positional_args,
code.putln("return %s;" % self.error_value()) Naming.args_cname, max_positional_args))
code.putln("}") pos_arg_count = "used_pos_args"
else:
pos_arg_count = "PyTuple_GET_SIZE(%s)" % Naming.args_cname
code.globalstate.use_utility_code(split_keywords_utility_code)
code.put(
'if (unlikely(__Pyx_SplitKeywords(%s, %s, %s, %s, "%s") < 0)) ' % (
Naming.kwds_cname,
Naming.pykwdlist_cname,
self.starstar_arg and self.starstar_arg.entry.cname or '0',
pos_arg_count,
self.name.utf8encode()))
code.putln(code.error_goto(self.pos))
code.putln('}')
def generate_keyword_args_check(self, code): # convert arg values to their final type and assign them
code.putln("if (unlikely(%s)) {" % Naming.kwds_cname) for i, arg in enumerate(all_args):
code.putln("if (unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( if arg.default:
Naming.kwds_cname, self.name, code.putln("if (values[%d]) {" % i)
bool(self.starstar_arg), self.error_value())) self.generate_arg_assignment(arg, "values[%d]" % i, code)
code.putln("}") if arg.default:
code.putln('}')
def generate_argument_conversion_code(self, code): def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from # Generate code to convert arguments from
...@@ -2006,7 +2136,7 @@ class OverrideCheckNode(StatNode): ...@@ -2006,7 +2136,7 @@ class OverrideCheckNode(StatNode):
else: else:
self_arg = "((PyObject *)%s)" % self.args[0].cname self_arg = "((PyObject *)%s)" % self.args[0].cname
code.putln("/* Check if called by wrapper */") code.putln("/* Check if called by wrapper */")
code.putln("if (unlikely(%s)) %s = 0;" % (Naming.skip_dispatch_cname, Naming.skip_dispatch_cname)) code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
code.putln("/* Check if overriden in Python */") code.putln("/* Check if overriden in Python */")
if self.py_func.is_module_scope: if self.py_func.is_module_scope:
code.putln("else {") code.putln("else {")
...@@ -2865,6 +2995,7 @@ class RaiseStatNode(StatNode): ...@@ -2865,6 +2995,7 @@ class RaiseStatNode(StatNode):
if self.exc_tb: if self.exc_tb:
self.exc_tb.release_temp(env) self.exc_tb.release_temp(env)
env.use_utility_code(raise_utility_code) env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
self.gil_check(env) self.gil_check(env)
gil_message = "Raising exception" gil_message = "Raising exception"
...@@ -2919,6 +3050,7 @@ class ReraiseStatNode(StatNode): ...@@ -2919,6 +3050,7 @@ class ReraiseStatNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.gil_check(env) self.gil_check(env)
env.use_utility_code(raise_utility_code) env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
gil_message = "Raising exception" gil_message = "Raising exception"
...@@ -3339,6 +3471,8 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3339,6 +3471,8 @@ class ForFromStatNode(LoopNode, StatNode):
# "Cannot assign integer to variable of type '%s'" % target_type) # "Cannot assign integer to variable of type '%s'" % target_type)
if target_type.is_numeric: if target_type.is_numeric:
self.is_py_target = 0 self.is_py_target = 0
if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
raise error(self.pos, "Buffer indexing not allowed as for loop target.")
self.loopvar_name = self.target.entry.cname self.loopvar_name = self.target.entry.cname
self.py_loopvar_node = None self.py_loopvar_node = None
else: else:
...@@ -3466,13 +3600,19 @@ class TryExceptStatNode(StatNode): ...@@ -3466,13 +3600,19 @@ class TryExceptStatNode(StatNode):
if self.else_clause: if self.else_clause:
self.else_clause.analyse_declarations(env) self.else_clause.analyse_declarations(env)
self.gil_check(env) self.gil_check(env)
env.use_utility_code(reset_exception_utility_code)
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.body.analyse_expressions(env) self.body.analyse_expressions(env)
self.cleanup_list = env.free_temp_entries[:] self.cleanup_list = env.free_temp_entries[:]
default_clause_seen = 0
for except_clause in self.except_clauses: for except_clause in self.except_clauses:
except_clause.analyse_expressions(env) except_clause.analyse_expressions(env)
if default_clause_seen:
error(except_clause.pos, "default 'except:' must be last")
if not except_clause.pattern:
default_clause_seen = 1
self.has_default_clause = default_clause_seen
if self.else_clause: if self.else_clause:
self.else_clause.analyse_expressions(env) self.else_clause.analyse_expressions(env)
self.gil_check(env) self.gil_check(env)
...@@ -3480,35 +3620,61 @@ class TryExceptStatNode(StatNode): ...@@ -3480,35 +3620,61 @@ class TryExceptStatNode(StatNode):
gil_message = "Try-except statement" gil_message = "Try-except statement"
def generate_execution_code(self, code): def generate_execution_code(self, code):
old_return_label = code.return_label
old_error_label = code.new_error_label() old_error_label = code.new_error_label()
our_error_label = code.error_label our_error_label = code.error_label
end_label = code.new_label() except_end_label = code.new_label('exception_handled')
except_error_label = code.new_label('except_error')
except_return_label = code.new_label('except_return')
try_end_label = code.new_label('try')
code.putln("{")
code.putln("PyObject %s;" %
', '.join(['*%s' % var for var in Naming.exc_save_vars]))
code.putln("__Pyx_ExceptionSave(%s);" %
', '.join(['&%s' % var for var in Naming.exc_save_vars]))
code.putln( code.putln(
"/*try:*/ {") "/*try:*/ {")
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
code.putln( code.putln(
"}") "}")
code.error_label = old_error_label code.error_label = except_error_label
code.return_label = except_return_label
if self.else_clause: if self.else_clause:
code.putln( code.putln(
"/*else:*/ {") "/*else:*/ {")
self.else_clause.generate_execution_code(code) self.else_clause.generate_execution_code(code)
code.putln( code.putln(
"}") "}")
code.put_goto(end_label) code.put_goto(try_end_label)
code.put_label(our_error_label) code.put_label(our_error_label)
code.put_var_xdecrefs_clear(self.cleanup_list) code.put_var_xdecrefs_clear(self.cleanup_list)
default_clause_seen = 0
for except_clause in self.except_clauses: for except_clause in self.except_clauses:
if not except_clause.pattern: except_clause.generate_handling_code(code, except_end_label)
default_clause_seen = 1
else: error_label_used = code.label_used(except_error_label)
if default_clause_seen: if error_label_used or not self.has_default_clause:
error(except_clause.pos, "Default except clause not last") if error_label_used:
except_clause.generate_handling_code(code, end_label) code.put_label(except_error_label)
if not default_clause_seen: for var in Naming.exc_save_vars:
code.put_goto(code.error_label) code.put_xdecref(var, py_object_type)
code.put_label(end_label) code.put_goto(old_error_label)
if code.label_used(except_return_label):
code.put_label(except_return_label)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_label(try_end_label)
code.putln("}")
code.return_label = old_return_label
code.error_label = old_error_label
def annotate(self, code): def annotate(self, code):
self.body.annotate(code) self.body.annotate(code)
...@@ -3576,6 +3742,7 @@ class ExceptClauseNode(Node): ...@@ -3576,6 +3742,7 @@ class ExceptClauseNode(Node):
for var in self.exc_vars: for var in self.exc_vars:
env.release_temp(var) env.release_temp(var)
env.use_utility_code(get_exception_utility_code) env.use_utility_code(get_exception_utility_code)
env.use_utility_code(restore_exception_utility_code)
def generate_handling_code(self, code, end_label): def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos) code.mark_pos(self.pos)
...@@ -3708,6 +3875,11 @@ class TryFinallyStatNode(StatNode): ...@@ -3708,6 +3875,11 @@ class TryFinallyStatNode(StatNode):
"PyObject *%s, *%s, *%s;" % Naming.exc_vars) "PyObject *%s, *%s, *%s;" % Naming.exc_vars)
code.putln( code.putln(
"int %s;" % Naming.exc_lineno_name) "int %s;" % Naming.exc_lineno_name)
exc_var_init_zero = ''.join(["%s = 0; " % var for var in Naming.exc_vars])
exc_var_init_zero += '%s = 0;' % Naming.exc_lineno_name
code.putln(exc_var_init_zero)
else:
exc_var_init_zero = None
code.use_label(catch_label) code.use_label(catch_label)
code.putln( code.putln(
"__pyx_why = 0; goto %s;" % catch_label) "__pyx_why = 0; goto %s;" % catch_label)
...@@ -3718,9 +3890,10 @@ class TryFinallyStatNode(StatNode): ...@@ -3718,9 +3890,10 @@ class TryFinallyStatNode(StatNode):
self.put_error_catcher(code, self.put_error_catcher(code,
new_error_label, i+1, catch_label) new_error_label, i+1, catch_label)
else: else:
code.putln( code.put('%s: ' % new_label)
"%s: __pyx_why = %s; goto %s;" % ( if exc_var_init_zero:
new_label, code.putln(exc_var_init_zero)
code.putln("__pyx_why = %s; goto %s;" % (
i+1, i+1,
catch_label)) catch_label))
code.put_label(catch_label) code.put_label(catch_label)
...@@ -3760,6 +3933,7 @@ class TryFinallyStatNode(StatNode): ...@@ -3760,6 +3933,7 @@ class TryFinallyStatNode(StatNode):
"}") "}")
def put_error_catcher(self, code, error_label, i, catch_label): def put_error_catcher(self, code, error_label, i, catch_label):
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln( code.putln(
"%s: {" % "%s: {" %
error_label) error_label)
...@@ -3768,7 +3942,7 @@ class TryFinallyStatNode(StatNode): ...@@ -3768,7 +3942,7 @@ class TryFinallyStatNode(StatNode):
i) i)
code.put_var_xdecrefs_clear(self.cleanup_list) code.put_var_xdecrefs_clear(self.cleanup_list)
code.putln( code.putln(
"PyErr_Fetch(&%s, &%s, &%s);" % "__Pyx_ErrFetch(&%s, &%s, &%s);" %
Naming.exc_vars) Naming.exc_vars)
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
...@@ -3781,11 +3955,12 @@ class TryFinallyStatNode(StatNode): ...@@ -3781,11 +3955,12 @@ class TryFinallyStatNode(StatNode):
"}") "}")
def put_error_uncatcher(self, code, i, error_label): def put_error_uncatcher(self, code, i, error_label):
code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln( code.putln(
"case %s: {" % "case %s: {" %
i) i)
code.putln( code.putln(
"PyErr_Restore(%s, %s, %s);" % "__Pyx_ErrRestore(%s, %s, %s);" %
Naming.exc_vars) Naming.exc_vars)
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
...@@ -4220,7 +4395,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { ...@@ -4220,7 +4395,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
} }
#endif #endif
} }
PyErr_Restore(type, value, tb); __Pyx_ErrRestore(type, value, tb);
return; return;
raise_error: raise_error:
Py_XDECREF(value); Py_XDECREF(value);
...@@ -4244,7 +4419,7 @@ static void __Pyx_ReRaise(void) { ...@@ -4244,7 +4419,7 @@ static void __Pyx_ReRaise(void) {
Py_XINCREF(type); Py_XINCREF(type);
Py_XINCREF(value); Py_XINCREF(value);
Py_XINCREF(tb); Py_XINCREF(tb);
PyErr_Restore(type, value, tb); __Pyx_ErrRestore(type, value, tb);
} }
"""] """]
...@@ -4252,9 +4427,12 @@ static void __Pyx_ReRaise(void) { ...@@ -4252,9 +4427,12 @@ static void __Pyx_ReRaise(void) {
arg_type_test_utility_code = [ arg_type_test_utility_code = [
""" """
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name, int exact); /*proto*/ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
const char *name, int exact); /*proto*/
""",""" ""","""
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name, int exact) { static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
const char *name, int exact)
{
if (!type) { if (!type) {
PyErr_Format(PyExc_SystemError, "Missing type object"); PyErr_Format(PyExc_SystemError, "Missing type object");
return 0; return 0;
...@@ -4275,59 +4453,80 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed ...@@ -4275,59 +4453,80 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# __Pyx_SplitStarArg splits the args tuple into two parts, one part # __Pyx_RaiseArgtupleInvalid raises the correct exception when too
# suitable for passing to PyArg_ParseTupleAndKeywords, and the other # many or too few positional arguments were found. This handles
# containing any extra arguments. On success, replaces the borrowed # Py_ssize_t formatting correctly.
# reference *args with references to a new tuple, and passes back a
# new reference in *args2. Does not touch any of its arguments on raise_argtuple_invalid_utility_code = [
# failure.
get_stararg_utility_code = [
""" """
static INLINE int __Pyx_SplitStarArg(PyObject **args, Py_ssize_t nargs, PyObject **args2); /*proto*/ static INLINE void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
""",""" ""","""
static INLINE int __Pyx_SplitStarArg( static INLINE void __Pyx_RaiseArgtupleInvalid(
PyObject **args, const char* func_name,
Py_ssize_t nargs, int exact,
PyObject **args2) Py_ssize_t num_min,
Py_ssize_t num_max,
Py_ssize_t num_found)
{ {
PyObject *args1 = 0; Py_ssize_t num_expected;
args1 = PyTuple_GetSlice(*args, 0, nargs); const char *number, *more_or_less;
if (!args1) {
*args2 = 0; if (num_found < num_min) {
return -1; num_expected = num_min;
more_or_less = "at least";
} else {
num_expected = num_max;
more_or_less = "at most";
} }
*args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args)); if (exact) {
if (!*args2) { more_or_less = "exactly";
Py_DECREF(args1);
return -1;
} }
*args = args1; number = (num_expected == 1) ? "" : "s";
return 0; PyErr_Format(PyExc_TypeError,
#if PY_VERSION_HEX < 0x02050000
"%s() takes %s %d positional argument%s (%d given)",
#else
"%s() takes %s %zd positional argument%s (%zd given)",
#endif
func_name, more_or_less, num_expected, number, num_found);
} }
"""] """]
#------------------------------------------------------------------------------------ raise_keyword_required_utility_code = [
# """
# __Pyx_RaiseArgtupleTooLong raises the correct exception when too static INLINE void __Pyx_RaiseKeywordRequired(const char* func_name, PyObject* kw_name); /*proto*/
# many positional arguments were found. This handles Py_ssize_t ""","""
# formatting correctly. static INLINE void __Pyx_RaiseKeywordRequired(
const char* func_name,
PyObject* kw_name)
{
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION >= 3
"%s() needs keyword-only argument %U", func_name, kw_name);
#else
"%s() needs keyword-only argument %s", func_name,
PyString_AS_STRING(kw_name));
#endif
}
"""]
raise_argtuple_too_long_utility_code = [ raise_double_keywords_utility_code = [
""" """
static INLINE void __Pyx_RaiseArgtupleTooLong(Py_ssize_t num_expected, Py_ssize_t num_found); /*proto*/ static INLINE void __Pyx_RaiseDoubleKeywordsError(
const char* func_name, PyObject* kw_name); /*proto*/
""",""" ""","""
static INLINE void __Pyx_RaiseArgtupleTooLong( static INLINE void __Pyx_RaiseDoubleKeywordsError(
Py_ssize_t num_expected, const char* func_name,
Py_ssize_t num_found) PyObject* kw_name)
{ {
const char* error_message = PyErr_Format(PyExc_TypeError,
#if PY_VERSION_HEX < 0x02050000 #if PY_MAJOR_VERSION >= 3
"function takes at most %d positional arguments (%d given)"; "%s() got multiple values for keyword argument '%U'", func_name, kw_name);
#else #else
"function takes at most %zd positional arguments (%zd given)"; "%s() got multiple values for keyword argument '%s'", func_name,
PyString_AS_STRING(kw_name));
#endif #endif
PyErr_Format(PyExc_TypeError, error_message, num_expected, num_found);
} }
"""] """]
...@@ -4337,11 +4536,12 @@ static INLINE void __Pyx_RaiseArgtupleTooLong( ...@@ -4337,11 +4536,12 @@ static INLINE void __Pyx_RaiseArgtupleTooLong(
# were passed to a function, or if any keywords were passed to a # were passed to a function, or if any keywords were passed to a
# function that does not accept them. # function that does not accept them.
get_keyword_string_check_utility_code = [ keyword_string_check_utility_code = [
""" """
static int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); /*proto*/ static INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict,
const char* function_name, int kw_allowed); /*proto*/
""",""" ""","""
static int __Pyx_CheckKeywordStrings( static INLINE int __Pyx_CheckKeywordStrings(
PyObject *kwdict, PyObject *kwdict,
const char* function_name, const char* function_name,
int kw_allowed) int kw_allowed)
...@@ -4350,141 +4550,115 @@ static int __Pyx_CheckKeywordStrings( ...@@ -4350,141 +4550,115 @@ static int __Pyx_CheckKeywordStrings(
Py_ssize_t pos = 0; Py_ssize_t pos = 0;
while (PyDict_Next(kwdict, &pos, &key, 0)) { while (PyDict_Next(kwdict, &pos, &key, 0)) {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
if (unlikely(!PyString_Check(key))) { if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key)))
#else #else
if (unlikely(!PyUnicode_Check(key))) { if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key)))
#endif #endif
goto invalid_keyword_type;
}
if ((!kw_allowed) && unlikely(key))
goto invalid_keyword;
return 1;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name); "%s() keywords must be strings", function_name);
return 0; return 0;
} invalid_keyword:
}
if (unlikely(!kw_allowed) && unlikely(key)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
"'%s' is an invalid keyword argument for this function", "%s() got an unexpected keyword argument '%s'",
PyString_AsString(key)); function_name, PyString_AsString(key));
#else #else
"'%U' is an invalid keyword argument for this function", "%s() got an unexpected keyword argument '%U'",
key); function_name, key);
#endif #endif
return 0; return 0;
}
return 1;
} }
"""] """]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# __Pyx_SplitKeywords splits the kwds dict into two parts one part # __Pyx_SplitKeywords copies the keyword arguments that are not named
# suitable for passing to PyArg_ParseTupleAndKeywords, and the other # in argnames[] from the kwds dict into kwds2. If kwds2 is NULL,
# containing any extra arguments. On success, replaces the borrowed # these keywords will raise an invalid keyword error.
# reference *kwds with references to a new dict, and passes back a
# new reference in *kwds2. Does not touch any of its arguments on
# failure.
# #
# Any of *kwds and kwds2 may be 0 (but not kwds). If *kwds == 0, it # Three kinds of errors are checked: 1) non-string keywords, 2)
# is not changed. If kwds2 == 0 and *kwds != 0, a new reference to # unexpected keywords and 3) overlap with positional arguments.
# the same dictionary is passed back in *kwds.
# #
# If rqd_kwds is not 0, it is an array of booleans corresponding to # If num_posargs is greater 0, it denotes the number of positional
# the names in kwd_list, indicating required keyword arguments. If # arguments that were passed and that must therefore not appear
# any of these are not present in kwds, an exception is raised. # amongst the keywords as well.
#
# This method does not check for required keyword arguments.
# #
get_splitkeywords_utility_code = [ split_keywords_utility_code = [
""" """
static int __Pyx_SplitKeywords(PyObject **kwds, char *kwd_list[], \ static int __Pyx_SplitKeywords(PyObject *kwds, PyObject **argnames[], \
PyObject **kwds2, char rqd_kwds[]); /*proto*/ PyObject *kwds2, Py_ssize_t num_pos_args, const char* function_name); /*proto*/
""",""" ""","""
static int __Pyx_SplitKeywords( static int __Pyx_SplitKeywords(
PyObject **kwds, PyObject *kwds,
char *kwd_list[], PyObject **argnames[],
PyObject **kwds2, PyObject *kwds2,
char rqd_kwds[]) Py_ssize_t num_pos_args,
const char* function_name)
{ {
PyObject *s = 0, *x = 0, *kwds1 = 0; PyObject *key = 0, *value = 0;
int i; Py_ssize_t pos = 0;
char **p; PyObject*** name;
if (*kwds) { while (PyDict_Next(kwds, &pos, &key, &value)) {
kwds1 = PyDict_New();
if (!kwds1)
goto bad;
*kwds2 = PyDict_Copy(*kwds);
if (!*kwds2)
goto bad;
for (i = 0, p = kwd_list; *p; i++, p++) {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
s = PyString_FromString(*p); if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
#else #else
s = PyUnicode_FromString(*p); if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
#endif
goto invalid_keyword_type;
} else {
name = argnames;
while (*name && (**name != key)) name++;
if (!*name) {
for (name = argnames; *name; name++) {
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
PyUnicode_Compare(**name, key) == 0) break;
#else
if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
strcmp(PyString_AS_STRING(**name),
PyString_AS_STRING(key)) == 0) break;
#endif #endif
x = PyDict_GetItem(*kwds, s);
if (x) {
if (PyDict_SetItem(kwds1, s, x) < 0)
goto bad;
if (PyDict_DelItem(*kwds2, s) < 0)
goto bad;
}
else if (rqd_kwds && rqd_kwds[i])
goto missing_kwarg;
Py_DECREF(s);
} }
s = 0; if (!*name) {
if (kwds2) {
if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
} else {
goto invalid_keyword;
} }
else {
if (rqd_kwds) {
for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i])
goto missing_kwarg;
} }
*kwds2 = PyDict_New();
if (!*kwds2)
goto bad;
} }
if (*name && ((name-argnames) < num_pos_args))
*kwds = kwds1; goto arg_passed_twice;
return 0;
missing_kwarg:
PyErr_Format(PyExc_TypeError,
"required keyword argument '%s' is missing", *p);
bad:
Py_XDECREF(s);
Py_XDECREF(kwds1);
Py_XDECREF(*kwds2);
return -1;
}
"""]
get_checkkeywords_utility_code = [
"""
static INLINE int __Pyx_CheckRequiredKeywords(PyObject *kwds, char *kwd_list[],
char rqd_kwds[]); /*proto*/
""","""
static INLINE int __Pyx_CheckRequiredKeywords(
PyObject *kwds,
char *kwd_list[],
char rqd_kwds[])
{
int i;
char **p;
if (kwds) {
for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i] && !PyDict_GetItemString(kwds, *p))
goto missing_kwarg;
} }
else {
for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i])
goto missing_kwarg;
} }
return 0; return 0;
missing_kwarg: arg_passed_twice:
__Pyx_RaiseDoubleKeywordsError(function_name, **name);
goto bad;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
goto bad;
invalid_keyword:
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"required keyword argument '%s' is missing", *p); #if PY_MAJOR_VERSION < 3
"%s() got an unexpected keyword argument '%s'",
function_name, PyString_AsString(key));
#else
"%s() got an unexpected keyword argument '%U'",
function_name, key);
#endif
bad:
return -1; return -1;
} }
"""] """]
...@@ -4498,16 +4672,19 @@ static void __Pyx_WriteUnraisable(const char *name); /*proto*/ ...@@ -4498,16 +4672,19 @@ static void __Pyx_WriteUnraisable(const char *name); /*proto*/
static void __Pyx_WriteUnraisable(const char *name) { static void __Pyx_WriteUnraisable(const char *name) {
PyObject *old_exc, *old_val, *old_tb; PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx; PyObject *ctx;
PyErr_Fetch(&old_exc, &old_val, &old_tb); __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name); ctx = PyString_FromString(name);
#else #else
ctx = PyUnicode_FromString(name); ctx = PyUnicode_FromString(name);
#endif #endif
PyErr_Restore(old_exc, old_val, old_tb); __Pyx_ErrRestore(old_exc, old_val, old_tb);
if (!ctx) if (!ctx) {
ctx = Py_None; PyErr_WriteUnraisable(Py_None);
} else {
PyErr_WriteUnraisable(ctx); PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
} }
"""] """]
...@@ -4579,7 +4756,7 @@ static void __Pyx_AddTraceback(const char *funcname) { ...@@ -4579,7 +4756,7 @@ static void __Pyx_AddTraceback(const char *funcname) {
); );
if (!py_code) goto bad; if (!py_code) goto bad;
py_frame = PyFrame_New( py_frame = PyFrame_New(
PyThreadState_Get(), /*PyThreadState *tstate,*/ PyThreadState_GET(), /*PyThreadState *tstate,*/
py_code, /*PyCodeObject *code,*/ py_code, /*PyCodeObject *code,*/
py_globals, /*PyObject *globals,*/ py_globals, /*PyObject *globals,*/
0 /*PyObject *locals*/ 0 /*PyObject *locals*/
...@@ -4603,6 +4780,39 @@ bad: ...@@ -4603,6 +4780,39 @@ bad:
'EMPTY_TUPLE' : Naming.empty_tuple, 'EMPTY_TUPLE' : Naming.empty_tuple,
}] }]
restore_exception_utility_code = [
"""
void INLINE __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
void INLINE __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""","""
void INLINE __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
void INLINE __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
"""]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
set_vtable_utility_code = [ set_vtable_utility_code = [
...@@ -4697,8 +4907,8 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); ...@@ -4697,8 +4907,8 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb);
""",""" ""","""
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) { static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb; PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_GET();
PyErr_Fetch(type, value, tb); __Pyx_ErrFetch(type, value, tb);
PyErr_NormalizeException(type, value, tb); PyErr_NormalizeException(type, value, tb);
if (PyErr_Occurred()) if (PyErr_Occurred())
goto bad; goto bad;
...@@ -4727,3 +4937,35 @@ bad: ...@@ -4727,3 +4937,35 @@ bad:
"""] """]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
reset_exception_utility_code = [
"""
void INLINE __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""","""
void INLINE __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
"""]
#------------------------------------------------------------------------------------
...@@ -56,9 +56,8 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -56,9 +56,8 @@ class SwitchTransform(Visitor.VisitorTransform):
def visit_IfStatNode(self, node): def visit_IfStatNode(self, node):
self.visitchildren(node) self.visitchildren(node)
if len(node.if_clauses) < 3:
return node
common_var = None common_var = None
case_count = 0
cases = [] cases = []
for if_clause in node.if_clauses: for if_clause in node.if_clauses:
var, conditions = self.extract_conditions(if_clause.condition) var, conditions = self.extract_conditions(if_clause.condition)
...@@ -70,9 +69,12 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -70,9 +69,12 @@ class SwitchTransform(Visitor.VisitorTransform):
return node return node
else: else:
common_var = var common_var = var
case_count += len(conditions)
cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos, cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos,
conditions = conditions, conditions = conditions,
body = if_clause.body)) body = if_clause.body))
if case_count < 2:
return node
common_var = unwrap_node(common_var) common_var = unwrap_node(common_var)
return Nodes.SwitchStatNode(pos = node.pos, return Nodes.SwitchStatNode(pos = node.pos,
......
...@@ -57,12 +57,14 @@ c_line_in_traceback = 1 ...@@ -57,12 +57,14 @@ c_line_in_traceback = 1
# Declare pragmas # Declare pragmas
option_types = { option_types = {
'boundscheck' : bool, 'boundscheck' : bool,
'nonecheck' : bool 'nonecheck' : bool,
'embedsignature' : bool
} }
option_defaults = { option_defaults = {
'boundscheck' : True, 'boundscheck' : True,
'nonecheck' : False 'nonecheck' : False,
'embedsignature' : False,
} }
def parse_option_value(name, value): def parse_option_value(name, value):
......
...@@ -80,7 +80,7 @@ class NormalizeTree(CythonTransform): ...@@ -80,7 +80,7 @@ class NormalizeTree(CythonTransform):
class PostParseError(CompileError): pass class PostParseError(CompileError): pass
# error strings checked by unit tests, so define them # error strings checked by unit tests, so define them
ERR_CDEF_INCLASS = 'Cannot assign default value to cdef class attributes' ERR_CDEF_INCLASS = 'Cannot assign default value to fields in cdef classes, structs or unions'
ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables' ERR_BUF_LOCALONLY = 'Buffer types only allowed as function local variables'
ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)' ERR_BUF_DEFAULTS = 'Invalid buffer defaults specification (see docs)'
ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared' ERR_INVALID_SPECIALATTR_TYPE = 'Special attributes must not have a type declared'
...@@ -130,31 +130,33 @@ class PostParse(CythonTransform): ...@@ -130,31 +130,33 @@ class PostParse(CythonTransform):
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
self.scope_type = 'module' self.scope_type = 'module'
self.scope_node = node
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_ClassDefNode(self, node): def visit_scope(self, node, scope_type):
prev = self.scope_type prev = self.scope_type, self.scope_node
self.scope_type = 'class' self.scope_type = scope_type
self.classnode = node self.scope_node = node
self.visitchildren(node) self.visitchildren(node)
self.scope_type = prev self.scope_type, self.scope_node = prev
del self.classnode
return node return node
def visit_ClassDefNode(self, node):
return self.visit_scope(node, 'class')
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
prev = self.scope_type return self.visit_scope(node, 'function')
self.scope_type = 'function'
self.visitchildren(node) def visit_CStructOrUnionDefNode(self, node):
self.scope_type = prev return self.visit_scope(node, 'struct')
return node
# cdef variables # cdef variables
def handle_bufferdefaults(self, decl): def handle_bufferdefaults(self, decl):
if not isinstance(decl.default, DictNode): if not isinstance(decl.default, DictNode):
raise PostParseError(decl.pos, ERR_BUF_DEFAULTS) raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
self.classnode.buffer_defaults_node = decl.default self.scope_node.buffer_defaults_node = decl.default
self.classnode.buffer_defaults_pos = decl.pos self.scope_node.buffer_defaults_pos = decl.pos
def visit_CVarDefNode(self, node): def visit_CVarDefNode(self, node):
# This assumes only plain names and pointers are assignable on # This assumes only plain names and pointers are assignable on
...@@ -171,8 +173,8 @@ class PostParse(CythonTransform): ...@@ -171,8 +173,8 @@ class PostParse(CythonTransform):
declbase = declbase.base declbase = declbase.base
if isinstance(declbase, CNameDeclaratorNode): if isinstance(declbase, CNameDeclaratorNode):
if declbase.default is not None: if declbase.default is not None:
if self.scope_type == 'class': if self.scope_type in ('class', 'struct'):
if isinstance(self.classnode, CClassDefNode): if isinstance(self.scope_node, CClassDefNode):
handler = self.specialattribute_handlers.get(decl.name) handler = self.specialattribute_handlers.get(decl.name)
if handler: if handler:
if decl is not declbase: if decl is not declbase:
...@@ -346,7 +348,7 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -346,7 +348,7 @@ class InterpretCompilerDirectives(CythonTransform):
assert isinstance(body, StatListNode), body assert isinstance(body, StatListNode), body
retbody = self.visit_Node(body) retbody = self.visit_Node(body)
directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody, directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody,
directives=options) directives=newoptions)
self.options = oldoptions self.options = oldoptions
return directive return directive
......
...@@ -229,6 +229,8 @@ def p_typecast(s): ...@@ -229,6 +229,8 @@ def p_typecast(s):
pos = s.position() pos = s.position()
s.next() s.next()
base_type = p_c_base_type(s) base_type = p_c_base_type(s)
if base_type.name is None:
s.error("Unknown type")
declarator = p_c_declarator(s, empty = 1) declarator = p_c_declarator(s, empty = 1)
if s.sy == '?': if s.sy == '?':
s.next() s.next()
...@@ -297,7 +299,14 @@ def p_call(s, function): ...@@ -297,7 +299,14 @@ def p_call(s, function):
keyword_args = [] keyword_args = []
star_arg = None star_arg = None
starstar_arg = None starstar_arg = None
while s.sy not in ('*', '**', ')'): while s.sy not in ('**', ')'):
if s.sy == '*':
if star_arg:
s.error("only one star-arg parameter allowed",
pos = s.position())
s.next()
star_arg = p_simple_expr(s)
else:
arg = p_simple_expr(s) arg = p_simple_expr(s)
if s.sy == '=': if s.sy == '=':
s.next() s.next()
...@@ -313,16 +322,14 @@ def p_call(s, function): ...@@ -313,16 +322,14 @@ def p_call(s, function):
if keyword_args: if keyword_args:
s.error("Non-keyword arg following keyword arg", s.error("Non-keyword arg following keyword arg",
pos = arg.pos) pos = arg.pos)
if star_arg:
s.error("Non-keyword arg following star-arg",
pos = arg.pos)
positional_args.append(arg) positional_args.append(arg)
if s.sy != ',': if s.sy != ',':
break break
s.next() s.next()
if s.sy == '*':
s.next()
star_arg = p_simple_expr(s)
if s.sy == ',':
s.next()
if s.sy == '**': if s.sy == '**':
s.next() s.next()
starstar_arg = p_simple_expr(s) starstar_arg = p_simple_expr(s)
...@@ -1738,7 +1745,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0, ...@@ -1738,7 +1745,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0,
if s.sy == '(': if s.sy == '(':
s.next() s.next()
if s.sy == ')' or looking_at_type(s): if s.sy == ')' or looking_at_type(s):
base = Nodes.CNameDeclaratorNode(pos, name = "", cname = None) base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None)
result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag) result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
else: else:
result = p_c_declarator(s, ctx, empty = empty, is_type = is_type, result = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
...@@ -1808,7 +1815,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -1808,7 +1815,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
else: else:
rhs = None rhs = None
if s.sy == 'IDENT': if s.sy == 'IDENT':
name = s.systring name = EncodedString(s.systring)
if is_type: if is_type:
s.add_type_name(name) s.add_type_name(name)
if empty: if empty:
...@@ -2171,7 +2178,7 @@ def p_def_statement(s, decorators=None): ...@@ -2171,7 +2178,7 @@ def p_def_statement(s, decorators=None):
# s.sy == 'def' # s.sy == 'def'
pos = s.position() pos = s.position()
s.next() s.next()
name = p_ident(s) name = EncodedString( p_ident(s) )
#args = [] #args = []
s.expect('('); s.expect('(');
args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1) args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1)
......
...@@ -29,6 +29,7 @@ class PyrexType(BaseType): ...@@ -29,6 +29,7 @@ class PyrexType(BaseType):
# is_extension_type boolean Is a Python extension type # is_extension_type boolean Is a Python extension type
# is_numeric boolean Is a C numeric type # is_numeric boolean Is a C numeric type
# is_int boolean Is a C integer type # is_int boolean Is a C integer type
# is_longlong boolean Is a long long or unsigned long long.
# is_float boolean Is a C floating point type # is_float boolean Is a C floating point type
# is_void boolean Is the C void type # is_void boolean Is the C void type
# is_array boolean Is a C array type # is_array boolean Is a C array type
...@@ -79,6 +80,7 @@ class PyrexType(BaseType): ...@@ -79,6 +80,7 @@ class PyrexType(BaseType):
is_builtin_type = 0 is_builtin_type = 0
is_numeric = 0 is_numeric = 0
is_int = 0 is_int = 0
is_longlong = 0
is_float = 0 is_float = 0
is_void = 0 is_void = 0
is_array = 0 is_array = 0
...@@ -553,12 +555,14 @@ class CULongType(CUIntType): ...@@ -553,12 +555,14 @@ class CULongType(CUIntType):
class CLongLongType(CUIntType): class CLongLongType(CUIntType):
is_longlong = 1
to_py_function = "PyLong_FromLongLong" to_py_function = "PyLong_FromLongLong"
from_py_function = "__pyx_PyInt_AsLongLong" from_py_function = "__pyx_PyInt_AsLongLong"
class CULongLongType(CUIntType): class CULongLongType(CUIntType):
is_longlong = 1
to_py_function = "PyLong_FromUnsignedLongLong" to_py_function = "PyLong_FromUnsignedLongLong"
from_py_function = "__pyx_PyInt_AsUnsignedLongLong" from_py_function = "__pyx_PyInt_AsUnsignedLongLong"
...@@ -728,7 +732,7 @@ class CFuncType(CType): ...@@ -728,7 +732,7 @@ class CFuncType(CType):
return 1 return 1
if not other_type.is_cfunction: if not other_type.is_cfunction:
return 0 return 0
if not self.is_overridable and other_type.is_overridable: if self.is_overridable != other_type.is_overridable:
return 0 return 0
nargs = len(self.args) nargs = len(self.args)
if nargs != len(other_type.args): if nargs != len(other_type.args):
...@@ -842,6 +846,8 @@ class CFuncType(CType): ...@@ -842,6 +846,8 @@ class CFuncType(CType):
for arg in self.args[:len(self.args)-self.optional_arg_count]: for arg in self.args[:len(self.args)-self.optional_arg_count]:
arg_decl_list.append( arg_decl_list.append(
arg.type.declaration_code("", for_display, pyrex = pyrex)) arg.type.declaration_code("", for_display, pyrex = pyrex))
if self.is_overridable:
arg_decl_list.append("int %s" % Naming.skip_dispatch_cname)
if self.optional_arg_count: if self.optional_arg_count:
arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname)) arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname))
if self.has_varargs: if self.has_varargs:
...@@ -1175,11 +1181,16 @@ def widest_numeric_type(type1, type2): ...@@ -1175,11 +1181,16 @@ def widest_numeric_type(type1, type2):
# Given two numeric types, return the narrowest type # Given two numeric types, return the narrowest type
# encompassing both of them. # encompassing both of them.
if type1.is_enum and type2.is_enum: if type1.is_enum and type2.is_enum:
widest_type = c_int_type return c_int_type
elif type2.rank > type1.rank: elif type1 is type2:
widest_type = type2 return type1
elif (type1.signed and type2.signed) or (not type1.signed and not type2.signed):
if type2.rank > type1.rank:
return type2
else:
return type1
else: else:
widest_type = type1 return sign_and_rank_to_type[min(type1.signed, type2.signed), max(type1.rank, type2.rank)]
return widest_type return widest_type
def simple_c_type(signed, longness, name): def simple_c_type(signed, longness, name):
......
...@@ -138,6 +138,7 @@ class Entry: ...@@ -138,6 +138,7 @@ class Entry:
utility_code = None utility_code = None
is_overridable = 0 is_overridable = 0
buffer_aux = None buffer_aux = None
prev_entry = None
def __init__(self, name, cname, type, pos = None, init = None): def __init__(self, name, cname, type, pos = None, init = None):
self.name = name self.name = name
...@@ -280,7 +281,7 @@ class Scope: ...@@ -280,7 +281,7 @@ class Scope:
if name and dict.has_key(name): if name and dict.has_key(name):
if visibility == 'extern': if visibility == 'extern':
warning(pos, "'%s' redeclared " % name, 0) warning(pos, "'%s' redeclared " % name, 0)
else: elif visibility != 'ignore':
error(pos, "'%s' redeclared " % name) error(pos, "'%s' redeclared " % name)
entry = Entry(name, cname, type, pos = pos) entry = Entry(name, cname, type, pos = pos)
entry.in_cinclude = self.in_cinclude entry.in_cinclude = self.in_cinclude
...@@ -1414,22 +1415,8 @@ class CClassScope(ClassScope): ...@@ -1414,22 +1415,8 @@ class CClassScope(ClassScope):
if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: if type.same_c_signature_as(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
pass pass
elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil: elif type.compatible_signature_with(entry.type, as_cmethod = 1) and type.nogil == entry.type.nogil:
if type.optional_arg_count and not type.original_sig.optional_arg_count: entry = self.add_cfunction(name, type, pos, cname or name, visibility='ignore')
# Need to put a wrapper taking no optional arguments
# into the method table.
wrapper_func_cname = self.mangle(Naming.func_prefix, name) + Naming.no_opt_args
wrapper_func_name = name + Naming.no_opt_args
if entry.type.optional_arg_count:
old_entry = self.lookup_here(wrapper_func_name)
old_entry.func_cname = wrapper_func_cname
else:
entry.func_cname = wrapper_func_cname
entry.name = wrapper_func_name
entry = self.add_cfunction(name, type, pos, cname or name, visibility)
defining = 1 defining = 1
entry.type = type
# if type.narrower_c_signature_than(entry.type, as_cmethod = 1):
# entry.type = type
else: else:
error(pos, "Signature not compatible with previous declaration") error(pos, "Signature not compatible with previous declaration")
error(entry.pos, "Previous declaration is here") error(entry.pos, "Previous declaration is here")
...@@ -1445,8 +1432,10 @@ class CClassScope(ClassScope): ...@@ -1445,8 +1432,10 @@ class CClassScope(ClassScope):
def add_cfunction(self, name, type, pos, cname, visibility): def add_cfunction(self, name, type, pos, cname, visibility):
# Add a cfunction entry without giving it a func_cname. # Add a cfunction entry without giving it a func_cname.
prev_entry = self.lookup_here(name)
entry = ClassScope.add_cfunction(self, name, type, pos, cname, visibility) entry = ClassScope.add_cfunction(self, name, type, pos, cname, visibility)
entry.is_cmethod = 1 entry.is_cmethod = 1
entry.prev_entry = prev_entry
return entry return entry
def declare_property(self, name, doc, pos): def declare_property(self, name, doc, pos):
......
...@@ -127,13 +127,15 @@ class SlotDescriptor: ...@@ -127,13 +127,15 @@ class SlotDescriptor:
# flag Py_TPFLAGS_XXX value indicating presence of slot # flag Py_TPFLAGS_XXX value indicating presence of slot
# py3k Indicates presence of slot in Python 3 # py3k Indicates presence of slot in Python 3
# py2 Indicates presence of slot in Python 2 # py2 Indicates presence of slot in Python 2
# ifdef Full #ifdef string that slot is wrapped in. Using this causes py3k, py2 and flags to be ignored.)
def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True): def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True, ifdef = None):
self.slot_name = slot_name self.slot_name = slot_name
self.is_initialised_dynamically = dynamic self.is_initialised_dynamically = dynamic
self.flag = flag self.flag = flag
self.py3k = py3k self.py3k = py3k
self.py2 = py2 self.py2 = py2
self.ifdef = ifdef
def generate(self, scope, code): def generate(self, scope, code):
if self.is_initialised_dynamically: if self.is_initialised_dynamically:
...@@ -143,6 +145,9 @@ class SlotDescriptor: ...@@ -143,6 +145,9 @@ class SlotDescriptor:
flag = self.flag flag = self.flag
py3k = self.py3k py3k = self.py3k
py2 = self.py2 py2 = self.py2
if self.ifdef:
code.putln("#if %s" % self.ifdef)
else:
if not py3k: if not py3k:
code.putln("#if PY_MAJOR_VERSION < 3") code.putln("#if PY_MAJOR_VERSION < 3")
elif not py2: elif not py2:
...@@ -150,9 +155,7 @@ class SlotDescriptor: ...@@ -150,9 +155,7 @@ class SlotDescriptor:
if flag: if flag:
code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag) code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag)
code.putln("%s, /*%s*/" % (value, self.slot_name)) code.putln("%s, /*%s*/" % (value, self.slot_name))
if flag: if flag or (not py3k or not py2) or self.ifdef:
code.putln("#endif")
if not py3k or not py2:
code.putln("#endif") code.putln("#endif")
# Some C implementations have trouble statically # Some C implementations have trouble statically
...@@ -199,8 +202,8 @@ class MethodSlot(SlotDescriptor): ...@@ -199,8 +202,8 @@ class MethodSlot(SlotDescriptor):
# method_name string The __xxx__ name of the method # method_name string The __xxx__ name of the method
# default string or None Default value of the slot # default string or None Default value of the slot
def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True): def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True, ifdef=None):
SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2) SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2, ifdef=ifdef)
self.signature = signature self.signature = signature
self.slot_name = slot_name self.slot_name = slot_name
self.method_name = method_name self.method_name = method_name
...@@ -296,7 +299,7 @@ class TypeFlagsSlot(SlotDescriptor): ...@@ -296,7 +299,7 @@ class TypeFlagsSlot(SlotDescriptor):
# Descriptor for the type flags slot. # Descriptor for the type flags slot.
def slot_code(self, scope): def slot_code(self, scope):
value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE" value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER"
if scope.needs_gc(): if scope.needs_gc():
value += "|Py_TPFLAGS_HAVE_GC" value += "|Py_TPFLAGS_HAVE_GC"
return value return value
...@@ -609,8 +612,8 @@ PyBufferProcs = ( ...@@ -609,8 +612,8 @@ PyBufferProcs = (
MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3k = False), MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3k = False),
MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3k = False), MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3k = False),
MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"), MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"),
MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"), MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000")
) )
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
......
...@@ -164,11 +164,26 @@ class CythonTransform(VisitorTransform): ...@@ -164,11 +164,26 @@ class CythonTransform(VisitorTransform):
super(CythonTransform, self).__init__() super(CythonTransform, self).__init__()
self.context = context self.context = context
def __call__(self, node):
import ModuleNode
if isinstance(node, ModuleNode.ModuleNode):
self.current_directives = node.directives
return super(CythonTransform, self).__call__(node)
def visit_CompilerDirectivesNode(self, node):
old = self.current_directives
self.current_directives = node.directives
self.visitchildren(node)
self.current_directives = old
return node
def visit_Node(self, node): def visit_Node(self, node):
self.visitchildren(node) self.visitchildren(node)
return node return node
# Utils # Utils
def ensure_statlist(node): def ensure_statlist(node):
if not isinstance(node, Nodes.StatListNode): if not isinstance(node, Nodes.StatListNode):
......
cimport python_buffer as pybuf
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef int Py_intptr_t ctypedef int Py_intptr_t
...@@ -19,7 +21,11 @@ cdef extern from "numpy/arrayobject.h": ...@@ -19,7 +21,11 @@ cdef extern from "numpy/arrayobject.h":
NPY_NTYPES, NPY_NTYPES,
NPY_NOTYPE, NPY_NOTYPE,
NPY_CHAR, NPY_CHAR,
NPY_USERDEF NPY_USERDEF,
NPY_C_CONTIGUOUS,
NPY_F_CONTIGUOUS
ctypedef class numpy.ndarray [object PyArrayObject]: ctypedef class numpy.ndarray [object PyArrayObject]:
cdef __cythonbufferdefaults__ = {"mode": "strided"} cdef __cythonbufferdefaults__ = {"mode": "strided"}
...@@ -29,20 +35,29 @@ cdef extern from "numpy/arrayobject.h": ...@@ -29,20 +35,29 @@ cdef extern from "numpy/arrayobject.h":
int ndim "nd" int ndim "nd"
npy_intp *shape "dimensions" npy_intp *shape "dimensions"
npy_intp *strides npy_intp *strides
int flags
# Note: This syntax (function definition in pxd files) is an # Note: This syntax (function definition in pxd files) is an
# experimental exception made for __getbuffer__ and __releasebuffer__ # experimental exception made for __getbuffer__ and __releasebuffer__
# -- the details of this may change. # -- the details of this may change.
def __getbuffer__(ndarray self, Py_buffer* info, int flags): def __getbuffer__(ndarray self, Py_buffer* info, int flags):
# This implementation of getbuffer is geared towards Cython # This implementation of getbuffer is geared towards Cython
# requirements, and does not yet fullfill the PEP (specifically, # requirements, and does not yet fullfill the PEP.
# Cython always requests and we always provide strided access, # In particular strided access is always provided regardless
# so the flags are not even checked). # of flags
if sizeof(npy_intp) != sizeof(Py_ssize_t): if sizeof(npy_intp) != sizeof(Py_ssize_t):
raise RuntimeError("Py_intptr_t and Py_ssize_t differs in size, numpy.pxd does not support this") raise RuntimeError("Py_intptr_t and Py_ssize_t differs in size, numpy.pxd does not support this")
if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
raise ValueError("ndarray is not C contiguous")
if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
raise ValueError("ndarray is not Fortran contiguous")
info.buf = PyArray_DATA(self) info.buf = PyArray_DATA(self)
# info.obj = None # this is automatic
info.ndim = PyArray_NDIM(self) info.ndim = PyArray_NDIM(self)
info.strides = <Py_ssize_t*>PyArray_STRIDES(self) info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
info.shape = <Py_ssize_t*>PyArray_DIMS(self) info.shape = <Py_ssize_t*>PyArray_DIMS(self)
...@@ -81,6 +96,7 @@ cdef extern from "numpy/arrayobject.h": ...@@ -81,6 +96,7 @@ cdef extern from "numpy/arrayobject.h":
cdef npy_intp PyArray_STRIDES(ndarray arr) cdef npy_intp PyArray_STRIDES(ndarray arr)
cdef npy_intp PyArray_DIMS(ndarray arr) cdef npy_intp PyArray_DIMS(ndarray arr)
cdef Py_ssize_t PyArray_ITEMSIZE(ndarray arr) cdef Py_ssize_t PyArray_ITEMSIZE(ndarray arr)
cdef int PyArray_CHKFLAGS(ndarray arr, int flags)
ctypedef signed int npy_byte ctypedef signed int npy_byte
ctypedef signed int npy_short ctypedef signed int npy_short
......
##################################################################### #####################################################################
# #
# These are the "SageX" pxi files for (most of) the Python/C API. # These are the Cython pxd files for (most of) the Python/C API.
#
# SageX = SAGE Pyrex, which is a fork of Pyrex for use in SAGE.
# #
# REFERENCE COUNTING: # REFERENCE COUNTING:
# #
# JUST TO SCARE YOU: # JUST TO SCARE YOU:
# If you are going to use any of the Python/C API in your SageX # If you are going to use any of the Python/C API in your Cython
# program, you might be responsible for doing reference counting. # program, you might be responsible for doing reference counting.
# Read http://docs.python.org/api/refcounts.html which is so # Read http://docs.python.org/api/refcounts.html which is so
# important I've copied it below. # important I've copied it below.
...@@ -15,10 +13,10 @@ ...@@ -15,10 +13,10 @@
# For all the declaration below, whenver the Py_ function returns # For all the declaration below, whenver the Py_ function returns
# a *new reference* to a PyObject*, the return type is "object". # a *new reference* to a PyObject*, the return type is "object".
# When the function returns a borrowed reference, the return # When the function returns a borrowed reference, the return
# type is PyObject*. When SageX sees "object" as a return type # type is PyObject*. When Cython sees "object" as a return type
# it doesn't increment the reference count. When it sees PyObject* # it doesn't increment the reference count. When it sees PyObject*
# in order to use the result you must explicitly cast to <object>, # in order to use the result you must explicitly cast to <object>,
# and when you do that SageX increments the reference count wether # and when you do that Cython increments the reference count wether
# you want it to or not, forcing you to an explicit DECREF (or leak memory). # you want it to or not, forcing you to an explicit DECREF (or leak memory).
# To avoid this we make the above convention. Note, you can # To avoid this we make the above convention. Note, you can
# always locally override this convention by putting something like # always locally override this convention by putting something like
...@@ -26,10 +24,10 @@ ...@@ -26,10 +24,10 @@
# cdef extern from "Python.h": # cdef extern from "Python.h":
# PyObject* PyNumber_Add(PyObject *o1, PyObject *o2) # PyObject* PyNumber_Add(PyObject *o1, PyObject *o2)
# #
# in your file after any .pxi includes. SageX will use the latest # in your file after any .pxi includes. Cython will use the latest
# declaration. # declaration.
# #
# SageX takes care of this automatically for anything of type object. # Cython takes care of this automatically for anything of type object.
## More precisely, I think the correct convention for ## More precisely, I think the correct convention for
## using the Python/C API from Pyrex is as follows. ## using the Python/C API from Pyrex is as follows.
## ##
...@@ -119,7 +117,7 @@ ...@@ -119,7 +117,7 @@
# #
################################################################# #################################################################
from python_version cimport *
from python_ref cimport * from python_ref cimport *
from python_exc cimport * from python_exc cimport *
from python_module cimport * from python_module cimport *
...@@ -138,6 +136,7 @@ from python_long cimport * ...@@ -138,6 +136,7 @@ from python_long cimport *
from python_float cimport * from python_float cimport *
from python_complex cimport * from python_complex cimport *
from python_string cimport * from python_string cimport *
from python_unicode cimport *
from python_dict cimport * from python_dict cimport *
from python_instance cimport * from python_instance cimport *
from python_function cimport * from python_function cimport *
......
cdef extern from *:
ctypedef int Py_UNICODE
# Return true if the object o is a Unicode object or an instance
# of a Unicode subtype. Changed in version 2.2: Allowed subtypes
# to be accepted.
bint PyUnicode_Check(object o)
# Return true if the object o is a Unicode object, but not an
# instance of a subtype. New in version 2.2.
bint PyUnicode_CheckExact(object o)
# Return the size of the object. o has to be a PyUnicodeObject
# (not checked).
Py_ssize_t PyUnicode_GET_SIZE(object o)
# Return the size of the object's internal buffer in bytes. o has
# to be a PyUnicodeObject (not checked).
Py_ssize_t PyUnicode_GET_DATA_SIZE(object o)
# Return a pointer to the internal Py_UNICODE buffer of the
# object. o has to be a PyUnicodeObject (not checked).
Py_UNICODE* PyUnicode_AS_UNICODE(object o)
# Return a pointer to the internal buffer of the object. o has to
# be a PyUnicodeObject (not checked).
char* PyUnicode_AS_DATA(object o)
# Return 1 or 0 depending on whether ch is a whitespace character.
bint Py_UNICODE_ISSPACE(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a lowercase character.
bint Py_UNICODE_ISLOWER(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an uppercase character.
bint Py_UNICODE_ISUPPER(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a titlecase character.
bint Py_UNICODE_ISTITLE(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a linebreak character.
bint Py_UNICODE_ISLINEBREAK(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a decimal character.
bint Py_UNICODE_ISDECIMAL(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a digit character.
bint Py_UNICODE_ISDIGIT(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is a numeric character.
bint Py_UNICODE_ISNUMERIC(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an alphabetic character.
bint Py_UNICODE_ISALPHA(Py_UNICODE ch)
# Return 1 or 0 depending on whether ch is an alphanumeric character.
bint Py_UNICODE_ISALNUM(Py_UNICODE ch)
# Return the character ch converted to lower case.
Py_UNICODE Py_UNICODE_TOLOWER(Py_UNICODE ch)
# Return the character ch converted to upper case.
Py_UNICODE Py_UNICODE_TOUPPER(Py_UNICODE ch)
# Return the character ch converted to title case.
Py_UNICODE Py_UNICODE_TOTITLE(Py_UNICODE ch)
# Return the character ch converted to a decimal positive
# integer. Return -1 if this is not possible. This macro does not
# raise exceptions.
int Py_UNICODE_TODECIMAL(Py_UNICODE ch)
# Return the character ch converted to a single digit
# integer. Return -1 if this is not possible. This macro does not
# raise exceptions.
int Py_UNICODE_TODIGIT(Py_UNICODE ch)
# Return the character ch converted to a double. Return -1.0 if
# this is not possible. This macro does not raise exceptions.
double Py_UNICODE_TONUMERIC(Py_UNICODE ch)
# To create Unicode objects and access their basic sequence
# properties, use these APIs:
# Create a Unicode Object from the Py_UNICODE buffer u of the
# given size. u may be NULL which causes the contents to be
# undefined. It is the user's responsibility to fill in the needed
# data. The buffer is copied into the new object. If the buffer is
# not NULL, the return value might be a shared object. Therefore,
# modification of the resulting Unicode object is only allowed
# when u is NULL.
object PyUnicode_FromUnicode(Py_UNICODE *u, Py_ssize_t size)
# Return a read-only pointer to the Unicode object's internal
# Py_UNICODE buffer, NULL if unicode is not a Unicode object.
Py_UNICODE* PyUnicode_AsUnicode(object o)
# Return the length of the Unicode object.
Py_ssize_t PyUnicode_GetSize(object o)
# Coerce an encoded object obj to an Unicode object and return a
# reference with incremented refcount.
# String and other char buffer compatible objects are decoded
# according to the given encoding and using the error handling
# defined by errors. Both can be NULL to have the interface use
# the default values (see the next section for details).
# All other objects, including Unicode objects, cause a TypeError
# to be set.
object PyUnicode_FromEncodedObject(object o, char *encoding, char *errors)
# Shortcut for PyUnicode_FromEncodedObject(obj, NULL, "strict")
# which is used throughout the interpreter whenever coercion to
# Unicode is needed.
object PyUnicode_FromObject(object obj)
# If the platform supports wchar_t and provides a header file
# wchar.h, Python can interface directly to this type using the
# following functions. Support is optimized if Python's own
# Py_UNICODE type is identical to the system's wchar_t.
#ctypedef int wchar_t
# Create a Unicode object from the wchar_t buffer w of the given
# size. Return NULL on failure.
#PyObject* PyUnicode_FromWideChar(wchar_t *w, Py_ssize_t size)
#Py_ssize_t PyUnicode_AsWideChar(object o, wchar_t *w, Py_ssize_t size)
# Codecs
# Create a Unicode object by decoding size bytes of the encoded
# string s. encoding and errors have the same meaning as the
# parameters of the same name in the unicode() builtin
# function. The codec to be used is looked up using the Python
# codec registry. Return NULL if an exception was raised by the
# codec.
object PyUnicode_Decode(char *s, Py_ssize_t size, char *encoding, char *errors)
# Encode the Py_UNICODE buffer of the given size and return a
# Python string object. encoding and errors have the same meaning
# as the parameters of the same name in the Unicode encode()
# method. The codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyUnicode_Encode(Py_UNICODE *s, Py_ssize_t size,
char *encoding, char *errors)
# Encode a Unicode object and return the result as Python string
# object. encoding and errors have the same meaning as the
# parameters of the same name in the Unicode encode() method. The
# codec to be used is looked up using the Python codec
# registry. Return NULL if an exception was raised by the codec.
object PyUnicode_AsEncodedString(object unicode, char *encoding, char *errors)
# These are the UTF-8 codec APIs:
# Create a Unicode object by decoding size bytes of the UTF-8
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeUTF8(char *s, Py_ssize_t size, char *errors)
# If consumed is NULL, behave like PyUnicode_DecodeUTF8(). If
# consumed is not NULL, trailing incomplete UTF-8 byte sequences
# will not be treated as an error. Those bytes will not be decoded
# and the number of bytes that have been decoded will be stored in
# consumed. New in version 2.4.
object PyUnicode_DecodeUTF8Stateful(char *s, Py_ssize_t size, char *errors, Py_ssize_t *consumed)
# Encode the Py_UNICODE buffer of the given size using UTF-8 and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeUTF8(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using UTF-8 and return the result as Python string object. Error handling is ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsUTF8String(object unicode)
# These are the UTF-16 codec APIs:
# Decode length bytes from a UTF-16 encoded buffer string and
# return the corresponding Unicode object. errors (if non-NULL)
# defines the error handling. It defaults to ``strict''.
#
# If byteorder is non-NULL, the decoder starts decoding using the
# given byte order:
#
# *byteorder == -1: little endian
# *byteorder == 0: native order
# *byteorder == 1: big endian
#
# and then switches if the first two bytes of the input data are a
# byte order mark (BOM) and the specified byte order is native
# order. This BOM is not copied into the resulting Unicode
# string. After completion, *byteorder is set to the current byte
# order at the.
#
# If byteorder is NULL, the codec starts in native order mode.
object PyUnicode_DecodeUTF16(char *s, Py_ssize_t size, char *errors, int *byteorder)
# If consumed is NULL, behave like PyUnicode_DecodeUTF16(). If
# consumed is not NULL, PyUnicode_DecodeUTF16Stateful() will not
# treat trailing incomplete UTF-16 byte sequences (such as an odd
# number of bytes or a split surrogate pair) as an error. Those
# bytes will not be decoded and the number of bytes that have been
# decoded will be stored in consumed. New in version 2.4.
object PyUnicode_DecodeUTF16Stateful(char *s, Py_ssize_t size, char *errors, int *byteorder, Py_ssize_t *consumed)
# Return a Python string object holding the UTF-16 encoded value
# of the Unicode data in s. If byteorder is not 0, output is
# written according to the following byte order:
#
# byteorder == -1: little endian
# byteorder == 0: native byte order (writes a BOM mark)
# byteorder == 1: big endian
#
# If byteorder is 0, the output string will always start with the
# Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark
# is prepended.
#
# If Py_UNICODE_WIDE is defined, a single Py_UNICODE value may get
# represented as a surrogate pair. If it is not defined, each
# Py_UNICODE values is interpreted as an UCS-2 character.
object PyUnicode_EncodeUTF16(Py_UNICODE *s, Py_ssize_t size, char *errors, int byteorder)
# Return a Python string using the UTF-16 encoding in native byte
# order. The string always starts with a BOM mark. Error handling
# is ``strict''. Return NULL if an exception was raised by the
# codec.
object PyUnicode_AsUTF16String(object unicode)
# These are the ``Unicode Escape'' codec APIs:
# Create a Unicode object by decoding size bytes of the
# Unicode-Escape encoded string s. Return NULL if an exception was
# raised by the codec.
object PyUnicode_DecodeUnicodeEscape(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using
# Unicode-Escape and return a Python string object. Return NULL if
# an exception was raised by the codec.
object PyUnicode_EncodeUnicodeEscape(Py_UNICODE *s, Py_ssize_t size)
# Encode a Unicode objects using Unicode-Escape and return the
# result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsUnicodeEscapeString(object unicode)
# These are the ``Raw Unicode Escape'' codec APIs:
# Create a Unicode object by decoding size bytes of the
# Raw-Unicode-Escape encoded string s. Return NULL if an exception
# was raised by the codec.
object PyUnicode_DecodeRawUnicodeEscape(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using
# Raw-Unicode-Escape and return a Python string object. Return
# NULL if an exception was raised by the codec.
object PyUnicode_EncodeRawUnicodeEscape(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using Raw-Unicode-Escape and return the
# result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsRawUnicodeEscapeString(object unicode)
# These are the Latin-1 codec APIs: Latin-1 corresponds to the first 256 Unicode ordinals and only these are accepted by the codecs during encoding.
# Create a Unicode object by decoding size bytes of the Latin-1
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeLatin1(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using Latin-1 and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeLatin1(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using Latin-1 and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsLatin1String(object unicode)
# These are the ASCII codec APIs. Only 7-bit ASCII data is
# accepted. All other codes generate errors.
# Create a Unicode object by decoding size bytes of the ASCII
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeASCII(char *s, Py_ssize_t size, char *errors)
# Encode the Py_UNICODE buffer of the given size using ASCII and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeASCII(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using ASCII and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsASCIIString(object o)
# These are the mapping codec APIs:
#
# This codec is special in that it can be used to implement many
# different codecs (and this is in fact what was done to obtain most
# of the standard codecs included in the encodings package). The codec
# uses mapping to encode and decode characters.
#
# Decoding mappings must map single string characters to single
# Unicode characters, integers (which are then interpreted as Unicode
# ordinals) or None (meaning "undefined mapping" and causing an
# error).
#
# Encoding mappings must map single Unicode characters to single
# string characters, integers (which are then interpreted as Latin-1
# ordinals) or None (meaning "undefined mapping" and causing an
# error).
#
# The mapping objects provided must only support the __getitem__
# mapping interface.
#
# If a character lookup fails with a LookupError, the character is
# copied as-is meaning that its ordinal value will be interpreted as
# Unicode or Latin-1 ordinal resp. Because of this, mappings only need
# to contain those mappings which map characters to different code
# points.
# Create a Unicode object by decoding size bytes of the encoded
# string s using the given mapping object. Return NULL if an
# exception was raised by the codec. If mapping is NULL latin-1
# decoding will be done. Else it can be a dictionary mapping byte
# or a unicode string, which is treated as a lookup table. Byte
# values greater that the length of the string and U+FFFE
# "characters" are treated as "undefined mapping". Changed in
# version 2.4: Allowed unicode string as mapping argument.
object PyUnicode_DecodeCharmap(char *s, Py_ssize_t size, object mapping, char *errors)
# Encode the Py_UNICODE buffer of the given size using the given
# mapping object and return a Python string object. Return NULL if
# an exception was raised by the codec.
object PyUnicode_EncodeCharmap(Py_UNICODE *s, Py_ssize_t size, object mapping, char *errors)
# Encode a Unicode objects using the given mapping object and
# return the result as Python string object. Error handling is
# ``strict''. Return NULL if an exception was raised by the codec.
object PyUnicode_AsCharmapString(object o, object mapping)
# The following codec API is special in that maps Unicode to Unicode.
# Translate a Py_UNICODE buffer of the given length by applying a
# character mapping table to it and return the resulting Unicode
# object. Return NULL when an exception was raised by the codec.
#
# The mapping table must map Unicode ordinal integers to Unicode
# ordinal integers or None (causing deletion of the character).
#
# Mapping tables need only provide the __getitem__() interface;
# dictionaries and sequences work well. Unmapped character
# ordinals (ones which cause a LookupError) are left untouched and
# are copied as-is.
object PyUnicode_TranslateCharmap(Py_UNICODE *s, Py_ssize_t size,
object table, char *errors)
# These are the MBCS codec APIs. They are currently only available on
# Windows and use the Win32 MBCS converters to implement the
# conversions. Note that MBCS (or DBCS) is a class of encodings, not
# just one. The target encoding is defined by the user settings on the
# machine running the codec.
# Create a Unicode object by decoding size bytes of the MBCS
# encoded string s. Return NULL if an exception was raised by the
# codec.
object PyUnicode_DecodeMBCS(char *s, Py_ssize_t size, char *errors)
# If consumed is NULL, behave like PyUnicode_DecodeMBCS(). If
# consumed is not NULL, PyUnicode_DecodeMBCSStateful() will not
# decode trailing lead byte and the number of bytes that have been
# decoded will be stored in consumed. New in version 2.5.
object PyUnicode_DecodeMBCSStateful(char *s, int size, char *errors, int *consumed)
# Encode the Py_UNICODE buffer of the given size using MBCS and
# return a Python string object. Return NULL if an exception was
# raised by the codec.
object PyUnicode_EncodeMBCS(Py_UNICODE *s, Py_ssize_t size, char *errors)
# Encode a Unicode objects using MBCS and return the result as
# Python string object. Error handling is ``strict''. Return NULL
# if an exception was raised by the codec.
object PyUnicode_AsMBCSString(object o)
# Python version constants
#
# It's better to evaluate these at runtime (i.e. C compile time) using
#
# if PY_MAJOR_VERSION >= 3:
# do_stuff_in_Py3_0_and_later()
# if PY_VERSION_HEX >= 0x02050000:
# do_stuff_in_Py2_5_and_later()
#
# than using the IF/DEF statements, which are evaluated at Cython
# compile time. This will keep your C code portable.
cdef extern from *:
# the complete version, e.g. 0x010502B2 == 1.5.2b2
int PY_VERSION_HEX
# the individual sections as plain numbers
int PY_MAJOR_VERSION
int PY_MINOR_VERSION
int PY_MICRO_VERSION
int PY_RELEASE_LEVEL
int PY_RELEASE_SERIAL
# Note: PY_RELEASE_LEVEL is one of
# 0xA (alpha)
# 0xB (beta)
# 0xC (release candidate)
# 0xF (final)
char[] PY_VERSION
char[] PY_PATCHLEVEL_REVISION
#! /usr/bin/env python
# --------------------------------------------------------------------
import re
from epydoc import docstringparser as dsp
CYTHON_SIGNATURE_RE = re.compile(
# Class name (for builtin methods)
r'^\s*((?P<class>\w+)\.)?' +
# The function name
r'(?P<func>\w+)' +
# The parameters
r'\(((?P<self>(?:self|cls|mcs)),?)?(?P<params>.*)\)' +
# The return value (optional)
r'(\s*(->)\s*(?P<return>\w+(?:\s*\w+)))?' +
# The end marker
r'\s*(?:\n|$)')
parse_signature = dsp.parse_function_signature
def parse_function_signature(func_doc, doc_source,
docformat, parse_errors):
PYTHON_SIGNATURE_RE = dsp._SIGNATURE_RE
assert PYTHON_SIGNATURE_RE is not CYTHON_SIGNATURE_RE
try:
dsp._SIGNATURE_RE = CYTHON_SIGNATURE_RE
found = parse_signature(func_doc, doc_source,
docformat, parse_errors)
dsp._SIGNATURE_RE = PYTHON_SIGNATURE_RE
if not found:
found = parse_signature(func_doc, doc_source,
docformat, parse_errors)
return found
finally:
dsp._SIGNATURE_RE = PYTHON_SIGNATURE_RE
dsp.parse_function_signature = parse_function_signature
# --------------------------------------------------------------------
from epydoc.cli import cli
cli()
# --------------------------------------------------------------------
...@@ -52,7 +52,8 @@ class ErrorWriter(object): ...@@ -52,7 +52,8 @@ class ErrorWriter(object):
class TestBuilder(object): class TestBuilder(object):
def __init__(self, rootdir, workdir, selectors, exclude_selectors, annotate, def __init__(self, rootdir, workdir, selectors, exclude_selectors, annotate,
cleanup_workdir, cleanup_sharedlibs, with_pyregr, cythononly): cleanup_workdir, cleanup_sharedlibs, with_pyregr, cython_only,
languages):
self.rootdir = rootdir self.rootdir = rootdir
self.workdir = workdir self.workdir = workdir
self.selectors = selectors self.selectors = selectors
...@@ -61,7 +62,8 @@ class TestBuilder(object): ...@@ -61,7 +62,8 @@ class TestBuilder(object):
self.cleanup_workdir = cleanup_workdir self.cleanup_workdir = cleanup_workdir
self.cleanup_sharedlibs = cleanup_sharedlibs self.cleanup_sharedlibs = cleanup_sharedlibs
self.with_pyregr = with_pyregr self.with_pyregr = with_pyregr
self.cythononly = cythononly self.cython_only = cython_only
self.languages = languages
def build_suite(self): def build_suite(self):
suite = unittest.TestSuite() suite = unittest.TestSuite()
...@@ -83,8 +85,6 @@ class TestBuilder(object): ...@@ -83,8 +85,6 @@ class TestBuilder(object):
workdir = os.path.join(self.workdir, context) workdir = os.path.join(self.workdir, context)
if not os.path.exists(workdir): if not os.path.exists(workdir):
os.makedirs(workdir) os.makedirs(workdir)
if workdir not in sys.path:
sys.path.insert(0, workdir)
expect_errors = (context == 'errors') expect_errors = (context == 'errors')
suite = unittest.TestSuite() suite = unittest.TestSuite()
...@@ -106,49 +106,76 @@ class TestBuilder(object): ...@@ -106,49 +106,76 @@ class TestBuilder(object):
continue continue
if context in TEST_RUN_DIRS: if context in TEST_RUN_DIRS:
if module.startswith("test_"): if module.startswith("test_"):
build_test = CythonUnitTestCase test_class = CythonUnitTestCase
else: else:
build_test = CythonRunTestCase test_class = CythonRunTestCase
test = build_test( else:
path, workdir, module, test_class = CythonCompileTestCase
annotate=self.annotate, for test in self.build_tests(test_class, path, workdir,
cleanup_workdir=self.cleanup_workdir, module, expect_errors):
cleanup_sharedlibs=self.cleanup_sharedlibs, suite.addTest(test)
cythononly=self.cythononly) return suite
def build_tests(self, test_class, path, workdir, module, expect_errors):
if expect_errors:
languages = self.languages[:1]
else: else:
test = CythonCompileTestCase( languages = self.languages
path, workdir, module, tests = [ self.build_test(test_class, path, workdir, module,
language, expect_errors)
for language in languages ]
return tests
def build_test(self, test_class, path, workdir, module,
language, expect_errors):
workdir = os.path.join(workdir, language)
if not os.path.exists(workdir):
os.makedirs(workdir)
return test_class(path, workdir, module,
language=language,
expect_errors=expect_errors, expect_errors=expect_errors,
annotate=self.annotate, annotate=self.annotate,
cleanup_workdir=self.cleanup_workdir, cleanup_workdir=self.cleanup_workdir,
cleanup_sharedlibs=self.cleanup_sharedlibs, cleanup_sharedlibs=self.cleanup_sharedlibs,
cythononly=self.cythononly) cython_only=self.cython_only)
suite.addTest(test)
return suite
class CythonCompileTestCase(unittest.TestCase): class CythonCompileTestCase(unittest.TestCase):
def __init__(self, directory, workdir, module, def __init__(self, directory, workdir, module, language='c',
expect_errors=False, annotate=False, cleanup_workdir=True, expect_errors=False, annotate=False, cleanup_workdir=True,
cleanup_sharedlibs=True, cythononly=False): cleanup_sharedlibs=True, cython_only=False):
self.directory = directory self.directory = directory
self.workdir = workdir self.workdir = workdir
self.module = module self.module = module
self.language = language
self.expect_errors = expect_errors self.expect_errors = expect_errors
self.annotate = annotate self.annotate = annotate
self.cleanup_workdir = cleanup_workdir self.cleanup_workdir = cleanup_workdir
self.cleanup_sharedlibs = cleanup_sharedlibs self.cleanup_sharedlibs = cleanup_sharedlibs
self.cythononly = cythononly self.cython_only = cython_only
unittest.TestCase.__init__(self) unittest.TestCase.__init__(self)
def shortDescription(self): def shortDescription(self):
return "compiling " + self.module return "compiling (%s) %s" % (self.language, self.module)
def setUp(self):
if self.workdir not in sys.path:
sys.path.insert(0, self.workdir)
def tearDown(self): def tearDown(self):
try:
sys.path.remove(self.workdir)
except ValueError:
pass
try:
del sys.modules[self.module]
except KeyError:
pass
cleanup_c_files = WITH_CYTHON and self.cleanup_workdir cleanup_c_files = WITH_CYTHON and self.cleanup_workdir
cleanup_lib_files = self.cleanup_sharedlibs cleanup_lib_files = self.cleanup_sharedlibs
if os.path.exists(self.workdir): if os.path.exists(self.workdir):
for rmfile in os.listdir(self.workdir): for rmfile in os.listdir(self.workdir):
if not cleanup_c_files and rmfile[-2:] in (".c", ".h"): if not cleanup_c_files:
if rmfile[-2:] in (".c", ".h") or rmfile[-4:] == ".cpp":
continue continue
if not cleanup_lib_files and rmfile.endswith(".so") or rmfile.endswith(".dll"): if not cleanup_lib_files and rmfile.endswith(".so") or rmfile.endswith(".dll"):
continue continue
...@@ -177,6 +204,10 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -177,6 +204,10 @@ class CythonCompileTestCase(unittest.TestCase):
source_file = source_file[:-1] source_file = source_file[:-1]
return source_file return source_file
def build_target_filename(self, module_name):
target = '%s.%s' % (module_name, self.language)
return target
def split_source_and_output(self, directory, module, workdir): def split_source_and_output(self, directory, module, workdir):
source_file = os.path.join(directory, module) + '.pyx' source_file = os.path.join(directory, module) + '.pyx'
source_and_output = open( source_and_output = open(
...@@ -202,13 +233,15 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -202,13 +233,15 @@ class CythonCompileTestCase(unittest.TestCase):
include_dirs.append(incdir) include_dirs.append(incdir)
source = self.find_module_source_file( source = self.find_module_source_file(
os.path.join(directory, module + '.pyx')) os.path.join(directory, module + '.pyx'))
target = os.path.join(targetdir, module + '.c') target = os.path.join(targetdir, self.build_target_filename(module))
options = CompilationOptions( options = CompilationOptions(
pyrex_default_options, pyrex_default_options,
include_path = include_dirs, include_path = include_dirs,
output_file = target, output_file = target,
annotate = annotate, annotate = annotate,
use_listing_file = False, cplus = False, generate_pxi = False) use_listing_file = False,
cplus = self.language == 'cpp',
generate_pxi = False)
cython_compile(source, options=options, cython_compile(source, options=options,
full_module_name=module) full_module_name=module)
...@@ -224,7 +257,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -224,7 +257,7 @@ class CythonCompileTestCase(unittest.TestCase):
extension = Extension( extension = Extension(
module, module,
sources = [module + '.c'], sources = [self.build_target_filename(module)],
extra_compile_args = CFLAGS, extra_compile_args = CFLAGS,
) )
build_extension.extensions = [extension] build_extension.extensions = [extension]
...@@ -261,20 +294,21 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -261,20 +294,21 @@ class CythonCompileTestCase(unittest.TestCase):
unexpected_error = errors[len(expected_errors)] unexpected_error = errors[len(expected_errors)]
self.assertEquals(None, unexpected_error) self.assertEquals(None, unexpected_error)
else: else:
if not self.cythononly: if not self.cython_only:
self.run_distutils(module, workdir, incdir) self.run_distutils(module, workdir, incdir)
class CythonRunTestCase(CythonCompileTestCase): class CythonRunTestCase(CythonCompileTestCase):
def shortDescription(self): def shortDescription(self):
return "compiling and running " + self.module return "compiling (%s) and running %s" % (self.language, self.module)
def run(self, result=None): def run(self, result=None):
if result is None: if result is None:
result = self.defaultTestResult() result = self.defaultTestResult()
result.startTest(self) result.startTest(self)
try: try:
self.setUp()
self.runCompileTest() self.runCompileTest()
if not self.cythononly: if not self.cython_only:
sys.stderr.write('running doctests in %s ...\n' % self.module) sys.stderr.write('running doctests in %s ...\n' % self.module)
doctest.DocTestSuite(self.module).run(result) doctest.DocTestSuite(self.module).run(result)
except Exception: except Exception:
...@@ -287,13 +321,14 @@ class CythonRunTestCase(CythonCompileTestCase): ...@@ -287,13 +321,14 @@ class CythonRunTestCase(CythonCompileTestCase):
class CythonUnitTestCase(CythonCompileTestCase): class CythonUnitTestCase(CythonCompileTestCase):
def shortDescription(self): def shortDescription(self):
return "compiling tests in " + self.module return "compiling (%s) tests in %s" % (self.language, self.module)
def run(self, result=None): def run(self, result=None):
if result is None: if result is None:
result = self.defaultTestResult() result = self.defaultTestResult()
result.startTest(self) result.startTest(self)
try: try:
self.setUp()
self.runCompileTest() self.runCompileTest()
sys.stderr.write('running tests in %s ...\n' % self.module) sys.stderr.write('running tests in %s ...\n' % self.module)
unittest.defaultTestLoader.loadTestsFromName(self.module).run(result) unittest.defaultTestLoader.loadTestsFromName(self.module).run(result)
...@@ -394,6 +429,12 @@ if __name__ == '__main__': ...@@ -394,6 +429,12 @@ if __name__ == '__main__':
parser.add_option("--no-cython", dest="with_cython", parser.add_option("--no-cython", dest="with_cython",
action="store_false", default=True, action="store_false", default=True,
help="do not run the Cython compiler, only the C compiler") help="do not run the Cython compiler, only the C compiler")
parser.add_option("--no-c", dest="use_c",
action="store_false", default=True,
help="do not test C compilation")
parser.add_option("--no-cpp", dest="use_cpp",
action="store_false", default=True,
help="do not test C++ compilation")
parser.add_option("--no-unit", dest="unittests", parser.add_option("--no-unit", dest="unittests",
action="store_false", default=True, action="store_false", default=True,
help="do not run the unit tests") help="do not run the unit tests")
...@@ -406,18 +447,24 @@ if __name__ == '__main__': ...@@ -406,18 +447,24 @@ if __name__ == '__main__':
parser.add_option("--no-pyregr", dest="pyregr", parser.add_option("--no-pyregr", dest="pyregr",
action="store_false", default=True, action="store_false", default=True,
help="do not run the regression tests of CPython in tests/pyregr/") help="do not run the regression tests of CPython in tests/pyregr/")
parser.add_option("--cython-only", dest="cythononly", parser.add_option("--cython-only", dest="cython_only",
action="store_true", default=False, action="store_true", default=False,
help="only compile pyx to c, do not run C compiler or run the tests") help="only compile pyx to c, do not run C compiler or run the tests")
parser.add_option("--sys-pyregr", dest="system_pyregr", parser.add_option("--sys-pyregr", dest="system_pyregr",
action="store_true", default=False, action="store_true", default=False,
help="run the regression tests of the CPython installation") help="run the regression tests of the CPython installation")
parser.add_option("-x", "--exclude", dest="exclude",
action="append", metavar="PATTERN",
help="exclude tests matching the PATTERN")
parser.add_option("-C", "--coverage", dest="coverage", parser.add_option("-C", "--coverage", dest="coverage",
action="store_true", default=False, action="store_true", default=False,
help="collect source coverage data for the Compiler") help="collect source coverage data for the Compiler")
parser.add_option("-A", "--annotate", dest="annotate_source", parser.add_option("-A", "--annotate", dest="annotate_source",
action="store_true", default=False, action="store_true", default=True,
help="generate annotated HTML versions of the test source files") help="generate annotated HTML versions of the test source files")
parser.add_option("--no-annotate", dest="annotate_source",
action="store_false",
help="do not generate annotated HTML versions of the test source files")
parser.add_option("-v", "--verbose", dest="verbosity", parser.add_option("-v", "--verbose", dest="verbosity",
action="count", default=0, action="count", default=0,
help="display test progress, pass twice to print test names") help="display test progress, pass twice to print test names")
...@@ -476,6 +523,15 @@ if __name__ == '__main__': ...@@ -476,6 +523,15 @@ if __name__ == '__main__':
missing_dep_excluder = MissingDependencyExcluder(EXT_DEP_MODULES) missing_dep_excluder = MissingDependencyExcluder(EXT_DEP_MODULES)
exclude_selectors = [missing_dep_excluder] # want to pring msg at exit exclude_selectors = [missing_dep_excluder] # want to pring msg at exit
if options.exclude:
exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ]
languages = []
if options.use_c:
languages.append('c')
if options.use_cpp:
languages.append('cpp')
test_suite = unittest.TestSuite() test_suite = unittest.TestSuite()
if options.unittests: if options.unittests:
...@@ -484,18 +540,18 @@ if __name__ == '__main__': ...@@ -484,18 +540,18 @@ if __name__ == '__main__':
if options.doctests: if options.doctests:
collect_doctests(UNITTEST_ROOT, UNITTEST_MODULE + ".", test_suite, selectors) collect_doctests(UNITTEST_ROOT, UNITTEST_MODULE + ".", test_suite, selectors)
if options.filetests: if options.filetests and languages:
filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors, filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
options.annotate_source, options.cleanup_workdir, options.annotate_source, options.cleanup_workdir,
options.cleanup_sharedlibs, options.pyregr, options.cleanup_sharedlibs, options.pyregr,
options.cythononly) options.cython_only, languages)
test_suite.addTest(filetests.build_suite()) test_suite.addTest(filetests.build_suite())
if options.system_pyregr: if options.system_pyregr and languages:
filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
options.annotate_source, options.cleanup_workdir, options.annotate_source, options.cleanup_workdir,
options.cleanup_sharedlibs, True, options.cleanup_sharedlibs, True,
options.cythononly) options.cython_only, languages)
test_suite.addTest( test_suite.addTest(
filetests.handle_directory( filetests.handle_directory(
os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'), os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
......
...@@ -10,11 +10,11 @@ cdef extern from "longintrepr.h": ...@@ -10,11 +10,11 @@ cdef extern from "longintrepr.h":
cdef struct _longobject: cdef struct _longobject:
int ob_refcnt int ob_refcnt
PyTypeObject *ob_type PyTypeObject *ob_type
int ob_size # int ob_size # not in Py3k
unsigned int *ob_digit unsigned int *ob_digit
def test(temp = long(0)): def test(temp = long(0)):
cdef _longobject *l cdef _longobject *l
l = <_longobject *> temp l = <_longobject *> temp
print sizeof(l.ob_size) #print sizeof(l.ob_size) # not in Py3k
print sizeof(l.ob_digit[0]) print sizeof(l.ob_digit[0])
def f(*args, **kwargs):
pass
args = (1,2,3)
kwargs = {u"test" : "toast"}
def test():
f(*args, 1, 2, 3)
f(**kwargs, 1, 2, c=3)
f(*args, **kwargs, *args)
f(1, 2, c=3, *args, **kwargs, *args)
f(1, 2, c=3, *args, d=5, **kwargs, **kwargs)
f(1, 2, c=3, *args, d=5, **kwargs, x=6)
f(1=2)
# too bad we don't get more errors here ...
_ERRORS = u"""
8:13: Non-keyword arg following star-arg
"""
cdef class Test:
cdef __cinit__(self):
pass
cdef __len__(self):
pass
_ERRORS = u"""
3:9: Special methods must be declared with 'def', not 'cdef'
6:9: Special methods must be declared with 'def', not 'cdef'
"""
cdef class A: cdef class A:
cdef int value = 3 cdef int value = 3
cdef extern from *:
cdef struct B:
int value = 3
_ERRORS = u""" _ERRORS = u"""
2:13: Cannot assign default value to cdef class attributes 2:13: Cannot assign default value to fields in cdef classes, structs or unions
6:12: Cannot assign default value to fields in cdef classes, structs or unions
""" """
try:
raise KeyError
except KeyError:
pass
except:
pass
except:
pass
except AttributeError:
pass
_ERRORS = u"""
8:0: default 'except:' must be last
10:0: default 'except:' must be last
"""
...@@ -13,5 +13,5 @@ cdef class ExtClass: ...@@ -13,5 +13,5 @@ cdef class ExtClass:
_attribute = 5 # FIXME: this is not currently handled!!! _attribute = 5 # FIXME: this is not currently handled!!!
_ERRORS = u""" _ERRORS = u"""
8:13: Cannot assign default value to cdef class attributes 8:13: Cannot assign default value to fields in cdef classes, structs or unions
""" """
def f():
a = <foao>x
_ERRORS = """
2:13: Unknown type
"""
\ No newline at end of file
...@@ -329,6 +329,35 @@ def explicitly_release_buffer(): ...@@ -329,6 +329,35 @@ def explicitly_release_buffer():
x = None x = None
print "After release" print "After release"
#
# Format strings
#
@testcase
def alignment_string(object[int] buf):
"""
>>> alignment_string(IntMockBuffer(None, [1,2], format="@i"))
2
>>> alignment_string(IntMockBuffer(None, [1,2], format="@i@@"))
2
>>> alignment_string(IntMockBuffer(None, [1,2], format=">i"))
Traceback (most recent call last):
...
ValueError: Buffer acquisition error: Only native byte order, size and alignment supported.
>>> alignment_string(IntMockBuffer(None, [1,2], format="<i"))
Traceback (most recent call last):
...
ValueError: Buffer acquisition error: Only native byte order, size and alignment supported.
>>> alignment_string(IntMockBuffer(None, [1,2], format="=i"))
Traceback (most recent call last):
...
ValueError: Buffer acquisition error: Only native byte order, size and alignment supported.
>>> alignment_string(IntMockBuffer(None, [1,2], format="!i"))
Traceback (most recent call last):
...
ValueError: Buffer acquisition error: Only native byte order, size and alignment supported.
"""
print buf[1]
# #
# Getting items and index bounds checking # Getting items and index bounds checking
# #
...@@ -524,6 +553,54 @@ def strided(object[int, ndim=1, mode='strided'] buf): ...@@ -524,6 +553,54 @@ def strided(object[int, ndim=1, mode='strided'] buf):
""" """
return buf[2] return buf[2]
@testcase
def c_contig(object[int, ndim=1, mode='c'] buf):
"""
>>> A = IntMockBuffer(None, range(4))
>>> c_contig(A)
2
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
"""
return buf[2]
@testcase
def c_contig_2d(object[int, ndim=2, mode='c'] buf):
"""
Multi-dim has seperate implementation
>>> A = IntMockBuffer(None, range(12), shape=(3,4))
>>> c_contig_2d(A)
7
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
"""
return buf[1, 3]
@testcase
def f_contig(object[int, ndim=1, mode='fortran'] buf):
"""
>>> A = IntMockBuffer(None, range(4))
>>> f_contig(A)
2
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
"""
return buf[2]
@testcase
def f_contig_2d(object[int, ndim=2, mode='fortran'] buf):
"""
Must set up strides manually to ensure Fortran ordering.
>>> A = IntMockBuffer(None, range(12), shape=(4,3), strides=(1, 4))
>>> f_contig_2d(A)
7
>>> [str(x) for x in A.recieved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
"""
return buf[3, 1]
# #
# Test compiler options for bounds checking. We create an array with a # Test compiler options for bounds checking. We create an array with a
# safe "boundary" (memory # safe "boundary" (memory
...@@ -848,6 +925,8 @@ available_flags = ( ...@@ -848,6 +925,8 @@ available_flags = (
('INDIRECT', python_buffer.PyBUF_INDIRECT), ('INDIRECT', python_buffer.PyBUF_INDIRECT),
('ND', python_buffer.PyBUF_ND), ('ND', python_buffer.PyBUF_ND),
('STRIDES', python_buffer.PyBUF_STRIDES), ('STRIDES', python_buffer.PyBUF_STRIDES),
('C_CONTIGUOUS', python_buffer.PyBUF_C_CONTIGUOUS),
('F_CONTIGUOUS', python_buffer.PyBUF_F_CONTIGUOUS),
('WRITABLE', python_buffer.PyBUF_WRITABLE) ('WRITABLE', python_buffer.PyBUF_WRITABLE)
) )
...@@ -884,7 +963,6 @@ cdef class MockBuffer: ...@@ -884,7 +963,6 @@ cdef class MockBuffer:
strides.reverse() strides.reverse()
strides = [x * self.itemsize for x in strides] strides = [x * self.itemsize for x in strides]
suboffsets = [-1] * len(shape) suboffsets = [-1] * len(shape)
datashape = [len(data)] datashape = [len(data)]
p = data p = data
while True: while True:
...@@ -950,10 +1028,6 @@ cdef class MockBuffer: ...@@ -950,10 +1028,6 @@ cdef class MockBuffer:
if self.fail: if self.fail:
raise ValueError("Failing on purpose") raise ValueError("Failing on purpose")
if buffer is NULL:
print u"locking!"
return
self.recieved_flags = [] self.recieved_flags = []
cdef int value cdef int value
for name, value in available_flags: for name, value in available_flags:
...@@ -961,6 +1035,7 @@ cdef class MockBuffer: ...@@ -961,6 +1035,7 @@ cdef class MockBuffer:
self.recieved_flags.append(name) self.recieved_flags.append(name)
buffer.buf = <void*>(<char*>self.buffer + (<int>self.offset * self.itemsize)) buffer.buf = <void*>(<char*>self.buffer + (<int>self.offset * self.itemsize))
buffer.obj = self
buffer.len = self.len buffer.len = self.len
buffer.readonly = 0 buffer.readonly = 0
buffer.format = <char*>self.format buffer.format = <char*>self.format
...@@ -1000,7 +1075,7 @@ cdef class IntMockBuffer(MockBuffer): ...@@ -1000,7 +1075,7 @@ cdef class IntMockBuffer(MockBuffer):
(<int*>buf)[0] = <int>value (<int*>buf)[0] = <int>value
return 0 return 0
cdef get_itemsize(self): return sizeof(int) cdef get_itemsize(self): return sizeof(int)
cdef get_default_format(self): return b"=i" cdef get_default_format(self): return b"@i"
cdef class ShortMockBuffer(MockBuffer): cdef class ShortMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1: cdef int write(self, char* buf, object value) except -1:
...@@ -1014,7 +1089,7 @@ cdef class UnsignedShortMockBuffer(MockBuffer): ...@@ -1014,7 +1089,7 @@ cdef class UnsignedShortMockBuffer(MockBuffer):
(<unsigned short*>buf)[0] = <unsigned short>value (<unsigned short*>buf)[0] = <unsigned short>value
return 0 return 0
cdef get_itemsize(self): return sizeof(unsigned short) cdef get_itemsize(self): return sizeof(unsigned short)
cdef get_default_format(self): return b"=1H" # Try with repeat count cdef get_default_format(self): return b"@1H" # Try with repeat count
cdef class FloatMockBuffer(MockBuffer): cdef class FloatMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1: cdef int write(self, char* buf, object value) except -1:
...@@ -1040,7 +1115,7 @@ cdef class ObjectMockBuffer(MockBuffer): ...@@ -1040,7 +1115,7 @@ cdef class ObjectMockBuffer(MockBuffer):
return 0 return 0
cdef get_itemsize(self): return sizeof(void*) cdef get_itemsize(self): return sizeof(void*)
cdef get_default_format(self): return b"=O" cdef get_default_format(self): return b"@O"
cdef class IntStridedMockBuffer(IntMockBuffer): cdef class IntStridedMockBuffer(IntMockBuffer):
...@@ -1052,10 +1127,10 @@ cdef class ErrorBuffer: ...@@ -1052,10 +1127,10 @@ cdef class ErrorBuffer:
def __init__(self, label): def __init__(self, label):
self.label = label self.label = label
def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags): def __getbuffer__(ErrorBuffer self, Py_buffer* buffer, int flags):
raise Exception("acquiring %s" % self.label) raise Exception("acquiring %s" % self.label)
def __releasebuffer__(MockBuffer self, Py_buffer* buffer): def __releasebuffer__(ErrorBuffer self, Py_buffer* buffer):
raise Exception("releasing %s" % self.label) raise Exception("releasing %s" % self.label)
# #
......
...@@ -8,18 +8,16 @@ if sys.version_info[0] >= 3: ...@@ -8,18 +8,16 @@ if sys.version_info[0] >= 3:
__doc__ += u""" __doc__ += u"""
>>> ms = memoryview(s) >>> ms = memoryview(s)
>>> ms.tobytes() >>> ms.tobytes()
bytearray(b'abcdefg') b'abcdefg'
>>> m1 = memoryview(b1) >>> m1 = memoryview(b1)
>>> m1.tobytes() >>> m1.tobytes()
locking! b'abcdefg'
bytearray(b'abcdefg')
>>> m2 = memoryview(b2) >>> m2 = memoryview(b2)
>>> m2.tobytes() >>> m2.tobytes()
locking! releasing!
unlocking! b'abcdefg'
bytearray(b'abcdefg')
>>> del m1 >>> del m1
>>> del m2 >>> del m2
...@@ -30,10 +28,8 @@ s = "abcdefg" ...@@ -30,10 +28,8 @@ s = "abcdefg"
cdef class TestBuffer: cdef class TestBuffer:
def __getbuffer__(self, Py_buffer* buffer, int flags): def __getbuffer__(self, Py_buffer* buffer, int flags):
if buffer is NULL:
print u"locking!"
return
buffer.buf = <char*>s buffer.buf = <char*>s
buffer.obj = self
buffer.len = len(s) buffer.len = len(s)
buffer.readonly = 0 buffer.readonly = 0
buffer.format = "B" buffer.format = "B"
...@@ -46,7 +42,4 @@ cdef class TestBuffer: ...@@ -46,7 +42,4 @@ cdef class TestBuffer:
cdef class TestBufferRelease(TestBuffer): cdef class TestBufferRelease(TestBuffer):
def __releasebuffer__(self, Py_buffer* buffer): def __releasebuffer__(self, Py_buffer* buffer):
if buffer is NULL:
print u"unlocking!"
else:
print u"releasing!" print u"releasing!"
__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
"""
def e(*args, **kwargs):
print len(args), len(kwargs)
def f(*args):
print len(args)
def g(**kwargs):
print len(kwargs)
def h(a, b, c, *args, **kwargs):
print a, b, c, u'*', len(args), len(kwargs)
args = (9,8,7)
import sys
if sys.version_info[0] >= 3:
kwargs = {u"test" : u"toast"}
else:
kwargs = {"test" : u"toast"}
def test_kw_args(f):
f(1,2, c=3)
f(1,2, d=3, *args)
f(1,2, d=3, *(7,8,9))
f(1,2, d=3, *args, **kwargs)
f(1,2, d=3, *args, e=5)
f(1,2, d=3, *args, e=5, **kwargs)
def test_pos_args(f):
f(1,2,3)
f(1,2, *args)
f(1,2, *(7,8,9))
f(*args)
f(*(7,8,9))
def test_kw(f):
f(c=3)
f(d=3, e=5)
f(d=3, **kwargs)
f(**kwargs)
def test_noargs(f):
f()
def test_int_kwargs(f):
f(a=1,b=2,c=3, **{10:20,30:40})
...@@ -5,23 +5,23 @@ __doc__ = u""" ...@@ -5,23 +5,23 @@ __doc__ = u"""
>>> b(1,2,3) >>> b(1,2,3)
>>> b(1,2,3,4) >>> b(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 4 arguments (5 given) TypeError: b() takes exactly 4 positional arguments (5 given)
>>> c(1,2) >>> c(1,2)
>>> c(1,2,3) >>> c(1,2,3)
>>> c(1,2,3,4) >>> c(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 4 arguments (5 given) TypeError: c() takes at most 4 positional arguments (5 given)
>>> d(1,2) >>> d(1,2)
>>> d(1,2, c=1) >>> d(1,2, c=1)
>>> d(1,2,3) >>> d(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: d() takes exactly 3 positional arguments (4 given)
>>> d(1,2, d=1) >>> d(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'd' is an invalid keyword argument for this function TypeError: d() got an unexpected keyword argument 'd'
>>> e(1,2) >>> e(1,2)
>>> e(1,2, c=1) >>> e(1,2, c=1)
...@@ -30,34 +30,34 @@ __doc__ = u""" ...@@ -30,34 +30,34 @@ __doc__ = u"""
>>> e(1,2,3) >>> e(1,2,3)
>>> e(1,2,3,4) >>> e(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 4 positional arguments (5 given) TypeError: e() takes at most 4 positional arguments (5 given)
>>> f(1,2, c=1) >>> f(1,2, c=1)
>>> f(1,2, c=1, d=2) >>> f(1,2, c=1, d=2)
>>> f(1,2,3) >>> f(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: f() takes exactly 3 positional arguments (4 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: f() needs keyword-only argument c
>>> f(1,2, c=1, e=2) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: f() got an unexpected keyword argument 'e'
>>> g(1,2, c=1, f=2) >>> g(1,2, c=1, f=2)
>>> g(1,2, c=1, e=0, f=2, d=11) >>> g(1,2, c=1, e=0, f=2, d=11)
>>> g(1,2, c=1, f=2, e=0, x=25) >>> g(1,2, c=1, f=2, e=0, x=25)
>>> g(1,2,3) #doctest: +ELLIPSIS >>> g(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: g() takes exactly 3 positional arguments (4 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: g() needs keyword-only argument f
>>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -66,10 +66,10 @@ __doc__ = u""" ...@@ -66,10 +66,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -78,20 +78,12 @@ __doc__ = u""" ...@@ -78,20 +78,12 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"(ELLIPSIS[^>]*Error: )[^\n]*\n", u"\\1...\n", __doc__, re.M)
class Spam: class Spam:
def b(self, a, b, c): def b(self, a, b, c):
pass pass
......
#cython: embedsignature=True
# note the r, we use \n below
__doc__ = ur"""
>>> print (Ext.a.__doc__)
Ext.a(self)
>>> print (Ext.b.__doc__)
Ext.b(self, a, b, c)
>>> print (Ext.c.__doc__)
Ext.c(self, a, b, c=1)
>>> print (Ext.d.__doc__)
Ext.d(self, a, b, *, c=88)
>>> print (Ext.e.__doc__)
Ext.e(self, a, b, c=88, **kwds)
>>> print (Ext.f.__doc__)
Ext.f(self, a, b, *, c, d=42)
>>> print (Ext.g.__doc__)
Ext.g(self, a, b, *, c, d=42, e=17, f, **kwds)
>>> print (Ext.h.__doc__)
Ext.h(self, a, b, *args, c, d=42, e=17, f, **kwds)
>>> print (Ext.k.__doc__)
Ext.k(self, a, b, c=1, *args, d=42, e=17, f, **kwds)
>>> print (Ext.get_int.__doc__)
Ext.get_int(self) -> int
>>> print (Ext.get_float.__doc__)
Ext.get_float(self) -> float
>>> print (Ext.clone.__doc__)
Ext.clone(self) -> Ext
>>> print (foo.__doc__)
foo()
>>> with_doc_1.__doc__
'with_doc_1(a, b, c)\nExisting string'
>>> with_doc_2.__doc__
'with_doc_2(a, b, c)\n\n Existing string\n '
>>> types.__doc__
'types(Ext a, int b, unsigned short int c, float d, e)'
>>> print (f_c.__doc__)
f_c(char c) -> char
>>> print (f_uc.__doc__)
f_uc(unsigned char c) -> unsigned char
>>> print (f_sc.__doc__)
f_sc(signed char c) -> signed char
>>> print (f_s.__doc__)
f_s(short int s) -> short int
>>> print (f_us.__doc__)
f_us(unsigned short int s) -> unsigned short int
>>> print (f_ss.__doc__)
f_ss(signed short int s) -> signed short int
>>> print (f_i.__doc__)
f_i(int i) -> int
>>> print (f_ui.__doc__)
f_ui(unsigned int i) -> unsigned int
>>> print (f_si.__doc__)
f_si(signed int i) -> signed int
>>> print (f_l.__doc__)
f_l(long int l) -> long int
>>> print (f_ul.__doc__)
f_ul(unsigned long int l) -> unsigned long int
>>> print (f_sl.__doc__)
f_sl(signed long int l) -> signed long int
>>> print (f_L.__doc__)
f_L(long long int L) -> long long int
>>> print (f_uL.__doc__)
f_uL(unsigned long long int L) -> unsigned long long int
>>> print (f_sL.__doc__)
f_sL(signed long long int L) -> signed long long int
>>> print (f_f.__doc__)
f_f(float f) -> float
>>> print (f_d.__doc__)
f_d(double d) -> double
>>> print (f_D.__doc__)
f_D(long double D) -> long double
"""
cdef class Ext:
def a(self):
pass
def b(self, a, b, c):
pass
def c(self, a, b, c=1):
pass
def d(self, a, b, *, c = 88):
pass
def e(self, a, b, c = 88, **kwds):
pass
def f(self, a, b, *, c, d = 42):
pass
def g(self, a, b, *, c, d = 42, e = 17, f, **kwds):
pass
def h(self, a, b, *args, c, d = 42, e = 17, f, **kwds):
pass
def k(self, a, b, c=1, *args, d = 42, e = 17, f, **kwds):
pass
cpdef int get_int(self):
return 0
cpdef float get_float(self):
return 0.0
cpdef Ext clone(self):
return Ext()
def foo():
pass
def types(Ext a, int b, unsigned short c, float d, e):
pass
def with_doc_1(a, b, c):
"""Existing string"""
pass
def with_doc_2(a, b, c):
"""
Existing string
"""
pass
cpdef char f_c(char c):
return c
cpdef unsigned char f_uc(unsigned char c):
return c
cpdef signed char f_sc(signed char c):
return c
cpdef short f_s(short s):
return s
cpdef unsigned short f_us(unsigned short s):
return s
cpdef signed short f_ss(signed short s):
return s
cpdef int f_i(int i):
return i
cpdef unsigned int f_ui(unsigned int i):
return i
cpdef signed int f_si(signed int i):
return i
cpdef long f_l(long l):
return l
cpdef unsigned long f_ul(unsigned long l):
return l
cpdef signed long f_sl(signed long l):
return l
cpdef long long f_L(long long L):
return L
cpdef unsigned long long f_uL(unsigned long long L):
return L
cpdef signed long long f_sL(signed long long L):
return L
cpdef float f_f(float f):
return f
cpdef double f_d(double d):
return d
cpdef long double f_D(long double D):
return D
...@@ -5,23 +5,23 @@ __doc__ = u""" ...@@ -5,23 +5,23 @@ __doc__ = u"""
>>> b(1,2,3) >>> b(1,2,3)
>>> b(1,2,3,4) >>> b(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (4 given) TypeError: b() takes exactly 3 positional arguments (4 given)
>>> c(1,2) >>> c(1,2)
>>> c(1,2,3) >>> c(1,2,3)
>>> c(1,2,3,4) >>> c(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 arguments (4 given) TypeError: c() takes at most 3 positional arguments (4 given)
>>> d(1,2) >>> d(1,2)
>>> d(1,2, c=1) >>> d(1,2, c=1)
>>> d(1,2,3) >>> d(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: d() takes exactly 2 positional arguments (3 given)
>>> d(1,2, d=1) >>> d(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'd' is an invalid keyword argument for this function TypeError: d() got an unexpected keyword argument 'd'
>>> e(1,2) >>> e(1,2)
>>> e(1,2, c=1) >>> e(1,2, c=1)
...@@ -30,20 +30,20 @@ __doc__ = u""" ...@@ -30,20 +30,20 @@ __doc__ = u"""
>>> e(1,2,3) >>> e(1,2,3)
>>> e(1,2,3,4) >>> e(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: e() takes at most 3 positional arguments (4 given)
>>> f(1,2, c=1) >>> f(1,2, c=1)
>>> f(1,2, c=1, d=2) >>> f(1,2, c=1, d=2)
>>> f(1,2,3) >>> f(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: f() takes exactly 2 positional arguments (3 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: f() needs keyword-only argument c
>>> f(1,2, c=1, e=2) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: f() got an unexpected keyword argument 'e'
>>> g(1,2, c=1, f=2) >>> g(1,2, c=1, f=2)
>>> g(1,2, c=1, e=0, f=2, d=11) >>> g(1,2, c=1, e=0, f=2, d=11)
...@@ -51,13 +51,13 @@ __doc__ = u""" ...@@ -51,13 +51,13 @@ __doc__ = u"""
>>> g(1,2,3) >>> g(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: g() takes exactly 2 positional arguments (3 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: g() needs keyword-only argument f
>>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -66,10 +66,10 @@ __doc__ = u""" ...@@ -66,10 +66,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -78,16 +78,12 @@ __doc__ = u""" ...@@ -78,16 +78,12 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
cdef class Ext: cdef class Ext:
def b(self, a, b, c): def b(self, a, b, c):
pass pass
......
...@@ -5,15 +5,15 @@ __doc__ = u""" ...@@ -5,15 +5,15 @@ __doc__ = u"""
>>> spam(1,2,3) >>> spam(1,2,3)
(1, 2, 3) (1, 2, 3)
>>> spam(1,2) #doctest: +ELLIPSIS >>> spam(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (2 given) TypeError: spam() takes exactly 3 positional arguments (2 given)
>>> spam(1,2,3,4) >>> spam(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (4 given) TypeError: spam() takes exactly 3 positional arguments (4 given)
>>> spam(1,2,3, a=1) #doctest: +ELLIPSIS >>> spam(1,2,3, a=1) #doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: spam() got an unexpected keyword argument 'a'
>>> grail(1,2,3) >>> grail(1,2,3)
(1, 2, 3, ()) (1, 2, 3, ())
...@@ -21,23 +21,23 @@ __doc__ = u""" ...@@ -21,23 +21,23 @@ __doc__ = u"""
(1, 2, 3, (4,)) (1, 2, 3, (4,))
>>> grail(1,2,3,4,5,6,7,8,9) >>> grail(1,2,3,4,5,6,7,8,9)
(1, 2, 3, (4, 5, 6, 7, 8, 9)) (1, 2, 3, (4, 5, 6, 7, 8, 9))
>>> grail(1,2) #doctest: +ELLIPSIS >>> grail(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (2 given) TypeError: grail() takes at least 3 positional arguments (2 given)
>>> grail(1,2,3, a=1) #doctest: +ELLIPSIS >>> grail(1,2,3, a=1) #doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: grail() got an unexpected keyword argument 'a'
>>> swallow(1,2,3) >>> swallow(1,2,3)
(1, 2, 3, ()) (1, 2, 3, ())
>>> swallow(1,2,3,4) >>> swallow(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: swallow() takes exactly 3 positional arguments (4 given)
>>> swallow(1,2,3, a=1, b=2) >>> swallow(1,2,3, a=1, b=2)
(1, 2, 3, (('a', 1), ('b', 2))) (1, 2, 3, (('a', 1), ('b', 2)))
>>> swallow(1,2,3, x=1) #doctest: +ELLIPSIS >>> swallow(1,2,3, x=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: keyword parameter 'x' was given by position and by name TypeError: swallow() got multiple values for keyword argument 'x'
>>> creosote(1,2,3) >>> creosote(1,2,3)
(1, 2, 3, (), ()) (1, 2, 3, (), ())
...@@ -47,9 +47,9 @@ __doc__ = u""" ...@@ -47,9 +47,9 @@ __doc__ = u"""
(1, 2, 3, (), (('a', 1),)) (1, 2, 3, (), (('a', 1),))
>>> creosote(1,2,3,4, a=1, b=2) >>> creosote(1,2,3,4, a=1, b=2)
(1, 2, 3, (4,), (('a', 1), ('b', 2))) (1, 2, 3, (4,), (('a', 1), ('b', 2)))
>>> creosote(1,2,3,4, x=1) #doctest: +ELLIPSIS >>> creosote(1,2,3,4, x=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: keyword parameter 'x' was given by position and by name TypeError: creosote() got multiple values for keyword argument 'x'
>>> onlyt(1) >>> onlyt(1)
(1,) (1,)
...@@ -57,10 +57,10 @@ __doc__ = u""" ...@@ -57,10 +57,10 @@ __doc__ = u"""
(1, 2) (1, 2)
>>> onlyt(a=1) >>> onlyt(a=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: onlyt() got an unexpected keyword argument 'a'
>>> onlyt(1, a=2) >>> onlyt(1, a=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: onlyt() got an unexpected keyword argument 'a'
>>> onlyk(a=1) >>> onlyk(a=1)
(('a', 1),) (('a', 1),)
...@@ -68,13 +68,13 @@ __doc__ = u""" ...@@ -68,13 +68,13 @@ __doc__ = u"""
(('a', 1), ('b', 2)) (('a', 1), ('b', 2))
>>> onlyk(1) >>> onlyk(1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (1 given) TypeError: onlyk() takes exactly 0 positional arguments (1 given)
>>> onlyk(1, 2) >>> onlyk(1, 2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (2 given) TypeError: onlyk() takes exactly 0 positional arguments (2 given)
>>> onlyk(1, a=1, b=2) >>> onlyk(1, a=1, b=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (1 given) TypeError: onlyk() takes exactly 0 positional arguments (1 given)
>>> tk(a=1) >>> tk(a=1)
(('a', 1),) (('a', 1),)
...@@ -88,10 +88,6 @@ __doc__ = u""" ...@@ -88,10 +88,6 @@ __doc__ = u"""
(1, ('a', 1), ('b', 2)) (1, ('a', 1), ('b', 2))
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
import sys, re import sys, re
if sys.version_info >= (2,6): if sys.version_info >= (2,6):
__doc__ = re.sub(u"(ELLIPSIS[^>]*Error: )[^\n]*\n", u"\\1...\n", __doc__, re.M) __doc__ = re.sub(u"(ELLIPSIS[^>]*Error: )[^\n]*\n", u"\\1...\n", __doc__, re.M)
......
__doc__ = u"""
>>> import sys
>>> if not IS_PY3: sys.exc_clear()
>>> def test_py():
... try:
... raise AttributeError
... except AttributeError:
... print(sys.exc_info()[0] == AttributeError or sys.exc_info()[0])
... print((IS_PY3 and sys.exc_info()[0] is None) or
... (not IS_PY3 and sys.exc_info()[0] == AttributeError) or
... sys.exc_info()[0])
>>> print(sys.exc_info()[0]) # 0
None
>>> test_py()
True
True
>>> print(sys.exc_info()[0]) # test_py()
None
>>> test_c()
True
True
>>> print(sys.exc_info()[0]) # test_c()
None
"""
import sys
IS_PY3 = sys.version_info[0] >= 3
def test_c():
try:
raise AttributeError
except AttributeError:
print(sys.exc_info()[0] == AttributeError or sys.exc_info()[0])
print(sys.exc_info()[0] is None or sys.exc_info()[0])
__doc__ = u"""
>>> import sys
>>> if not IS_PY3: sys.exc_clear()
>>> def test_py(outer_exc):
... try:
... raise AttributeError
... except AttributeError:
... print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
... try: raise KeyError
... except: print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
... print((IS_PY3 and sys.exc_info()[0] is AttributeError) or
... (not IS_PY3 and sys.exc_info()[0] is KeyError) or
... sys.exc_info()[0])
... print((IS_PY3 and sys.exc_info()[0] is outer_exc) or
... (not IS_PY3 and sys.exc_info()[0] is KeyError) or
... sys.exc_info()[0])
>>> print(sys.exc_info()[0]) # 0
None
>>> test_py(None)
True
True
True
True
>>> print(sys.exc_info()[0]) # test_py()
None
>>> test_c(None)
True
True
True
True
>>> print(sys.exc_info()[0]) # test_c()
None
>>> def test_py2():
... try:
... raise Exception
... except Exception:
... test_py(Exception)
... print(sys.exc_info()[0] is Exception or sys.exc_info()[0])
... print((IS_PY3 and sys.exc_info()[0] is None) or
... (not IS_PY3 and sys.exc_info()[0] is Exception) or
... sys.exc_info()[0])
>>> test_py2()
True
True
True
True
True
True
>>> print(sys.exc_info()[0]) # test_py2()
None
>>> test_c2()
True
True
True
True
True
True
>>> print(sys.exc_info()[0]) # test_c2()
None
"""
import sys
IS_PY3 = sys.version_info[0] >= 3
def test_c(outer_exc):
try:
raise AttributeError
except AttributeError:
print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
try: raise KeyError
except: print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
print(sys.exc_info()[0] is outer_exc or sys.exc_info()[0])
def test_c2():
try:
raise Exception
except Exception:
test_c(Exception)
print(sys.exc_info()[0] is Exception or sys.exc_info()[0])
print(sys.exc_info()[0] is None or sys.exc_info()[0])
__doc__ = u"""
>>> import sys
>>> if not IS_PY3: sys.exc_clear()
>>> def test_py():
... try:
... raise AttributeError
... except AttributeError:
... test_c(error=AttributeError)
... print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
... print((IS_PY3 and sys.exc_info()[0] is TestException) or
... (not IS_PY3 and sys.exc_info()[0] is AttributeError) or
... sys.exc_info()[0])
>>> print(sys.exc_info()[0]) # 0
None
>>> test_py()
True
True
True
True
>>> print(sys.exc_info()[0]) # test_py()
None
>>> test_c(test_py)
True
True
True
True
True
True
>>> print(sys.exc_info()[0]) # test_c()
None
"""
import sys
IS_PY3 = sys.version_info[0] >= 3
class TestException(Exception):
pass
def test_c(func=None, error=None):
try:
raise TestException
except TestException:
if func:
func()
print(sys.exc_info()[0] is TestException or sys.exc_info()[0])
print(sys.exc_info()[0] is error or sys.exc_info()[0])
__doc__ = u"""
>>> import sys
>>> if not IS_PY3: sys.exc_clear()
>>> print(sys.exc_info()[0]) # 0
None
>>> exc = test_c()
>>> type(exc) is TestException
True
>>> print(sys.exc_info()[0]) # test_c()
None
"""
import sys
IS_PY3 = sys.version_info[0] >= 3
class TestException(Exception):
pass
def test_c():
try:
raise TestException
except TestException, e:
return e
...@@ -2,23 +2,23 @@ __doc__ = u""" ...@@ -2,23 +2,23 @@ __doc__ = u"""
>>> b(1,2,3) >>> b(1,2,3)
>>> b(1,2,3,4) >>> b(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (4 given) TypeError: b() takes exactly 3 positional arguments (4 given)
>>> c(1,2) >>> c(1,2)
>>> c(1,2,3) >>> c(1,2,3)
>>> c(1,2,3,4) >>> c(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 arguments (4 given) TypeError: c() takes at most 3 positional arguments (4 given)
>>> d(1,2) >>> d(1,2)
>>> d(1,2, c=1) >>> d(1,2, c=1)
>>> d(1,2,3) >>> d(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: d() takes exactly 2 positional arguments (3 given)
>>> d(1,2, d=1) >>> d(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'd' is an invalid keyword argument for this function TypeError: d() got an unexpected keyword argument 'd'
>>> e(1,2) >>> e(1,2)
>>> e(1,2, c=1) >>> e(1,2, c=1)
...@@ -27,20 +27,20 @@ __doc__ = u""" ...@@ -27,20 +27,20 @@ __doc__ = u"""
>>> e(1,2,3) >>> e(1,2,3)
>>> e(1,2,3,4) >>> e(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: e() takes at most 3 positional arguments (4 given)
>>> f(1,2, c=1) >>> f(1,2, c=1)
>>> f(1,2, c=1, d=2) >>> f(1,2, c=1, d=2)
>>> f(1,2,3) >>> f(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: f() takes exactly 2 positional arguments (3 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: f() needs keyword-only argument c
>>> f(1,2, c=1, e=2) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: f() got an unexpected keyword argument 'e'
>>> g(1,2, c=1, f=2) >>> g(1,2, c=1, f=2)
>>> g(1,2, c=1, e=0, f=2, d=11) >>> g(1,2, c=1, e=0, f=2, d=11)
...@@ -48,13 +48,13 @@ __doc__ = u""" ...@@ -48,13 +48,13 @@ __doc__ = u"""
>>> g(1,2,3) >>> g(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: g() takes exactly 2 positional arguments (3 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: g() needs keyword-only argument f
>>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -63,10 +63,10 @@ __doc__ = u""" ...@@ -63,10 +63,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -75,15 +75,21 @@ __doc__ = u""" ...@@ -75,15 +75,21 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
"""
import sys, re >>> l(a=1, b=2)
if sys.version_info >= (2,6): >>> l(a=1, b=2, c=1)
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
>>> l(1,2,3)
Traceback (most recent call last):
TypeError: l() takes exactly 0 positional arguments (3 given)
>>> l(1,2, d=1)
Traceback (most recent call last):
TypeError: l() takes exactly 0 positional arguments (2 given)
"""
def b(a, b, c): def b(a, b, c):
pass pass
...@@ -108,3 +114,6 @@ def h(a, b, *args, c, d = 42, e = 17, f, **kwds): ...@@ -108,3 +114,6 @@ def h(a, b, *args, c, d = 42, e = 17, f, **kwds):
def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds): def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds):
pass pass
def l(*, a, b, c = 88):
pass
__doc__ = u""" __doc__ = u"""
>>> call0ab(b)
Traceback (most recent call last):
TypeError: b() takes exactly 3 positional arguments (2 given)
>>> call0abc(b)
1 2 3
>>> call3(b) >>> call3(b)
1 2 3
>>> call4(b) >>> call4(b)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (4 given) TypeError: b() takes exactly 3 positional arguments (4 given)
>>> call0ab(c)
1 2 1
>>> call0abc(c)
1 2 3
>>> call2(c) >>> call2(c)
1 2 1
>>> call3(c) >>> call3(c)
1 2 3
>>> call4(c) >>> call4(c)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 arguments (4 given) TypeError: c() takes at most 3 positional arguments (4 given)
>>> call0abc(d)
1 2 3
>>> call0ab(d)
1 2 88
>>> call2(d) >>> call2(d)
1 2 88
>>> call2c(d) >>> call2c(d)
1 2 1
>>> call3(d) >>> call3(d)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: d() takes exactly 2 positional arguments (3 given)
>>> call2d(d) >>> call2d(d)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'd' is an invalid keyword argument for this function TypeError: d() got an unexpected keyword argument 'd'
>>> call0abc(e)
1 2 3 []
>>> call2(e) >>> call2(e)
1 2 88 []
>>> call2c(e) >>> call2c(e)
1 2 1 []
>>> call2d(e) >>> call2d(e)
1 2 88 [('d', 1)]
>>> call2cde(e) >>> call2cde(e)
1 2 1 [('d', 2), ('e', 3)]
>>> call3(e) >>> call3(e)
1 2 3 []
>>> call4(e) >>> call4(e)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: e() takes at most 3 positional arguments (4 given)
>>> call0abc(f)
1 2 3 42
>>> call2c(f) >>> call2c(f)
1 2 1 42
>>> call2cd(f) >>> call2cd(f)
1 2 1 2
>>> call3(f) >>> call3(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: f() takes exactly 2 positional arguments (3 given)
>>> call2(f) >>> call2(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: f() needs keyword-only argument c
>>> call2ce(f) >>> call2ce(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: f() got an unexpected keyword argument 'e'
>>> call2cf(g) >>> call2cf(g)
1 2 1 42 17 2 []
>>> call2cefd(g) >>> call2cefd(g)
1 2 1 11 0 2 []
>>> call2cfex(g) >>> call2cfex(g)
1 2 1 42 0 2 [('x', 25)]
>>> call3(g) >>> call3(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 2 positional arguments (3 given) TypeError: g() takes exactly 2 positional arguments (3 given)
>>> call2(g) >>> call2(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> call2c(g) >>> call2c(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: g() needs keyword-only argument f
>>> call2cf(h) >>> call2cf(h)
1 2 1 42 17 2 () []
>>> call2cfe(h) >>> call2cfe(h)
1 2 1 42 3 2 () []
>>> call6cf(h) >>> call6cf(h)
1 2 1 42 17 2 (3, 4, 5, 6) []
>>> call6cfexy(h) >>> call6cfexy(h)
1 2 1 42 3 2 (3, 4, 5, 6) [('x', 25), ('y', 11)]
>>> call3(h) >>> call3(h)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> call3d(h) >>> call3d(h)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> call2cf(k) >>> call2cf(k)
1 2 1 42 17 2 () []
>>> call2cfe(k) >>> call2cfe(k)
1 2 1 42 3 2 () []
>>> call6df(k) >>> call6df(k)
1 2 3 1 17 2 (4, 5, 6) []
>>> call6dfexy(k) >>> call6dfexy(k)
1 2 3 1 3 2 (4, 5, 6) [('x', 25), ('y', 11)]
>>> call3(k) >>> call3(k)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> call2d(k) >>> call2d(k)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
"""
import sys, re >>> call0abc(m)
if sys.version_info >= (2,6): 1 2 3
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__) >>> call2c(m)
1 2 1
>>> call3(m)
Traceback (most recent call last):
TypeError: m() takes at most 2 positional arguments (3 given)
>>> call2(m)
Traceback (most recent call last):
TypeError: m() needs keyword-only argument c
>>> call2cd(m)
Traceback (most recent call last):
TypeError: m() got an unexpected keyword argument 'd'
"""
# the calls: # the calls:
def call0ab(f):
f(a=1,b=2)
def call0abc(f):
f(a=1,b=2,c=3)
def call2(f): def call2(f):
f(1,2) f(1,2)
...@@ -132,6 +189,10 @@ def call2cefd(f): ...@@ -132,6 +189,10 @@ def call2cefd(f):
def call2cfex(f): def call2cfex(f):
f(1,2, c=1, f=2, e=0, x=25) f(1,2, c=1, f=2, e=0, x=25)
def call6argscfexy(f):
args = (1,2,3,4,5,6)
f(*args, c=1, f=2, e=3, x=25, y=11)
def call6cfexy(f): def call6cfexy(f):
f(1,2,3,4,5,6, c=1, f=2, e=3, x=25, y=11) f(1,2,3,4,5,6, c=1, f=2, e=3, x=25, y=11)
...@@ -141,25 +202,36 @@ def call6dfexy(f): ...@@ -141,25 +202,36 @@ def call6dfexy(f):
# the called functions: # the called functions:
def b(a, b, c): def b(a, b, c):
pass print a,b,c
def c(a, b, c=1): def c(a, b, c=1):
pass print a,b,c
def d(a, b, *, c = 88): def d(a, b, *, c = 88):
pass print a,b,c
def e(a, b, c = 88, **kwds): def e(a, b, c = 88, **kwds):
pass kwlist = list(kwds.items())
kwlist.sort()
print a,b,c, kwlist
def f(a, b, *, c, d = 42): def f(a, b, *, c, d = 42):
pass print a,b,c,d
def g(a, b, *, c, d = 42, e = 17, f, **kwds): def g(a, b, *, c, d = 42, e = 17, f, **kwds):
pass kwlist = list(kwds.items())
kwlist.sort()
print a,b,c,d,e,f, kwlist
def h(a, b, *args, c, d = 42, e = 17, f, **kwds): def h(a, b, *args, c, d = 42, e = 17, f, **kwds):
pass kwlist = list(kwds.items())
kwlist.sort()
print a,b,c,d,e,f, args, kwlist
def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds): def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds):
pass kwlist = list(kwds.items())
kwlist.sort()
print a,b,c,d,e,f, args, kwlist
def m(a, b=1, *, c):
print a,b,c
u"""
>>> smoketest()
[0, 4, 8]
>>> typed()
[A, A, A]
"""
def smoketest():
print [x*2 for x in range(5) if x % 2 == 0]
cdef class A:
def __repr__(self): return "A"
def typed():
cdef A obj
print [obj for obj in [A(), A(), A()]]
\ No newline at end of file
__doc__ = """
>>> D = set_longlong(2**40, 2**50, 2, "yelp")
>>> D[2**40]
'yelp'
>>> D[2**50]
'yelp'
>>> D[2]
'yelp'
"""
ctypedef long long foo
def set_longlong(long long ob, foo x, long y, val):
tank = {}
tank[ob] = val
tank[x] = val
tank[y] = val
return tank
__doc__ = u"""
>>> a
2
"""
a = 0
try:
raise KeyError
except AttributeError:
a = 1
except KeyError:
a = 2
except:
a = 3
...@@ -79,6 +79,30 @@ try: ...@@ -79,6 +79,30 @@ try:
[[0 0 0 0 0] [[0 0 0 0 0]
[0 0 0 0 0]] [0 0 0 0 0]]
Test contiguous access modes:
>>> c_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='C')
>>> f_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='F')
>>> test_c_contig(c_arr)
0 1 2 3
4 5 6 7
8 9 10 11
>>> test_f_contig(f_arr)
0 1 2 3
4 5 6 7
8 9 10 11
>>> test_c_contig(f_arr)
Traceback (most recent call last):
...
ValueError: ndarray is not C contiguous
>>> test_f_contig(c_arr)
Traceback (most recent call last):
...
ValueError: ndarray is not Fortran contiguous
>>> test_c_contig(c_arr[::2,::2])
Traceback (most recent call last):
...
ValueError: ndarray is not C contiguous
>>> test_dtype('b', inc1_byte) >>> test_dtype('b', inc1_byte)
>>> test_dtype('B', inc1_ubyte) >>> test_dtype('B', inc1_ubyte)
>>> test_dtype('h', inc1_short) >>> test_dtype('h', inc1_short)
...@@ -153,6 +177,15 @@ def put_range_long_1d(np.ndarray[long] arr): ...@@ -153,6 +177,15 @@ def put_range_long_1d(np.ndarray[long] arr):
arr[i] = value arr[i] = value
value += 1 value += 1
def test_c_contig(np.ndarray[int, ndim=2, mode='c'] arr):
cdef int i, j
for i in range(arr.shape[0]):
print " ".join([str(arr[i, j]) for j in range(arr.shape[1])])
def test_f_contig(np.ndarray[int, ndim=2, mode='fortran'] arr):
cdef int i, j
for i in range(arr.shape[0]):
print " ".join([str(arr[i, j]) for j in range(arr.shape[1])])
# Exhaustive dtype tests -- increments element [1] by 1 for all dtypes # Exhaustive dtype tests -- increments element [1] by 1 for all dtypes
def inc1_byte(np.ndarray[char] arr): arr[1] += 1 def inc1_byte(np.ndarray[char] arr): arr[1] += 1
......
__doc__ = u""" __doc__ = u"""
>>> x = spam() >>> x = spam()
>>> print(repr(x)) >>> print(repr(x))
b'Ftang\\x00Ftang!' u'Ftang\\x00Ftang!'
""" """
import sys import sys
if sys.version_info[0] < 3: if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u" b'", u" '") __doc__ = __doc__.replace(u" u'", u" '")
cdef extern from "string.h": cdef extern from "string.h":
void memcpy(char *d, char *s, int n) void memcpy(char *d, char *s, int n)
cdef extern from "Python.h": from python_unicode cimport PyUnicode_DecodeUTF8
object PyString_FromStringAndSize(char *s, int len)
def spam(): def spam():
cdef char buf[12] cdef char buf[12]
memcpy(buf, "Ftang\0Ftang!", sizeof(buf)) memcpy(buf, "Ftang\0Ftang!", sizeof(buf))
return PyString_FromStringAndSize(buf, sizeof(buf)) return PyUnicode_DecodeUTF8(buf, sizeof(buf), NULL)
__doc__ = u""" __doc__ = u"""
>>> s = Spam() #doctest: +ELLIPSIS >>> s = Spam()
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (0 given) TypeError: __init__() takes exactly 3 positional arguments (0 given)
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: .*", u"Error: ...", __doc__)
cdef class Spam: cdef class Spam:
def __init__(self, a, b, int c): def __init__(self, a, b, int c):
......
...@@ -4,19 +4,15 @@ __doc__ = u""" ...@@ -4,19 +4,15 @@ __doc__ = u"""
Traceback (most recent call last): Traceback (most recent call last):
TypeError: an integer is required TypeError: an integer is required
>>> fail0(1,2) #doctest: +ELLIPSIS >>> fail0(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 2 arguments (0 given) TypeError: f() takes exactly 2 positional arguments (0 given)
>>> fail1(1,2) #doctest: +ELLIPSIS >>> fail1(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 2 arguments (1 given) TypeError: f() takes exactly 2 positional arguments (1 given)
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: .*exactly.*", u"Error: ...", __doc__)
import sys import sys
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
__doc__ = __doc__.replace(u" b'", u" '") __doc__ = __doc__.replace(u" b'", u" '")
......
__doc__ = u""" __doc__ = u"""
>>> spam(1,2,3) >>> spam(1,2,3)
(1, 2, 3) (1, 2, 3)
>>> spam(1,2) #doctest: +ELLIPSIS >>> spam(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (2 given) TypeError: spam() takes exactly 3 positional arguments (2 given)
>>> spam(1,2,3,4) >>> spam(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (4 given) TypeError: spam() takes exactly 3 positional arguments (4 given)
>>> spam(1,2,3, a=1) #doctest: +ELLIPSIS >>> spam(1,2,3, a=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: spam() got an unexpected keyword argument 'a'
>>> grail(1,2,3) >>> grail(1,2,3)
(1, 2, 3, ()) (1, 2, 3, ())
...@@ -17,23 +17,23 @@ __doc__ = u""" ...@@ -17,23 +17,23 @@ __doc__ = u"""
(1, 2, 3, (4,)) (1, 2, 3, (4,))
>>> grail(1,2,3,4,5,6,7,8,9) >>> grail(1,2,3,4,5,6,7,8,9)
(1, 2, 3, (4, 5, 6, 7, 8, 9)) (1, 2, 3, (4, 5, 6, 7, 8, 9))
>>> grail(1,2) #doctest: +ELLIPSIS >>> grail(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes exactly 3 arguments (2 given) TypeError: grail() takes at least 3 positional arguments (2 given)
>>> grail(1,2,3, a=1) #doctest: +ELLIPSIS >>> grail(1,2,3, a=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: grail() got an unexpected keyword argument 'a'
>>> swallow(1,2,3) >>> swallow(1,2,3)
(1, 2, 3, ()) (1, 2, 3, ())
>>> swallow(1,2,3,4) >>> swallow(1,2,3,4)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 3 positional arguments (4 given) TypeError: swallow() takes exactly 3 positional arguments (4 given)
>>> swallow(1,2,3, a=1, b=2) >>> swallow(1,2,3, a=1, b=2)
(1, 2, 3, (('a', 1), ('b', 2))) (1, 2, 3, (('a', 1), ('b', 2)))
>>> swallow(1,2,3, x=1) #doctest: +ELLIPSIS >>> swallow(1,2,3, x=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: keyword parameter 'x' was given by position and by name TypeError: swallow() got multiple values for keyword argument 'x'
>>> creosote(1,2,3) >>> creosote(1,2,3)
(1, 2, 3, (), ()) (1, 2, 3, (), ())
...@@ -43,9 +43,9 @@ __doc__ = u""" ...@@ -43,9 +43,9 @@ __doc__ = u"""
(1, 2, 3, (), (('a', 1),)) (1, 2, 3, (), (('a', 1),))
>>> creosote(1,2,3,4, a=1, b=2) >>> creosote(1,2,3,4, a=1, b=2)
(1, 2, 3, (4,), (('a', 1), ('b', 2))) (1, 2, 3, (4,), (('a', 1), ('b', 2)))
>>> creosote(1,2,3,4, x=1) #doctest: +ELLIPSIS >>> creosote(1,2,3,4, x=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: keyword parameter 'x' was given by position and by name TypeError: creosote() got multiple values for keyword argument 'x'
>>> onlyt(1) >>> onlyt(1)
(1,) (1,)
...@@ -53,10 +53,10 @@ __doc__ = u""" ...@@ -53,10 +53,10 @@ __doc__ = u"""
(1, 2) (1, 2)
>>> onlyt(a=1) >>> onlyt(a=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: onlyt() got an unexpected keyword argument 'a'
>>> onlyt(1, a=2) >>> onlyt(1, a=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'a' is an invalid keyword argument for this function TypeError: onlyt() got an unexpected keyword argument 'a'
>>> onlyk(a=1) >>> onlyk(a=1)
(('a', 1),) (('a', 1),)
...@@ -64,13 +64,13 @@ __doc__ = u""" ...@@ -64,13 +64,13 @@ __doc__ = u"""
(('a', 1), ('b', 2)) (('a', 1), ('b', 2))
>>> onlyk(1) >>> onlyk(1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (1 given) TypeError: onlyk() takes exactly 0 positional arguments (1 given)
>>> onlyk(1, 2) >>> onlyk(1, 2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (2 given) TypeError: onlyk() takes exactly 0 positional arguments (2 given)
>>> onlyk(1, a=1, b=2) >>> onlyk(1, a=1, b=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: function takes at most 0 positional arguments (1 given) TypeError: onlyk() takes exactly 0 positional arguments (1 given)
>>> tk(a=1) >>> tk(a=1)
(('a', 1),) (('a', 1),)
...@@ -84,14 +84,6 @@ __doc__ = u""" ...@@ -84,14 +84,6 @@ __doc__ = u"""
(1, ('a', 1), ('b', 2)) (1, ('a', 1), ('b', 2))
""" """
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
import sys, re
if sys.version_info >= (2,6):
__doc__ = re.sub(u"(ELLIPSIS[^>]*Error: )[^\n]*\n", u"\\1...\n", __doc__, re.M)
cdef sorteditems(d): cdef sorteditems(d):
l = list(d.items()) l = list(d.items())
l.sort() l.sort()
......
...@@ -62,6 +62,33 @@ __doc__ = u""" ...@@ -62,6 +62,33 @@ __doc__ = u"""
12 12
>>> switch_c(13) >>> switch_c(13)
0 0
>>> switch_or(0)
0
>>> switch_or(1)
1
>>> switch_or(2)
1
>>> switch_or(3)
1
>>> switch_or(4)
0
>>> switch_short(0)
0
>>> switch_short(1)
1
>>> switch_short(2)
2
>>> switch_short(3)
0
>>> switch_off(0)
0
>>> switch_off(1)
1
>>> switch_off(2)
0
""" """
def switch_simple_py(x): def switch_simple_py(x):
...@@ -123,3 +150,26 @@ def switch_c(int x): ...@@ -123,3 +150,26 @@ def switch_c(int x):
else: else:
return 0 return 0
return -1 return -1
def switch_or(int x):
if x == 1 or x == 2 or x == 3:
return 1
else:
return 0
return -1
def switch_short(int x):
if x == 1:
return 1
elif 2 == x:
return 2
else:
return 0
return -1
def switch_off(int x):
if x == 1:
return 1
else:
return 0
return -1
__doc__ = """
>>> test_signed()
3 <type 'int'>
9 <type 'long'>
6 <type 'long'>
12 <type 'long'>
"""
cdef int i = 1
cdef long l = 2
cdef unsigned int ui = 4
cdef unsigned long ul = 8
def test_signed():
print i + l, type(i+l)
print i + ul, type(i+ul)
print ui + l, type(ui+l)
print ui + ul, type(ui+ul)
__doc__ = u"""
>>> class PyTest(object):
... def __private(self): pass
>>> py = PyTest()
>>> '_PyTest__private' in dir(py)
True
>>> '__private' in dir(py)
False
>>> cy = CyTest()
>>> '_PyTest__private' in dir(cy)
True
>>> '__private' in dir(cy)
False
"""
class CyTest(object):
def __private(self): pass
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