Commit 6ed229d1 authored by Robert Bradshaw's avatar Robert Bradshaw

stupid merge

parents f4064312 00dd94db
...@@ -242,9 +242,7 @@ def put_acquire_arg_buffer(entry, code, pos): ...@@ -242,9 +242,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 +272,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, ...@@ -274,8 +272,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))
...@@ -537,12 +534,11 @@ def get_getbuffer_code(dtype, code): ...@@ -537,12 +534,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 +565,9 @@ def buffer_type_checker(dtype, code): ...@@ -569,6 +565,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 +588,12 @@ def use_py2_buffer_functions(env): ...@@ -589,8 +588,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 +609,9 @@ def use_py2_buffer_functions(env): ...@@ -606,7 +609,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 +620,21 @@ def use_py2_buffer_functions(env): ...@@ -615,18 +620,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 +663,20 @@ static void __Pyx_RaiseBufferIndexError(int axis) { ...@@ -655,20 +663,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,41 +685,24 @@ static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) { ...@@ -677,41 +685,24 @@ 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;
break;
case '=':
case '<':
case '>':
case '!':
PyErr_SetString(PyExc_ValueError, "Buffer acquisition error: Only native byte order, size and alignment supported.");
return NULL;
default: default:
return ts; 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 '=':
++ts; break;
case '<':
if (little_endian) ++ts;
else ok = 0;
break;
case '>':
case '!':
if (!little_endian) ++ts;
else ok = 0;
break;
}
if (!ok) {
PyErr_Format(PyExc_ValueError, "Buffer has wrong endianness (rejecting on '%s')", ts);
return NULL;
}
return ts;
}
static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim) { static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Buffer has wrong number of dimensions (expected %d, got %d)", "Buffer has wrong number of dimensions (expected %d, got %d)",
......
...@@ -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),
]) ])
] ]
......
...@@ -428,14 +428,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -428,14 +428,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("")
...@@ -459,6 +460,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -459,6 +460,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")
...@@ -757,10 +762,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -757,10 +762,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))
...@@ -868,7 +871,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -868,7 +871,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:
...@@ -1954,11 +1957,11 @@ builtin_module_name_utility_code = [ ...@@ -1954,11 +1957,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;
...@@ -1983,29 +1986,32 @@ bad: ...@@ -1983,29 +1986,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)) {
...@@ -2022,7 +2028,7 @@ static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, ...@@ -2022,7 +2028,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"
...@@ -95,6 +95,10 @@ exc_lineno_name = pyrex_prefix + "exc_lineno" ...@@ -95,6 +95,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__"
......
...@@ -860,6 +860,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -860,6 +860,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()
...@@ -902,6 +905,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -902,6 +905,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
...@@ -947,12 +953,13 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -947,12 +953,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()
...@@ -965,6 +972,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -965,6 +972,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
...@@ -973,17 +981,27 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -973,17 +981,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:
...@@ -995,7 +1013,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -995,7 +1013,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 */")
...@@ -1011,9 +1028,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1011,9 +1028,6 @@ class FuncDefNode(StatNode, BlockNode):
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_optarg_wrapper_function(env, 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:
...@@ -1044,8 +1058,27 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1044,8 +1058,27 @@ class FuncDefNode(StatNode, BlockNode):
# For Python class methods, create and store function object # For Python class methods, create and store function object
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.
...@@ -1338,17 +1371,6 @@ class DefNode(FuncDefNode): ...@@ -1338,17 +1371,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
...@@ -1469,6 +1491,10 @@ class DefNode(FuncDefNode): ...@@ -1469,6 +1491,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):
...@@ -1554,31 +1580,13 @@ class DefNode(FuncDefNode): ...@@ -1554,31 +1580,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
...@@ -1589,25 +1597,24 @@ class DefNode(FuncDefNode): ...@@ -1589,25 +1597,24 @@ 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 \
or self.starstar_arg is not None or has_kwonly_args or self.starstar_arg is not None or has_kwonly_args
if not self.signature_has_generic_args(): if not self.signature_has_generic_args():
if has_star_or_kw_args: if has_star_or_kw_args:
error(self.pos, "This method cannot have * or keyword arguments") error(self.pos, "This method cannot have * or keyword arguments")
self.generate_argument_conversion_code(code) self.generate_argument_conversion_code(code)
elif not self.signature_has_nongeneric_args(): elif not self.signature_has_nongeneric_args():
# func(*args) or func(**kw) or func(*args, **kw) # func(*args) or func(**kw) or func(*args, **kw)
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
...@@ -1617,44 +1624,37 @@ class DefNode(FuncDefNode): ...@@ -1617,44 +1624,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:
positional_args.append(arg) if arg.kw_only:
kw_only_args.append(arg)
else:
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) error(arg.pos,
else: "Cannot convert Python object argument to type '%s' (when parsing input arguments)"
error(arg.pos, % arg.type)
"Cannot convert Python object argument to type '%s' (when parsing input arguments)"
% 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):
code.put_goto(end_label) if not code.label_used(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:
...@@ -1663,72 +1663,24 @@ class DefNode(FuncDefNode): ...@@ -1663,72 +1663,24 @@ 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): if arg.type.is_pyobject:
# Unpack inplace if it's simple if arg.is_generic:
if not self.num_required_kw_args: item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
min_positional_args = self.num_required_args - self.num_required_kw_args code.putln("%s = %s;" % (arg.entry.cname, item))
max_positional_args = len(positional_args) else:
if len(self.args) > 0 and self.args[0].is_self_arg: func = arg.type.from_py_function
min_positional_args -= 1 if func:
if max_positional_args == min_positional_args: code.putln("%s = %s(%s); %s" % (
count_cond = "likely(PyTuple_GET_SIZE(%s) == %s)" % ( arg.entry.cname,
Naming.args_cname, max_positional_args) func,
item,
code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
else: else:
count_cond = "likely(%s <= PyTuple_GET_SIZE(%s)) && likely(PyTuple_GET_SIZE(%s) <= %s)" % ( error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
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.is_generic:
item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
code.putln("%s = %s;" % (arg.entry.cname, item))
else:
func = arg.type.from_py_function
if func:
code.putln("%s = %s(%s); %s" % (
arg.entry.cname,
func,
item,
code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
else:
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:
...@@ -1737,17 +1689,30 @@ class DefNode(FuncDefNode): ...@@ -1737,17 +1689,30 @@ class DefNode(FuncDefNode):
def generate_arg_decref(self, arg, code): def generate_arg_decref(self, arg, code):
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();" % (
...@@ -1757,7 +1722,6 @@ class DefNode(FuncDefNode): ...@@ -1757,7 +1722,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)
...@@ -1765,78 +1729,221 @@ class DefNode(FuncDefNode): ...@@ -1765,78 +1729,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('}')
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))
handle_error = 0 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('}')
if handle_error: def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
if self.star_arg: has_fixed_positional_count, positional_args,
code.putln("{") kw_only_args, argtuple_error_label, code):
code.put_decref(Naming.args_cname, py_object_type) all_args = tuple(positional_args) + tuple(kw_only_args)
code.put_decref(self.star_arg.entry.cname, py_object_type) max_args = len(all_args)
code.putln(error_return)
code.putln("}") 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)
# 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:
code.putln('default:')
for i in range(max_positional_args-1, -1, -1):
code.put('case %2d: ' % (i+1))
code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
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:
# 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: else:
code.putln(error_return) code.putln('if (values[%d]) kw_args--;' % i);
if arg.kw_only and not arg.default:
def generate_positional_args_check(self, code, nargs): code.putln('else {')
code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % ( code.put('__Pyx_RaiseKeywordRequired("%s", *%s[%d]); ' %(
Naming.args_cname, nargs)) self.name.utf8encode(), Naming.pykwdlist_cname, i))
code.putln("__Pyx_RaiseArgtupleTooLong(%d, PyTuple_GET_SIZE(%s));" % ( code.putln(code.error_goto(self.pos))
nargs, Naming.args_cname)) code.putln('}')
code.putln("return %s;" % self.error_value()) code.putln('}')
code.putln("}")
def generate_keyword_args_check(self, code): code.putln('if (unlikely(kw_args > 0)) {')
code.putln("if (unlikely(%s)) {" % Naming.kwds_cname) # non-positional kw args left in the dict: **kwargs or error
code.putln("if (unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( if self.star_arg:
Naming.kwds_cname, self.name, code.putln("const Py_ssize_t used_pos_args = (PyTuple_GET_SIZE(%s) < %d) ? PyTuple_GET_SIZE(%s) : %d;" % (
bool(self.starstar_arg), self.error_value())) Naming.args_cname, max_positional_args,
code.putln("}") Naming.args_cname, max_positional_args))
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('}')
# convert arg values to their final type and assign them
for i, arg in enumerate(all_args):
if arg.default:
code.putln("if (values[%d]) {" % i)
self.generate_arg_assignment(arg, "values[%d]" % i, code)
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
...@@ -2825,6 +2932,7 @@ class RaiseStatNode(StatNode): ...@@ -2825,6 +2932,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"
...@@ -2879,6 +2987,7 @@ class ReraiseStatNode(StatNode): ...@@ -2879,6 +2987,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"
...@@ -3299,6 +3408,8 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -3299,6 +3408,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:
...@@ -3426,13 +3537,19 @@ class TryExceptStatNode(StatNode): ...@@ -3426,13 +3537,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)
...@@ -3440,35 +3557,61 @@ class TryExceptStatNode(StatNode): ...@@ -3440,35 +3557,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)
...@@ -3536,6 +3679,7 @@ class ExceptClauseNode(Node): ...@@ -3536,6 +3679,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)
...@@ -3668,6 +3812,11 @@ class TryFinallyStatNode(StatNode): ...@@ -3668,6 +3812,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)
...@@ -3678,9 +3827,10 @@ class TryFinallyStatNode(StatNode): ...@@ -3678,9 +3827,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)
...@@ -3720,6 +3870,7 @@ class TryFinallyStatNode(StatNode): ...@@ -3720,6 +3870,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)
...@@ -3728,7 +3879,7 @@ class TryFinallyStatNode(StatNode): ...@@ -3728,7 +3879,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;" % (
...@@ -3741,11 +3892,12 @@ class TryFinallyStatNode(StatNode): ...@@ -3741,11 +3892,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;" % (
...@@ -4180,7 +4332,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { ...@@ -4180,7 +4332,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);
...@@ -4204,7 +4356,7 @@ static void __Pyx_ReRaise(void) { ...@@ -4204,7 +4356,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);
} }
"""] """]
...@@ -4212,9 +4364,12 @@ static void __Pyx_ReRaise(void) { ...@@ -4212,9 +4364,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;
...@@ -4235,59 +4390,80 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed ...@@ -4235,59 +4390,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,
#endif PyString_AS_STRING(kw_name));
PyErr_Format(PyExc_TypeError, error_message, num_expected, num_found); #endif
} }
"""] """]
...@@ -4297,11 +4473,12 @@ static INLINE void __Pyx_RaiseArgtupleTooLong( ...@@ -4297,11 +4473,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)
...@@ -4310,141 +4487,115 @@ static int __Pyx_CheckKeywordStrings( ...@@ -4310,141 +4487,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
if (unlikely(!PyUnicode_Check(key))) {
#endif
PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
return 0;
}
}
if (unlikely(!kw_allowed) && unlikely(key)) {
PyErr_Format(PyExc_TypeError,
#if PY_MAJOR_VERSION < 3
"'%s' is an invalid keyword argument for this function",
PyString_AsString(key));
#else #else
"'%U' is an invalid keyword argument for this function", if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key)))
key);
#endif #endif
return 0; goto invalid_keyword_type;
} }
if ((!kw_allowed) && unlikely(key))
goto invalid_keyword;
return 1; return 1;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError,
"%s() keywords must be strings", function_name);
return 0;
invalid_keyword:
PyErr_Format(PyExc_TypeError,
#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
return 0;
} }
"""] """]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# __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 # Three kinds of errors are checked: 1) non-string keywords, 2)
# failure. # unexpected keywords and 3) overlap with positional arguments.
# #
# Any of *kwds and kwds2 may be 0 (but not kwds). If *kwds == 0, it # If num_posargs is greater 0, it denotes the number of positional
# is not changed. If kwds2 == 0 and *kwds != 0, a new reference to # arguments that were passed and that must therefore not appear
# the same dictionary is passed back in *kwds. # amongst the keywords as well.
# #
# If rqd_kwds is not 0, it is an array of booleans corresponding to # This method does not check for required keyword arguments.
# the names in kwd_list, indicating required keyword arguments. If
# any of these are not present in kwds, an exception is raised.
# #
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,
char *kwd_list[],
PyObject **kwds2,
char rqd_kwds[])
{
PyObject *s = 0, *x = 0, *kwds1 = 0;
int i;
char **p;
if (*kwds) {
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
s = PyString_FromString(*p);
#else
s = PyUnicode_FromString(*p);
#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;
}
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;
}
*kwds = kwds1;
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, PyObject *kwds,
char *kwd_list[], PyObject **argnames[],
char rqd_kwds[]) PyObject *kwds2,
Py_ssize_t num_pos_args,
const char* function_name)
{ {
int i; PyObject *key = 0, *value = 0;
char **p; Py_ssize_t pos = 0;
PyObject*** name;
if (kwds) { while (PyDict_Next(kwds, &pos, &key, &value)) {
for (i = 0, p = kwd_list; *p; i++, p++) #if PY_MAJOR_VERSION < 3
if (rqd_kwds[i] && !PyDict_GetItemString(kwds, *p)) if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
goto missing_kwarg; #else
} if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
else { #endif
for (i = 0, p = kwd_list; *p; i++, p++) goto invalid_keyword_type;
if (rqd_kwds[i]) } else {
goto missing_kwarg; 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
}
if (!*name) {
if (kwds2) {
if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
} else {
goto invalid_keyword;
}
}
}
if (*name && ((name-argnames) < num_pos_args))
goto arg_passed_twice;
}
} }
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;
} }
"""] """]
...@@ -4458,16 +4609,19 @@ static void __Pyx_WriteUnraisable(const char *name); /*proto*/ ...@@ -4458,16 +4609,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);
PyErr_WriteUnraisable(ctx); } else {
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
} }
"""] """]
...@@ -4539,7 +4693,7 @@ static void __Pyx_AddTraceback(const char *funcname) { ...@@ -4539,7 +4693,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*/
...@@ -4563,6 +4717,39 @@ bad: ...@@ -4563,6 +4717,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 = [
...@@ -4657,8 +4844,8 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); ...@@ -4657,8 +4844,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;
...@@ -4687,3 +4874,35 @@ bad: ...@@ -4687,3 +4874,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,
......
...@@ -297,32 +297,37 @@ def p_call(s, function): ...@@ -297,32 +297,37 @@ 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 ('**', ')'):
arg = p_simple_expr(s) if s.sy == '*':
if s.sy == '=': if star_arg:
s.error("only one star-arg parameter allowed",
pos = s.position())
s.next() s.next()
if not arg.is_name: star_arg = p_simple_expr(s)
s.error("Expected an identifier before '='",
pos = arg.pos)
encoded_name = EncodedString(arg.name)
keyword = ExprNodes.IdentifierStringNode(arg.pos,
value = encoded_name)
arg = p_simple_expr(s)
keyword_args.append((keyword, arg))
else: else:
if keyword_args: arg = p_simple_expr(s)
s.error("Non-keyword arg following keyword arg", if s.sy == '=':
pos = arg.pos) s.next()
positional_args.append(arg) if not arg.is_name:
s.error("Expected an identifier before '='",
pos = arg.pos)
encoded_name = EncodedString(arg.name)
keyword = ExprNodes.IdentifierStringNode(arg.pos,
value = encoded_name)
arg = p_simple_expr(s)
keyword_args.append((keyword, arg))
else:
if keyword_args:
s.error("Non-keyword arg following keyword arg",
pos = arg.pos)
if star_arg:
s.error("Non-keyword arg following star-arg",
pos = arg.pos)
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 +1743,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0, ...@@ -1738,7 +1743,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 +1813,7 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -1808,7 +1813,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 +2176,7 @@ def p_def_statement(s, decorators=None): ...@@ -2171,7 +2176,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)
......
...@@ -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,16 +145,17 @@ class SlotDescriptor: ...@@ -143,16 +145,17 @@ class SlotDescriptor:
flag = self.flag flag = self.flag
py3k = self.py3k py3k = self.py3k
py2 = self.py2 py2 = self.py2
if not py3k: if self.ifdef:
code.putln("#if PY_MAJOR_VERSION < 3") code.putln("#if %s" % self.ifdef)
elif not py2: else:
code.putln("#if PY_MAJOR_VERSION >= 3") if not py3k:
if flag: code.putln("#if PY_MAJOR_VERSION < 3")
code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag) elif not py2:
code.putln("#if PY_MAJOR_VERSION >= 3")
if 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")
) )
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
......
...@@ -43,6 +43,7 @@ cdef extern from "numpy/arrayobject.h": ...@@ -43,6 +43,7 @@ cdef extern from "numpy/arrayobject.h":
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")
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)
......
##################################################################### #####################################################################
# #
# 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
...@@ -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,50 +106,77 @@ class TestBuilder(object): ...@@ -106,50 +106,77 @@ 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(
path, workdir, module,
annotate=self.annotate,
cleanup_workdir=self.cleanup_workdir,
cleanup_sharedlibs=self.cleanup_sharedlibs,
cythononly=self.cythononly)
else: else:
test = CythonCompileTestCase( test_class = CythonCompileTestCase
path, workdir, module, for test in self.build_tests(test_class, path, workdir,
expect_errors=expect_errors, module, expect_errors):
annotate=self.annotate, suite.addTest(test)
cleanup_workdir=self.cleanup_workdir,
cleanup_sharedlibs=self.cleanup_sharedlibs,
cythononly=self.cythononly)
suite.addTest(test)
return suite return suite
def build_tests(self, test_class, path, workdir, module, expect_errors):
if expect_errors:
languages = self.languages[:1]
else:
languages = self.languages
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,
annotate=self.annotate,
cleanup_workdir=self.cleanup_workdir,
cleanup_sharedlibs=self.cleanup_sharedlibs,
cython_only=self.cython_only)
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:
continue if rmfile[-2:] in (".c", ".h") or rmfile[-4:] == ".cpp":
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
if self.annotate and rmfile.endswith(".html"): if self.annotate and rmfile.endswith(".html"):
...@@ -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'
"""
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
"""
...@@ -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
# #
...@@ -949,10 +978,6 @@ cdef class MockBuffer: ...@@ -949,10 +978,6 @@ cdef class MockBuffer:
def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags): def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags):
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
...@@ -961,6 +986,7 @@ cdef class MockBuffer: ...@@ -961,6 +986,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 +1026,7 @@ cdef class IntMockBuffer(MockBuffer): ...@@ -1000,7 +1026,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 +1040,7 @@ cdef class UnsignedShortMockBuffer(MockBuffer): ...@@ -1014,7 +1040,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 +1066,7 @@ cdef class ObjectMockBuffer(MockBuffer): ...@@ -1040,7 +1066,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 +1078,10 @@ cdef class ErrorBuffer: ...@@ -1052,10 +1078,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"releasing!"
print u"unlocking!"
else:
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
......
...@@ -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
__doc__ = u"""
>>> a
2
"""
a = 0
try:
raise KeyError
except AttributeError:
a = 1
except KeyError:
a = 2
except:
a = 3
__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__ = 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