diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 2a426fe35a0969b1646c1e853522f5b2f71acc3f..1cf091eac28861aacb350c8917aff8e802e3135f 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -943,6 +943,15 @@ class CCodeWriter(object): def put_finish_refcount_context(self): self.putln("__Pyx_FinishRefcountContext();") + def put_trace_call(self, name, pos): + self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1])); + + def put_trace_exception(self): + self.putln("__Pyx_TraceException();") + + def put_trace_return(self, retvalue_cname): + self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname) + class PyrexCodeWriter(object): # f file output file diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index cb59255e10fdfc4e6ab5124ec7e44adb438d2797..1922db255530e4a1bff3d82aa96c0886484c7d40 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2578,6 +2578,9 @@ class GeneralCallNode(CallNode): if self.starstar_arg: self.starstar_arg.analyse_types(env) if not self.function.type.is_pyobject: + if self.function.type.is_error: + self.type = error_type + return error_type if hasattr(self.function, 'entry') and not self.function.entry.as_variable: error(self.pos, "Keyword arguments not allowed in cdef functions.") else: @@ -2592,6 +2595,7 @@ class GeneralCallNode(CallNode): self.is_temp = 1 def generate_result_code(self, code): + if self.type.is_error: return if self.keyword_args and self.starstar_arg: code.put_error_if_neg(self.pos, "PyDict_Update(%s, %s)" % ( diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 63b72a3a2b88c2a76d0b51a2fdc0550d38fecca9..9f61513ebe982345efe36ddff71697c36522546b 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -573,6 +573,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln('static PyObject *%s;' % env.module_cname) code.putln('static PyObject *%s;' % Naming.builtins_cname) code.putln('static PyObject *%s;' % Naming.empty_tuple) + code.putln('static PyObject *%s;' % Naming.empty_bytes) if Options.pre_import is not None: code.putln('static PyObject *%s;' % Naming.preimport_cname) code.putln('static int %s;' % Naming.lineno_cname) @@ -588,8 +589,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln('static char %s[] = "%s";' % ( env.doc_cname, escape_byte_string(docstr))) - env.use_utility_code(streq_utility_code) - # XXX this is a mess for utility_code in PyrexTypes.c_int_from_py_function.specialize_list: env.use_utility_code(utility_code) @@ -1556,6 +1555,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname) def generate_import_star(self, env, code): + env.use_utility_code(streq_utility_code) code.putln() code.putln("char* %s_type_names[] = {" % Naming.import_star) for name, entry in env.entries.items(): @@ -1648,6 +1648,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("#endif") code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos))); + code.putln("#if PY_MAJOR_VERSION < 3"); + code.putln("%s = PyString_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); + code.putln("#else"); + code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); + code.putln("#endif"); code.putln("/*--- Library function declarations ---*/") env.generate_library_function_declarations(code) @@ -2475,6 +2480,7 @@ static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL; #define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r) """) + main_method = UtilityCode( impl = """ #if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS)) diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index e12a40480ddd28f0520a75e47630853f55cc330e..b659199a9df2906b3291e479cf83ed737901cabf 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -74,6 +74,7 @@ c_api_tab_cname = pyrex_prefix + "c_api_tab" gilstate_cname = pyrex_prefix + "state" skip_dispatch_cname = pyrex_prefix + "skip_dispatch" empty_tuple = pyrex_prefix + "empty_tuple" +empty_bytes = pyrex_prefix + "empty_bytes" print_function = pyrex_prefix + "print" print_function_kwargs = pyrex_prefix + "print_kwargs" cleanup_cname = pyrex_prefix + "module_cleanup" @@ -83,6 +84,8 @@ import_star = pyrex_prefix + "import_star" import_star_set = pyrex_prefix + "import_star_set" cur_scope_cname = pyrex_prefix + "cur_scope" enc_scope_cname = pyrex_prefix + "enc_scope" +frame_cname = pyrex_prefix + "frame" +frame_code_cname = pyrex_prefix + "frame_code" line_c_macro = "__LINE__" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 4e1c860617e9d9a50bbf17d44993e334a21eeef6..efba286bb1e1cbd9dd9867bdf2ea859e6d2a3bd6 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -801,25 +801,18 @@ class CVarDefNode(StatNode): self.dest_scope = dest_scope base_type = self.base_type.analyse(env) - need_property = False + # If the field is an external typedef, we cannot be sure about the type, + # so do conversion ourself rather than rely on the CPython mechanism (through + # a property; made in AnalyseDeclarationsTransform). if (dest_scope.is_c_class_scope - and self.visibility == 'public' - and base_type.is_pyobject - and (base_type.is_builtin_type or base_type.is_extension_type)): - # If the field is settable and extension type, then the CPython mechanism does - # not do enough type-checking for us. - need_property = True - elif (base_type.is_typedef and base_type.typedef_is_external - and (self.visibility in ('public', 'readonly'))): - # If the field is an external typedef, we cannot be sure about the type, - # so do conversion ourself rather than rely on the CPython mechanism (through - # a property; made in AnalyseDeclarationsTransform). + and self.visibility == 'public' + and base_type.is_pyobject + and (base_type.is_builtin_type or base_type.is_extension_type)): + self.need_properties = [] need_property = True - - if need_property: visibility = 'private' - self.need_properties = [] else: + need_property = False visibility = self.visibility for declarator in self.declarators: @@ -1009,6 +1002,7 @@ class FuncDefNode(StatNode, BlockNode): py_func = None assmt = None needs_closure = False + modifiers = [] def analyse_default_values(self, env): genv = env.global_scope() @@ -1061,6 +1055,15 @@ class FuncDefNode(StatNode, BlockNode): is_getbuffer_slot = (self.entry.name == "__getbuffer__" and self.entry.scope.is_c_class_scope) + + if code.globalstate.directives['profile'] is None: + profile = 'inline' not in self.modifiers and not lenv.nogil + else: + profile = code.globalstate.directives['profile'] + if profile and lenv.nogil: + error(self.pos, "Cannot profile nogil function.") + if profile: + code.globalstate.use_utility_code(trace_utility_code) # Generate C code for header and body of function code.enter_cfunc_scope() @@ -1108,6 +1111,8 @@ class FuncDefNode(StatNode, BlockNode): env.use_utility_code(force_init_threads_utility_code) code.putln("PyGILState_STATE _save = PyGILState_Ensure();") # ----- Automatic lead-ins for certain special functions + if profile: + code.put_trace_call(self.entry.name, self.pos) if not lenv.nogil: code.put_setup_refcount_context(self.entry.name) if is_getbuffer_slot: @@ -1172,6 +1177,9 @@ class FuncDefNode(StatNode, BlockNode): err_val = self.error_value() exc_check = self.caller_will_check_exceptions() if err_val is not None or exc_check: + # TODO: Fix exception tracing (though currently unused by cProfile). + # code.globalstate.use_utility_code(get_exception_tuple_utility_code) + # code.put_trace_exception() code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name) else: warning(self.entry.pos, "Unraisable exception in function '%s'." \ @@ -1201,9 +1209,6 @@ class FuncDefNode(StatNode, BlockNode): # ----- Non-error return cleanup - # If you add anything here, remember to add a condition to the - # if-test above in the error block (so that it can jump past this - # block). code.put_label(code.return_label) for entry in lenv.buffer_entries: if entry.used: @@ -1235,6 +1240,17 @@ class FuncDefNode(StatNode, BlockNode): code.put_finish_refcount_context() + if self.entry.is_special and self.entry.name == "__hash__": + # Returning -1 for __hash__ is supposed to signal an error + # We do as Python instances and coerce -1 into -2. + code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (Naming.retval_cname, Naming.retval_cname)) + + if profile: + if self.return_type.is_pyobject: + code.put_trace_return(Naming.retval_cname) + else: + code.put_trace_return("Py_None") + if acquire_gil: code.putln("PyGILState_Release(_save);") @@ -1334,7 +1350,7 @@ class CFuncDefNode(FuncDefNode): return self.entry.name def analyse_declarations(self, env): - directive_locals = self.directive_locals = env.directives['locals'] + self.directive_locals.update(env.directives['locals']) base_type = self.base_type.analyse(env) # The 2 here is because we need both function and argument names. name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None)) @@ -5414,7 +5430,6 @@ static void __Pyx_AddTraceback(const char *funcname) { PyObject *py_srcfile = 0; PyObject *py_funcname = 0; PyObject *py_globals = 0; - PyObject *empty_string = 0; PyCodeObject *py_code = 0; PyFrameObject *py_frame = 0; @@ -5441,12 +5456,6 @@ static void __Pyx_AddTraceback(const char *funcname) { if (!py_funcname) goto bad; py_globals = PyModule_GetDict(%(GLOBALS)s); if (!py_globals) goto bad; - #if PY_MAJOR_VERSION < 3 - empty_string = PyString_FromStringAndSize("", 0); - #else - empty_string = PyBytes_FromStringAndSize("", 0); - #endif - if (!empty_string) goto bad; py_code = PyCode_New( 0, /*int argcount,*/ #if PY_MAJOR_VERSION >= 3 @@ -5455,7 +5464,7 @@ static void __Pyx_AddTraceback(const char *funcname) { 0, /*int nlocals,*/ 0, /*int stacksize,*/ 0, /*int flags,*/ - empty_string, /*PyObject *code,*/ + %(EMPTY_BYTES)s, /*PyObject *code,*/ %(EMPTY_TUPLE)s, /*PyObject *consts,*/ %(EMPTY_TUPLE)s, /*PyObject *names,*/ %(EMPTY_TUPLE)s, /*PyObject *varnames,*/ @@ -5464,7 +5473,7 @@ static void __Pyx_AddTraceback(const char *funcname) { py_srcfile, /*PyObject *filename,*/ py_funcname, /*PyObject *name,*/ %(LINENO)s, /*int firstlineno,*/ - empty_string /*PyObject *lnotab*/ + %(EMPTY_BYTES)s /*PyObject *lnotab*/ ); if (!py_code) goto bad; py_frame = PyFrame_New( @@ -5479,7 +5488,6 @@ static void __Pyx_AddTraceback(const char *funcname) { bad: Py_XDECREF(py_srcfile); Py_XDECREF(py_funcname); - Py_XDECREF(empty_string); Py_XDECREF(py_code); Py_XDECREF(py_frame); } @@ -5490,6 +5498,7 @@ bad: 'CLINENO': Naming.clineno_cname, 'GLOBALS': Naming.module_cname, 'EMPTY_TUPLE' : Naming.empty_tuple, + 'EMPTY_BYTES' : Naming.empty_bytes, }) restore_exception_utility_code = UtilityCode( @@ -5704,6 +5713,31 @@ bad: #------------------------------------------------------------------------------------ +get_exception_tuple_utility_code = UtilityCode(proto=""" +static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/ +""", +impl = """ +static PyObject *__Pyx_GetExceptionTuple(void) { + PyObject *type = NULL, *value = NULL, *tb = NULL; + if (__Pyx_GetException(&type, &value, &tb) == 0) { + PyObject* exc_info = PyTuple_New(3); + if (exc_info) { + Py_INCREF(type); + Py_INCREF(value); + Py_INCREF(tb); + PyTuple_SET_ITEM(exc_info, 0, type); + PyTuple_SET_ITEM(exc_info, 1, value); + PyTuple_SET_ITEM(exc_info, 2, tb); + return exc_info; + } + } + return NULL; +} +""", +requires=[get_exception_utility_code]) + +#------------------------------------------------------------------------------------ + reset_exception_utility_code = UtilityCode( proto = """ static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ @@ -5749,3 +5783,143 @@ proto=""" """) #------------------------------------------------------------------------------------ + +# Note that cPython ignores PyTrace_EXCEPTION, +# but maybe some other profilers don't. + +trace_utility_code = UtilityCode(proto=""" +#ifndef CYTHON_TRACING +#define CYTHON_TRACING 1 +#endif + +#ifndef CYTHON_TRACING_REUSE_FRAME +#define CYTHON_TRACING_REUSE_FRAME 0 +#endif + +#if CYTHON_TRACING + +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" + +#if CYTHON_TRACING_REUSE_FRAME +#define CYTHON_FRAME_MODIFIER static +#define CYTHON_FRAME_DEL +#else +#define CYTHON_FRAME_MODIFIER +#define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s) +#endif + +#define __Pyx_TraceCall(funcname, srcfile, firstlineno) \\ +static PyCodeObject *%(FRAME_CODE)s = NULL; \\ +CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL; \\ +int __Pyx_use_tracing = 0; \\ +if (PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\ + __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno); \\ +} + +#define __Pyx_TraceException() \\ +if (__Pyx_use_tracing && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\ + PyObject *exc_info = __Pyx_GetExceptionTuple(); \\ + if (exc_info) { \\ + PyThreadState_GET()->c_profilefunc( \\ + PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info); \\ + Py_DECREF(exc_info); \\ + } \\ +} + +#define __Pyx_TraceReturn(result) \\ +if (__Pyx_use_tracing && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) { \\ + PyThreadState_GET()->c_profilefunc( \\ + PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result); \\ + CYTHON_FRAME_DEL; \\ +} + +static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/ +static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/ + +#else +#define __Pyx_TraceCall(funcname, srcfile, firstlineno) +#define __Pyx_TraceException() +#define __Pyx_TraceReturn(result) +#endif /* CYTHON_TRACING */ +""" +% { + "FRAME": Naming.frame_cname, + "FRAME_CODE": Naming.frame_code_cname, +}, +impl = """ + +#if CYTHON_TRACING + +static int __Pyx_TraceSetupAndCall(PyCodeObject** code, + PyFrameObject** frame, + const char *funcname, + const char *srcfile, + int firstlineno) { + if (*frame == NULL || !CYTHON_TRACING_REUSE_FRAME) { + if (*code == NULL) { + *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno); + if (*code == NULL) return 0; + } + *frame = PyFrame_New( + PyThreadState_GET(), /*PyThreadState *tstate*/ + *code, /*PyCodeObject *code*/ + PyModule_GetDict(%(MODULE)s), /*PyObject *globals*/ + 0 /*PyObject *locals*/ + ); + if (*frame == NULL) return 0; + } + else { + (*frame)->f_tstate = PyThreadState_GET(); + } + return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0; +} + +static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) { + PyObject *py_srcfile = 0; + PyObject *py_funcname = 0; + PyCodeObject *py_code = 0; + + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + py_srcfile = PyString_FromString(srcfile); + #else + py_funcname = PyUnicode_FromString(funcname); + py_srcfile = PyUnicode_FromString(srcfile); + #endif + if (!py_funcname | !py_srcfile) goto bad; + + py_code = PyCode_New( + 0, /*int argcount,*/ + #if PY_MAJOR_VERSION >= 3 + 0, /*int kwonlyargcount,*/ + #endif + 0, /*int nlocals,*/ + 0, /*int stacksize,*/ + 0, /*int flags,*/ + %(EMPTY_BYTES)s, /*PyObject *code,*/ + %(EMPTY_TUPLE)s, /*PyObject *consts,*/ + %(EMPTY_TUPLE)s, /*PyObject *names,*/ + %(EMPTY_TUPLE)s, /*PyObject *varnames,*/ + %(EMPTY_TUPLE)s, /*PyObject *freevars,*/ + %(EMPTY_TUPLE)s, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + firstlineno, /*int firstlineno,*/ + %(EMPTY_BYTES)s /*PyObject *lnotab*/ + ); + +bad: + Py_XDECREF(py_srcfile); + Py_XDECREF(py_funcname); + + return py_code; +} + +#endif /* CYTHON_TRACING */ +""" % { + 'EMPTY_TUPLE' : Naming.empty_tuple, + 'EMPTY_BYTES' : Naming.empty_bytes, + "MODULE": Naming.module_cname, +}) diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index a5d70fd58ae302c2c4e6afb1b60cb86b02fede16..60a2cab05c4a6da02c48ed550bad630993ec790e 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -67,10 +67,11 @@ option_defaults = { 'wraparound' : True, 'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this... 'callspec' : "", + 'profile': None, } # Override types possibilities above, if needed -option_types = { } +option_types = { 'profile': bool } for key, val in option_defaults.items(): if key not in option_types: diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 1f3bf7d232383df7f34bbfc54f59195915c84c7f..36200d7414c8ffe72c07f014add32d70f22eb4a8 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -625,12 +625,6 @@ property NAME: ATTR = value """, level='c_class') - readonly_property = TreeFragment(u""" -property NAME: - def __get__(self): - return ATTR - """, level='c_class') - def __call__(self, root): self.env_stack = [root.scope] # needed to determine if a cdef var is declared after it's used. @@ -707,7 +701,7 @@ property NAME: # mechanism for them. stats = [] for entry in node.need_properties: - property = self.create_Property(entry, node.visibility == 'readonly') + property = self.create_Property(entry) property.analyse_declarations(node.dest_scope) self.visit(property) stats.append(property) @@ -715,11 +709,8 @@ property NAME: else: return None - def create_Property(self, entry, readonly): - if readonly: - template = self.readonly_property - else: - template = self.basic_property + def create_Property(self, entry): + template = self.basic_property property = template.substitute({ u"ATTR": AttributeNode(pos=entry.pos, obj=NameNode(pos=entry.pos, name="self"), diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 590a6a9543fc843b5cba16fddfd4fb33f7dc6579..d285aec7d0292fd2c05c6d83cb0bc3590e5dd3da 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -170,6 +170,19 @@ class CTypedefType(BaseType): self.typedef_cname = cname self.typedef_base_type = base_type self.typedef_is_external = is_external + + # Make typecodes in external typedefs use typesize-neutral macros + if is_external: + typecode = None + if base_type.is_int: + if base_type.signed == 0: + typecode = "__Pyx_T_UNSIGNED_INT" + else: + typecode = "__Pyx_T_SIGNED_INT" + elif base_type.is_float and not rank_to_type_name[base_type.rank] == "long double": + typecode = "__Pyx_T_FLOATING" + if typecode: + self.pymemberdef_typecode = "%s(%s)" % (typecode, cname) def resolve(self): return self.typedef_base_type.resolve() @@ -814,13 +827,14 @@ static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o); /* proto */ """, impl=""" static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o) { - if (PyComplex_Check(o)) { + if (PyComplex_CheckExact(o)) { return %(type_name)s_from_parts( (%(real_type)s)((PyComplexObject *)o)->cval.real, (%(real_type)s)((PyComplexObject *)o)->cval.imag); } else { - return %(type_name)s_from_parts(%(type_convert)s(o), 0); + Py_complex cval = PyComplex_AsCComplex(o); + return %(type_name)s_from_parts((%(real_type)s)cval.real, (%(real_type)s)cval.imag); } } """) @@ -1726,6 +1740,40 @@ static INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); #endif #endif + +#if !defined(T_ULONGLONG) +#define __Pyx_T_UNSIGNED_INT(x) \\ + ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \\ + ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \\ + ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \\ + ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : -1)))) +#else +#define __Pyx_T_UNSIGNED_INT(x) \\ + ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \\ + ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \\ + ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \\ + ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : \\ + ((sizeof(x) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))))) +#endif +#if !defined(T_LONGLONG) +#define __Pyx_T_SIGNED_INT(x) \\ + ((sizeof(x) == sizeof(char)) ? T_BYTE : \\ + ((sizeof(x) == sizeof(short)) ? T_SHORT : \\ + ((sizeof(x) == sizeof(int)) ? T_INT : \\ + ((sizeof(x) == sizeof(long)) ? T_LONG : -1)))) +#else +#define __Pyx_T_SIGNED_INT(x) \\ + ((sizeof(x) == sizeof(char)) ? T_BYTE : \\ + ((sizeof(x) == sizeof(short)) ? T_SHORT : \\ + ((sizeof(x) == sizeof(int)) ? T_INT : \\ + ((sizeof(x) == sizeof(long)) ? T_LONG : \\ + ((sizeof(x) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))))) +#endif + +#define __Pyx_T_FLOATING(x) \\ + ((sizeof(x) == sizeof(float)) ? T_FLOAT : \\ + ((sizeof(x) == sizeof(double)) ? T_DOUBLE : -1)) + #if !defined(T_SIZET) #if !defined(T_ULONGLONG) #define T_SIZET \\ diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 2e5415ef04fecd5961b8ae0bbd69ad99f18cf637..8c96a208f205a2f127c0ddd00aba24d36077b1d7 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -1583,8 +1583,14 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/ impl = """ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { /* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */ - /* if (!PyObject_TypeCheck(method, &PyMethodDescr_Type)) { */ - if (__Pyx_StrEq(Py_TYPE(method)->tp_name, "method_descriptor")) { /* cdef classes */ + static PyTypeObject *methoddescr_type = NULL; + if (methoddescr_type == NULL) { + PyObject *meth = __Pyx_GetAttrString((PyObject*)&PyList_Type, "append"); + if (!meth) return NULL; + methoddescr_type = Py_TYPE(meth); + Py_DECREF(meth); + } + if (PyObject_TypeCheck(method, methoddescr_type)) { /* cdef classes */ PyMethodDescrObject *descr = (PyMethodDescrObject *)method; return PyDescr_NewClassMethod(descr->d_type, descr->d_method); } diff --git a/Cython/Includes/__cython__.pxd b/Cython/Includes/__cython__.pxd deleted file mode 100644 index c703e6f2570969a848c0142734ffad27a2a083e3..0000000000000000000000000000000000000000 --- a/Cython/Includes/__cython__.pxd +++ /dev/null @@ -1,28 +0,0 @@ -cdef extern from "Python.h": - ctypedef struct PyObject - - - - ctypedef struct Py_buffer: - void *buf - Py_ssize_t len - int readonly - char *format - int ndim - Py_ssize_t *shape - Py_ssize_t *strides - Py_ssize_t *suboffsets - Py_ssize_t itemsize - void *internal - - - int PyObject_GetBuffer(PyObject* obj, Py_buffer* view, int flags) except -1 - void PyObject_ReleaseBuffer(PyObject* obj, Py_buffer* view) - - void PyErr_Format(int, char*, ...) - - enum: - PyExc_TypeError - -# int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, -# int flags) diff --git a/Cython/Includes/numpy.pxd b/Cython/Includes/numpy.pxd index 932a7433a100d60365a2fbaa0246e9044df6773b..3fb343d8dafa7d2f134e2e2023d3a39ca1ae8157 100644 --- a/Cython/Includes/numpy.pxd +++ b/Cython/Includes/numpy.pxd @@ -1,18 +1,24 @@ # NumPy static imports for Cython # +# If any of the PyArray_* functions are called, import_array must be +# called first. +# # This also defines backwards-compatability buffer acquisition # code for use in Python 2.x (or Python <= 2.5 when NumPy starts # implementing PEP-3118 directly). - - +# # Because of laziness, the format string of the buffer is statically # allocated. Increase the size if this is not enough, or submit a # patch to do this properly. +# +# Author: Dag Sverre Seljebotn +# DEF _buffer_format_string_len = 255 cimport python_buffer as pybuf cimport stdlib +cimport stdio cdef extern from "Python.h": ctypedef int Py_intptr_t @@ -20,43 +26,124 @@ cdef extern from "Python.h": cdef extern from "numpy/arrayobject.h": ctypedef Py_intptr_t npy_intp - cdef enum: - NPY_BOOL, - NPY_BYTE, NPY_UBYTE, - NPY_SHORT, NPY_USHORT, - NPY_INT, NPY_UINT, - NPY_LONG, NPY_ULONG, - NPY_LONGLONG, NPY_ULONGLONG, - NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, - NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, - NPY_OBJECT, - NPY_STRING, NPY_UNICODE, - NPY_VOID, - NPY_NTYPES, - NPY_NOTYPE, - NPY_CHAR, - NPY_USERDEF, - - NPY_C_CONTIGUOUS, + cdef enum NPY_TYPES: + NPY_BOOL + NPY_BYTE + NPY_UBYTE + NPY_SHORT + NPY_USHORT + NPY_INT + NPY_UINT + NPY_LONG + NPY_ULONG + NPY_LONGLONG + NPY_ULONGLONG + NPY_FLOAT + NPY_DOUBLE + NPY_LONGDOUBLE + NPY_CFLOAT + NPY_CDOUBLE + NPY_CLONGDOUBLE + NPY_OBJECT + NPY_STRING + NPY_UNICODE + NPY_VOID + NPY_NTYPES + NPY_NOTYPE + + enum NPY_ORDER: + NPY_ANYORDER + NPY_CORDER + NPY_FORTRANORDER + + enum NPY_CLIPMODE: + NPY_CLIP + NPY_WRAP + NPY_RAISE + + enum NPY_SCALARKIND: + NPY_NOSCALAR, + NPY_BOOL_SCALAR, + NPY_INTPOS_SCALAR, + NPY_INTNEG_SCALAR, + NPY_FLOAT_SCALAR, + NPY_COMPLEX_SCALAR, + NPY_OBJECT_SCALAR + + + enum NPY_SORTKIND: + NPY_QUICKSORT + NPY_HEAPSORT + NPY_MERGESORT + + cdef enum requirements: + NPY_C_CONTIGUOUS NPY_F_CONTIGUOUS + NPY_CONTIGUOUS + NPY_FORTRAN + NPY_OWNDATA + NPY_FORCECAST + NPY_ENSURECOPY + NPY_ENSUREARRAY + NPY_ELEMENTSTRIDES + NPY_ALIGNED + NPY_NOTSWAPPED + NPY_WRITEABLE + NPY_UPDATEIFCOPY + NPY_ARR_HAS_DESCR + + NPY_BEHAVED + NPY_BEHAVED_NS + NPY_CARRAY + NPY_CARRAY_RO + NPY_FARRAY + NPY_FARRAY_RO + NPY_DEFAULT + + NPY_IN_ARRAY + NPY_OUT_ARRAY + NPY_INOUT_ARRAY + NPY_IN_FARRAY + NPY_OUT_FARRAY + NPY_INOUT_FARRAY + + NPY_UPDATE_ALL + cdef enum: + NPY_MAXDIMS + + npy_intp NPY_MAX_ELSIZE + + ctypedef void (*PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *, void *) + ctypedef class numpy.dtype [object PyArray_Descr]: + # Use PyDataType_* macros when possible, however there are no macros + # for accessing some of the fields, so some are defined. Please + # ask on cython-dev if you need more. cdef int type_num cdef int itemsize "elsize" cdef char byteorder cdef object fields cdef object names + ctypedef extern class numpy.flatiter [object PyArrayIterObject]: + # Use through macros + pass + + ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]: + # Use through macros + pass ctypedef class numpy.ndarray [object PyArrayObject]: cdef __cythonbufferdefaults__ = {"mode": "strided"} cdef: + # Only taking a few of the most commonly used and stable fields. + # One should use PyArray_* macros instead to access the C fields. char *data int ndim "nd" npy_intp *shape "dimensions" npy_intp *strides - int flags dtype descr # Note: This syntax (function definition in pxd files) is an @@ -159,19 +246,9 @@ cdef extern from "numpy/arrayobject.h": if sizeof(npy_intp) != sizeof(Py_ssize_t): stdlib.free(info.strides) # info.shape was stored after info.strides in the same block - - cdef void* PyArray_DATA(ndarray arr) - cdef int PyArray_TYPE(ndarray arr) - cdef int PyArray_NDIM(ndarray arr) - cdef int PyArray_ISWRITEABLE(ndarray arr) - cdef npy_intp* PyArray_STRIDES(ndarray arr) - cdef npy_intp* PyArray_DIMS(ndarray arr) - cdef int PyArray_ITEMSIZE(ndarray arr) - cdef int PyArray_CHKFLAGS(ndarray arr, int flags) - cdef int PyArray_HASFIELDS(ndarray arr) - cdef int PyDataType_HASFIELDS(dtype obj) + ctypedef signed char npy_bool ctypedef signed char npy_byte ctypedef signed short npy_short @@ -216,17 +293,353 @@ cdef extern from "numpy/arrayobject.h": ctypedef long double complex npy_complex256 ctypedef struct npy_cfloat: - float real - float imag + double real + double imag ctypedef struct npy_cdouble: - float real - float imag + double real + double imag ctypedef struct npy_clongdouble: - float real - float imag - + double real + double imag + + ctypedef struct PyArray_Dims: + npy_intp *ptr + int len + + void import_array() + + # + # Macros from ndarrayobject.h + # + bint PyArray_CHKFLAGS(ndarray m, int flags) + bint PyArray_ISISCONTIGUOUS(ndarray m) + bint PyArray_ISWRITEABLE(ndarray m) + bint PyArray_ISALIGNED(ndarray m) + + int PyArray_NDIM(ndarray) + bint PyArray_ISONESEGMENT(ndarray) + bint PyArray_ISFORTRAN(ndarray) + int PyArray_FORTRANIF(ndarray) + + void* PyArray_DATA(ndarray) + char* PyArray_BYTES(ndarray) + npy_intp* PyArray_DIMS(ndarray) + npy_intp* PyArray_STRIDES(ndarray) + npy_intp PyArray_DIM(ndarray, size_t) + npy_intp PyArray_STRIDE(ndarray, size_t) + + # object PyArray_BASE(ndarray) wrong refcount semantics + # dtype PyArray_DESCR(ndarray) wrong refcount semantics + int PyArray_FLAGS(ndarray) + npy_intp PyArray_ITEMSIZE(ndarray) + int PyArray_TYPE(ndarray arr) + + object PyArray_GETITEM(ndarray arr, void *itemptr) + int PyArray_SETITEM(ndarray arr, void *itemptr, object obj) + + bint PyTypeNum_ISBOOL(int) + bint PyTypeNum_ISUNSIGNED(int) + bint PyTypeNum_ISSIGNED(int) + bint PyTypeNum_ISINTEGER(int) + bint PyTypeNum_ISFLOAT(int) + bint PyTypeNum_ISNUMBER(int) + bint PyTypeNum_ISSTRING(int) + bint PyTypeNum_ISCOMPLEX(int) + bint PyTypeNum_ISPYTHON(int) + bint PyTypeNum_ISFLEXIBLE(int) + bint PyTypeNum_ISUSERDEF(int) + bint PyTypeNum_ISEXTENDED(int) + bint PyTypeNum_ISOBJECT(int) + + bint PyDataType_ISBOOL(dtype) + bint PyDataType_ISUNSIGNED(dtype) + bint PyDataType_ISSIGNED(dtype) + bint PyDataType_ISINTEGER(dtype) + bint PyDataType_ISFLOAT(dtype) + bint PyDataType_ISNUMBER(dtype) + bint PyDataType_ISSTRING(dtype) + bint PyDataType_ISCOMPLEX(dtype) + bint PyDataType_ISPYTHON(dtype) + bint PyDataType_ISFLEXIBLE(dtype) + bint PyDataType_ISUSERDEF(dtype) + bint PyDataType_ISEXTENDED(dtype) + bint PyDataType_ISOBJECT(dtype) + bint PyDataType_HASFIELDS(dtype) + + bint PyArray_ISBOOL(ndarray) + bint PyArray_ISUNSIGNED(ndarray) + bint PyArray_ISSIGNED(ndarray) + bint PyArray_ISINTEGER(ndarray) + bint PyArray_ISFLOAT(ndarray) + bint PyArray_ISNUMBER(ndarray) + bint PyArray_ISSTRING(ndarray) + bint PyArray_ISCOMPLEX(ndarray) + bint PyArray_ISPYTHON(ndarray) + bint PyArray_ISFLEXIBLE(ndarray) + bint PyArray_ISUSERDEF(ndarray) + bint PyArray_ISEXTENDED(ndarray) + bint PyArray_ISOBJECT(ndarray) + bint PyArray_HASFIELDS(ndarray) + + bint PyArray_ISVARIABLE(ndarray) + + bint PyArray_SAFEALIGNEDCOPY(ndarray) + bint PyArray_ISNBO(ndarray) + bint PyArray_IsNativeByteOrder(ndarray) + bint PyArray_ISNOTSWAPPED(ndarray) + bint PyArray_ISBYTESWAPPED(ndarray) + + bint PyArray_FLAGSWAP(ndarray, int) + + bint PyArray_ISCARRAY(ndarray) + bint PyArray_ISCARRAY_RO(ndarray) + bint PyArray_ISFARRAY(ndarray) + bint PyArray_ISFARRAY_RO(ndarray) + bint PyArray_ISBEHAVED(ndarray) + bint PyArray_ISBEHAVED_RO(ndarray) + + + bint PyDataType_ISNOTSWAPPED(dtype) + bint PyDataType_ISBYTESWAPPED(dtype) + + bint PyArray_DescrCheck(object) + + bint PyArray_Check(object) + bint PyArray_CheckExact(object) + + # Cannot be supported due to out arg: + # bint PyArray_HasArrayInterfaceType(object, dtype, object, object&) + # bint PyArray_HasArrayInterface(op, out) + + + bint PyArray_IsZeroDim(object) + # Cannot be supported due to ## ## in macro: + # bint PyArray_IsScalar(object, verbatim work) + bint PyArray_CheckScalar(object) + bint PyArray_IsPythonNumber(object) + bint PyArray_IsPythonScalar(object) + bint PyArray_IsAnyScalar(object) + bint PyArray_CheckAnyScalar(object) + ndarray PyArray_GETCONTIGUOUS(ndarray) + bint PyArray_SAMESHAPE(ndarray, ndarray) + npy_intp PyArray_SIZE(ndarray) + npy_intp PyArray_NBYTES(ndarray) + + object PyArray_FROM_O(object) + object PyArray_FROM_OF(object m, int flags) + bint PyArray_FROM_OT(object m, int type) + bint PyArray_FROM_OTF(object m, int type, int flags) + object PyArray_FROMANY(object m, int type, int min, int max, int flags) + bint PyArray_ZEROS(ndarray m, dims, int type, int fortran) + object PyArray_EMPTY(object m, dims, int type, int fortran) + void PyArray_FILLWBYTE(object, int val) + npy_intp PyArray_REFCOUNT(object) + object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth) + unsigned char PyArray_EquivArrTypes(ndarray a1, ndarray a2) + bint PyArray_EquivByteorders(int b1, int b2) + object PyArray_SimpleNew(int nd, npy_intp* dims, int typenum) + object PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data) + #object PyArray_SimpleNewFromDescr(int nd, npy_intp* dims, dtype descr) + object PyArray_ToScalar(void* data, ndarray arr) + + void* PyArray_GETPTR1(ndarray m, npy_intp i) + void* PyArray_GETPTR2(ndarray m, npy_intp i, npy_intp j) + void* PyArray_GETPTR3(ndarray m, npy_intp i, npy_intp j, npy_intp k) + void* PyArray_GETPTR4(ndarray m, npy_intp i, npy_intp j, npy_intp k, npy_intp l) + + void PyArray_XDECREF_ERR(ndarray) + # Cannot be supported due to out arg + # void PyArray_DESCR_REPLACE(descr) + + + object PyArray_Copy(ndarray) + object PyArray_FromObject(object op, int type, int min_depth, int max_depth) + object PyArray_ContiguousFromObject(object op, int type, int min_depth, int max_depth) + object PyArray_CopyFromObject(object op, int type, int min_depth, int max_depth) + + object PyArray_Cast(ndarray mp, int type_num) + object PyArray_Take(ndarray ap, object items, int axis) + object PyArray_Put(ndarray ap, object items, object values) + + # Functions from __multiarray_api.h + + # Functions taking dtype and returning object/ndarray are disabled + # for now as they steal dtype references. I'm conservative and disable + # more than is probably needed until it can be checked further. + int PyArray_SetNumericOps (object) + object PyArray_GetNumericOps () + int PyArray_INCREF (ndarray) + int PyArray_XDECREF (ndarray) + void PyArray_SetStringFunction (object, int) + dtype PyArray_DescrFromType (int) + object PyArray_TypeObjectFromType (int) + char * PyArray_Zero (ndarray) + char * PyArray_One (ndarray) + #object PyArray_CastToType (ndarray, dtype, int) + int PyArray_CastTo (ndarray, ndarray) + int PyArray_CastAnyTo (ndarray, ndarray) + int PyArray_CanCastSafely (int, int) + npy_bool PyArray_CanCastTo (dtype, dtype) + int PyArray_ObjectType (object, int) + dtype PyArray_DescrFromObject (object, dtype) + #ndarray* PyArray_ConvertToCommonType (object, int *) + dtype PyArray_DescrFromScalar (object) + dtype PyArray_DescrFromTypeObject (object) + npy_intp PyArray_Size (object) + #object PyArray_Scalar (void *, dtype, object) + #object PyArray_FromScalar (object, dtype) + void PyArray_ScalarAsCtype (object, void *) + #int PyArray_CastScalarToCtype (object, void *, dtype) + #int PyArray_CastScalarDirect (object, dtype, void *, int) + object PyArray_ScalarFromObject (object) + #PyArray_VectorUnaryFunc * PyArray_GetCastFunc (dtype, int) + object PyArray_FromDims (int, int *, int) + #object PyArray_FromDimsAndDataAndDescr (int, int *, dtype, char *) + #object PyArray_FromAny (object, dtype, int, int, int, object) + object PyArray_EnsureArray (object) + object PyArray_EnsureAnyArray (object) + #object PyArray_FromFile (stdio.FILE *, dtype, npy_intp, char *) + #object PyArray_FromString (char *, npy_intp, dtype, npy_intp, char *) + #object PyArray_FromBuffer (object, dtype, npy_intp, npy_intp) + #object PyArray_FromIter (object, dtype, npy_intp) + object PyArray_Return (ndarray) + #object PyArray_GetField (ndarray, dtype, int) + #int PyArray_SetField (ndarray, dtype, int, object) + object PyArray_Byteswap (ndarray, npy_bool) + object PyArray_Resize (ndarray, PyArray_Dims *, int, NPY_ORDER) + int PyArray_MoveInto (ndarray, ndarray) + int PyArray_CopyInto (ndarray, ndarray) + int PyArray_CopyAnyInto (ndarray, ndarray) + int PyArray_CopyObject (ndarray, object) + object PyArray_NewCopy (ndarray, NPY_ORDER) + object PyArray_ToList (ndarray) + object PyArray_ToString (ndarray, NPY_ORDER) + int PyArray_ToFile (ndarray, stdio.FILE *, char *, char *) + int PyArray_Dump (object, object, int) + object PyArray_Dumps (object, int) + int PyArray_ValidType (int) + void PyArray_UpdateFlags (ndarray, int) + object PyArray_New (type, int, npy_intp *, int, npy_intp *, void *, int, int, object) + #object PyArray_NewFromDescr (type, dtype, int, npy_intp *, npy_intp *, void *, int, object) + #dtype PyArray_DescrNew (dtype) + dtype PyArray_DescrNewFromType (int) + double PyArray_GetPriority (object, double) + object PyArray_IterNew (object) + object PyArray_MultiIterNew (int, ...) + int PyArray_PyIntAsInt (object) + npy_intp PyArray_PyIntAsIntp (object) + int PyArray_Broadcast (broadcast) + void PyArray_FillObjectArray (ndarray, object) + int PyArray_FillWithScalar (ndarray, object) + npy_bool PyArray_CheckStrides (int, int, npy_intp, npy_intp, npy_intp *, npy_intp *) + dtype PyArray_DescrNewByteorder (dtype, char) + object PyArray_IterAllButAxis (object, int *) + #object PyArray_CheckFromAny (object, dtype, int, int, int, object) + #object PyArray_FromArray (ndarray, dtype, int) + object PyArray_FromInterface (object) + object PyArray_FromStructInterface (object) + #object PyArray_FromArrayAttr (object, dtype, object) + #NPY_SCALARKIND PyArray_ScalarKind (int, ndarray*) + int PyArray_CanCoerceScalar (int, int, NPY_SCALARKIND) + object PyArray_NewFlagsObject (object) + npy_bool PyArray_CanCastScalar (type, type) + #int PyArray_CompareUCS4 (npy_ucs4 *, npy_ucs4 *, register size_t) + int PyArray_RemoveSmallest (broadcast) + int PyArray_ElementStrides (object) + void PyArray_Item_INCREF (char *, dtype) + void PyArray_Item_XDECREF (char *, dtype) + object PyArray_FieldNames (object) + object PyArray_Transpose (ndarray, PyArray_Dims *) + object PyArray_TakeFrom (ndarray, object, int, ndarray, NPY_CLIPMODE) + object PyArray_PutTo (ndarray, object, object, NPY_CLIPMODE) + object PyArray_PutMask (ndarray, object, object) + object PyArray_Repeat (ndarray, object, int) + object PyArray_Choose (ndarray, object, ndarray, NPY_CLIPMODE) + int PyArray_Sort (ndarray, int, NPY_SORTKIND) + object PyArray_ArgSort (ndarray, int, NPY_SORTKIND) + object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE) + object PyArray_ArgMax (ndarray, int, ndarray) + object PyArray_ArgMin (ndarray, int, ndarray) + object PyArray_Reshape (ndarray, object) + object PyArray_Newshape (ndarray, PyArray_Dims *, NPY_ORDER) + object PyArray_Squeeze (ndarray) + #object PyArray_View (ndarray, dtype, type) + object PyArray_SwapAxes (ndarray, int, int) + object PyArray_Max (ndarray, int, ndarray) + object PyArray_Min (ndarray, int, ndarray) + object PyArray_Ptp (ndarray, int, ndarray) + object PyArray_Mean (ndarray, int, int, ndarray) + object PyArray_Trace (ndarray, int, int, int, int, ndarray) + object PyArray_Diagonal (ndarray, int, int, int) + object PyArray_Clip (ndarray, object, object, ndarray) + object PyArray_Conjugate (ndarray, ndarray) + object PyArray_Nonzero (ndarray) + object PyArray_Std (ndarray, int, int, ndarray, int) + object PyArray_Sum (ndarray, int, int, ndarray) + object PyArray_CumSum (ndarray, int, int, ndarray) + object PyArray_Prod (ndarray, int, int, ndarray) + object PyArray_CumProd (ndarray, int, int, ndarray) + object PyArray_All (ndarray, int, ndarray) + object PyArray_Any (ndarray, int, ndarray) + object PyArray_Compress (ndarray, object, int, ndarray) + object PyArray_Flatten (ndarray, NPY_ORDER) + object PyArray_Ravel (ndarray, NPY_ORDER) + npy_intp PyArray_MultiplyList (npy_intp *, int) + int PyArray_MultiplyIntList (int *, int) + void * PyArray_GetPtr (ndarray, npy_intp*) + int PyArray_CompareLists (npy_intp *, npy_intp *, int) + #int PyArray_AsCArray (object*, void *, npy_intp *, int, dtype) + #int PyArray_As1D (object*, char **, int *, int) + #int PyArray_As2D (object*, char ***, int *, int *, int) + int PyArray_Free (object, void *) + #int PyArray_Converter (object, object*) + int PyArray_IntpFromSequence (object, npy_intp *, int) + object PyArray_Concatenate (object, int) + object PyArray_InnerProduct (object, object) + object PyArray_MatrixProduct (object, object) + object PyArray_CopyAndTranspose (object) + object PyArray_Correlate (object, object, int) + int PyArray_TypestrConvert (int, int) + #int PyArray_DescrConverter (object, dtype*) + #int PyArray_DescrConverter2 (object, dtype*) + int PyArray_IntpConverter (object, PyArray_Dims *) + #int PyArray_BufferConverter (object, chunk) + int PyArray_AxisConverter (object, int *) + int PyArray_BoolConverter (object, npy_bool *) + int PyArray_ByteorderConverter (object, char *) + int PyArray_OrderConverter (object, NPY_ORDER *) + unsigned char PyArray_EquivTypes (dtype, dtype) + #object PyArray_Zeros (int, npy_intp *, dtype, int) + #object PyArray_Empty (int, npy_intp *, dtype, int) + object PyArray_Where (object, object, object) + object PyArray_Arange (double, double, double, int) + #object PyArray_ArangeObj (object, object, object, dtype) + int PyArray_SortkindConverter (object, NPY_SORTKIND *) + object PyArray_LexSort (object, int) + object PyArray_Round (ndarray, int, ndarray) + unsigned char PyArray_EquivTypenums (int, int) + int PyArray_RegisterDataType (dtype) + int PyArray_RegisterCastFunc (dtype, int, PyArray_VectorUnaryFunc *) + int PyArray_RegisterCanCast (dtype, int, NPY_SCALARKIND) + #void PyArray_InitArrFuncs (PyArray_ArrFuncs *) + object PyArray_IntTupleFromIntp (int, npy_intp *) + int PyArray_TypeNumFromName (char *) + int PyArray_ClipmodeConverter (object, NPY_CLIPMODE *) + #int PyArray_OutputConverter (object, ndarray*) + object PyArray_BroadcastToShape (object, npy_intp *, int) + void _PyArray_SigintHandler (int) + void* _PyArray_GetSigintBuf () + #int PyArray_DescrAlignConverter (object, dtype*) + #int PyArray_DescrAlignConverter2 (object, dtype*) + int PyArray_SearchsideConverter (object, void *) + object PyArray_CheckAxis (ndarray, int *, int) + npy_intp PyArray_OverflowMultiplyList (npy_intp *, int) + int PyArray_CompareString (char *, char *, size_t) + + + # Typedefs that matches the runtime dtype objects in # the numpy module. @@ -252,8 +665,8 @@ ctypedef npy_float64 float64_t #ctypedef npy_float80 float80_t #ctypedef npy_float128 float128_t -ctypedef npy_complex64 complex64_t -ctypedef npy_complex128 complex128_t +ctypedef float complex complex64_t +ctypedef double complex complex128_t # The int types are mapped a bit surprising -- # numpy.int corresponds to 'l' and numpy.long to 'q' diff --git a/Cython/Includes/python_version.pxd b/Cython/Includes/python_version.pxd index 0e839704887884ae4c2157af786904ab194df210..e5aee0fb5e6c8c7d0acfffb459a0173fe3711f14 100644 --- a/Cython/Includes/python_version.pxd +++ b/Cython/Includes/python_version.pxd @@ -28,5 +28,5 @@ cdef extern from *: # 0xC (release candidate) # 0xF (final) - char[] PY_VERSION - char[] PY_PATCHLEVEL_REVISION + char PY_VERSION[] + char PY_PATCHLEVEL_REVISION[] diff --git a/Demos/freeze/Makefile b/Demos/freeze/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dd511e084fa630f089f419da150fc1bb0423f3ed --- /dev/null +++ b/Demos/freeze/Makefile @@ -0,0 +1,33 @@ +CC = gcc +CYTHON = ./../bin/cython +CYTHON_FREEZE = ../../bin/cython_freeze.py + +CFLAGS = -fPIC -g -O2 -Wall -Wextra +CPPFLAGS = -I /usr/include/python2.6 +LDFLAGS = -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions +LDLIBS = /usr/lib/python2.6/config/libpython2.6.a \ + -lm -ldl -pthread -lutil -lz + + +# Name of executable +TARGET = nCr + +# List of Cython source files, with main module first. +CYTHON_SOURCE = combinatorics.pyx cmath.pyx + + +all : $(TARGET) + +$(TARGET) : $(TARGET).o $(CYTHON_SOURCE:.pyx=.o) + +$(TARGET).c : + $(CYTHON_FREEZE) $(CYTHON_SOURCE:.pyx=) > $@ + +%.c : %.pyx + $(CYTHON) $(CYTHONFLAGS) $^ + +clean: + $(RM) *.o *.c $(TARGET) + +.PHONY: clean +.SECONDARY: $(CYTHON_SOURCE:.pyx=.c) diff --git a/Demos/freeze/README.rst b/Demos/freeze/README.rst new file mode 100644 index 0000000000000000000000000000000000000000..cc81722f5a8971258d28ce4a252d559983a759e9 --- /dev/null +++ b/Demos/freeze/README.rst @@ -0,0 +1,82 @@ +NAME +==== + +cython_freeze.py - create a C file for embedding Cython modules + + +SYNOPSIS +======== + +cython_freeze.py module [...] + + +DESCRIPTION +=========== + +**cython_freeze.py** generates a C source file to embed a Python interpreter +with one or more Cython modules built in. This allows one to create a single +executable from Cython code, without having to have separate shared objects +for each Cython module. + +A major advantage of this approach is that it allows debuging with gprof(1), +which does not work with shared objects. + +Note that this method differs from ``cython --embed``. The ``--embed`` options +modifies the resulting C source file to include a ``main()`` function, so it +can only be used on a single Cython module. The advantage ``--embed`` is +simplicity. This module, on the other hand, can be used with multiple +modules, but it requires another C source file to be created. + + +EXAMPLE +======= + +In the example directory, there exist two Cython modules: + +cmath.pyx + A module that interfaces with the -lm library. + +combinatorics.pyx + A module that implements n-choose-r using cmath. + +Both modules have the Python idiom ``if __name__ == "__main__"``, which only +execute if that module is the "main" module. If run as main, cmath prints the +factorial of the argument, while combinatorics prints n-choose-r. + +The provided Makefile creates an executable, *nCr*, using combinatorics as the +"main" module. It basically performs the following (ignoring the compiler +flags):: + + $ cython_freeze.py combintorics cmath > nCr.c + $ cython combinatorics.pyx + $ cython cmath.pyx + $ gcc nCr.c -o nCr.o + $ gcc combinatorics.c -o combinatorics.o + $ gcc cmath.c -o cmath.o + $ gcc nCr.o combinatorics.o cmath.o -o nCr + +Because the combinatorics module was listed first, its ``__name__`` is set +to ``"__main__"``, while cmath's is set to ``"cmath"``. The executable now +contains a Python interpreter and both Cython modules. :: + + $ ./nCr + USAGE: ./nCr n r + Prints n-choose-r. + $ ./nCr 15812351235 12 + 5.10028093999e+113 + + + + +PREREQUISITES +============= + +Cython 0.11.2 (or newer, assuming the API does not change) + + +SEE ALSO +======== + +* `Python <http://www.python.org>`_ +* `Cython <http://www.cython.org>`_ +* `freeze.py <http://wiki.python.org/moin/Freeze>`_ diff --git a/Demos/freeze/cmath.pyx b/Demos/freeze/cmath.pyx new file mode 100644 index 0000000000000000000000000000000000000000..cc3f0521ed9a64494798c7f13bfbda00c4055998 --- /dev/null +++ b/Demos/freeze/cmath.pyx @@ -0,0 +1,24 @@ +cdef extern from "math.h": + double c_lgamma "lgamma" (double) + double c_exp "exp" (double) + +def exp(n): + """Return e**n.""" + return c_exp(n) + +def lfactorial(n): + """Return an estimate of the log factorial of n.""" + return c_lgamma(n+1) + +def factorial(n): + """Return an estimate of the factorial of n.""" + return c_exp( c_lgamma(n+1) ) + + +if __name__ == "__main__": + import sys + if len(sys.argv) != 2: + sys.stderr.write("USAGE: %s n\nPrints n!.\n" % sys.argv[0]) + sys.exit(1) + n = map(float, sys.argv[1:]) + print factorial(n) diff --git a/Demos/freeze/combinatorics.pyx b/Demos/freeze/combinatorics.pyx new file mode 100644 index 0000000000000000000000000000000000000000..f3a23ece55bd606f0f30e08f563b26e6689894c1 --- /dev/null +++ b/Demos/freeze/combinatorics.pyx @@ -0,0 +1,14 @@ +import cmath + +def nCr(n, r): + """Return the number of ways to choose r elements of a set of n.""" + return cmath.exp( cmath.lfactorial(n) - cmath.lfactorial(r) + - cmath.lfactorial(n-r) ) + +if __name__ == "__main__": + import sys + if len(sys.argv) != 3: + sys.stderr.write("USAGE: %s n r\nPrints n-choose-r.\n" % sys.argv[0]) + sys.exit(1) + n, r = map(float, sys.argv[1:]) + print nCr(n, r) diff --git a/Demos/setup.py b/Demos/setup.py index 75b05af0fce37948d547cb1fb88ae7303ba7712c..60cbeb817a1bec070cdafdecae6c1c422e6c5c81 100644 --- a/Demos/setup.py +++ b/Demos/setup.py @@ -4,6 +4,12 @@ from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext +try: + from numpy.distutils.misc_util import get_numpy_include_dirs + numpy_include_dirs = get_numpy_include_dirs() +except: + numpy_include_dirs = [] + ext_modules=[ Extension("primes", ["primes.pyx"]), Extension("spam", ["spam.pyx"]), @@ -11,7 +17,7 @@ ext_modules=[ for file in glob.glob("*.pyx"): if file != "numeric_demo.pyx": - ext_modules.append(Extension(file[:-4], [file])) + ext_modules.append(Extension(file[:-4], [file], include_dirs = numpy_include_dirs)) setup( name = 'Demos', diff --git a/bin/cython_freeze.py b/bin/cython_freeze.py new file mode 100644 index 0000000000000000000000000000000000000000..184c4a89ea406df38a8fc59b2e2158c6c2106999 --- /dev/null +++ b/bin/cython_freeze.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +""" +Create a C file for embedding one or more Cython source files. +Requires Cython 0.11.2 (or perhaps newer). + +See README.rst for more details. +""" + +import sys + +if len(sys.argv) < 2: + print >>sys.stderr, "USAGE: %s module [module ...]" % sys.argv[0] + sys.exit(1) + +def format_modname(name): + if name.endswith('.pyx'): + name = name[:-4] + return name.replace('.','_') + +modules = [format_modname(x) for x in sys.argv[1:]] + +print """ +#include <Python.h> +#include <stdio.h> +#include <stdlib.h> + +#if PY_MAJOR_VERSION < 3 +# define MODINIT(name) init ## name +#else +# define MODINIT(name) PyInit_ ## name +#endif +""" + +for name in modules: + print "PyMODINIT_FUNC MODINIT(%s) (void);" % name + +print """ +static struct _inittab inittab[] = {""" + +for name in modules: + print ' {"%(name)s", MODINIT(%(name)s)},' % {'name' : name} + +print """ {NULL, NULL} +}; + +extern int __pyx_module_is_main_%(main)s; + +#if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS)) +int main(int argc, char** argv) { +#else +int wmain(int argc, wchar_t **argv) { +#endif + int r = 0; + PyObject *m = NULL; + if (PyImport_ExtendInittab(inittab)) { + fprintf(stderr, "No memory\\n"); + exit(1); + } + Py_SetProgramName(argv[0]); + Py_Initialize(); + PySys_SetArgv(argc, argv); + __pyx_module_is_main_%(main)s = 1; + m = PyImport_ImportModule(inittab[0].name); + if (!m) { + r = 1; + PyErr_Print(); /* This exits with the right code if SystemExit. */ + if (Py_FlushLine()); PyErr_Clear(); + } + Py_XDECREF(m); + Py_Finalize(); + return r; +} +""" % {'main' : modules[0]} diff --git a/tests/bugs.txt b/tests/bugs.txt index ce41eb17f4b15d8b255bdbe0f03b17091747cda2..3d934c578270625e6ca9c70fd0b99684180e6aa8 100644 --- a/tests/bugs.txt +++ b/tests/bugs.txt @@ -14,3 +14,6 @@ large_consts_T237 bad_c_struct_T252 missing_baseclass_in_predecl_T262 ifelseexpr_T267 + +# Not yet enabled +profile_test diff --git a/tests/compile/shipped_pxds.pyx b/tests/compile/shipped_pxds.pyx new file mode 100644 index 0000000000000000000000000000000000000000..711484a5619f00191bbf2e4938e7b4c9c0f5240d --- /dev/null +++ b/tests/compile/shipped_pxds.pyx @@ -0,0 +1,30 @@ +cimport python_bool +cimport python_buffer +cimport python_complex +cimport python_dict +cimport python_exc +cimport python_float +cimport python_function +cimport python_instance +cimport python_int +cimport python_iterator +cimport python_list +cimport python_long +cimport python_mapping +cimport python_mem +cimport python_method +cimport python_module +cimport python_number +cimport python_object +cimport python_parse +cimport python +cimport python_ref +cimport python_sequence +cimport python_set +cimport python_string +cimport python_tuple +cimport python_type +cimport python_unicode +cimport python_version +cimport stdio +cimport stdlib diff --git a/tests/errors/callingnonexisting_T307.pyx b/tests/errors/callingnonexisting_T307.pyx new file mode 100644 index 0000000000000000000000000000000000000000..b66f64641111510b066193bf308d6297ec6fcc78 --- /dev/null +++ b/tests/errors/callingnonexisting_T307.pyx @@ -0,0 +1,5 @@ +nonexisting(3, with_kw_arg=4) + +_ERRORS = u""" +1:11: undeclared name not builtin: nonexisting +""" diff --git a/tests/run/delete.pyx b/tests/run/delete.pyx index 961967455340bd9e2aaffa520e8f89fbd1ae5f7b..917df2fcc0ecb6ba3136a3bb3e86f420becc27f7 100644 --- a/tests/run/delete.pyx +++ b/tests/run/delete.pyx @@ -4,6 +4,21 @@ [2, 1] >>> a.g() (False, True) +>>> del_item({1: 'a', 2: 'b'}, 1) +{2: 'b'} +>>> del_item(range(10), 2) +[0, 1, 3, 4, 5, 6, 7, 8, 9] + +>>> del_dict({1: 'a', 2: 'b'}, 1) +{2: 'b'} +>>> del_list(range(5), 3) +[0, 1, 2, 4] +>>> del_int(range(5), 3) +[0, 1, 2, 4] +>>> del_list_int(range(5), 3) +[0, 1, 2, 4] +>>> del_int({-1: 'neg', 1: 'pos'}, -1) +{1: 'pos'} """ class A: @@ -16,3 +31,23 @@ class A: self.a = 3 del self.a return (hasattr(self, u"a"), hasattr(self, u"g")) + +def del_item(L, o): + del L[o] + return L + +def del_dict(dict D, o): + del D[o] + return D + +def del_list(list L, o): + del L[o] + return L + +def del_int(L, int i): + del L[i] + return L + +def del_list_int(L, int i): + del L[i] + return L diff --git a/tests/run/external_defs.h b/tests/run/external_defs.h index a6f22cf088bc504264b5ec33c4d16b686c8cf625..aea5539f8072c0f9d8bd9d718267fded9168903a 100644 --- a/tests/run/external_defs.h +++ b/tests/run/external_defs.h @@ -1,3 +1,24 @@ - +typedef float FloatTypedef; typedef double DoubleTypedef; +typedef long double LongDoubleTypedef; + +typedef char CharTypedef; +typedef short ShortTypedef; +typedef int IntTypedef; +typedef long LongTypedef; +#if defined(T_LONGLONG) +typedef PY_LONG_LONG LongLongTypedef; +#else +typedef long LongLongTypedef; +#endif + +typedef unsigned char UCharTypedef; +typedef unsigned short UShortTypedef; +typedef unsigned int UIntTypedef; +typedef unsigned long ULongTypedef; +#if defined(T_LONGLONG) +typedef unsigned PY_LONG_LONG ULongLongTypedef; +#else +typedef unsigned long ULongLongTypedef; +#endif diff --git a/tests/run/hash_T326.pyx b/tests/run/hash_T326.pyx new file mode 100644 index 0000000000000000000000000000000000000000..bd850e9867df81a0c4cf718e6c5d402c32061343 --- /dev/null +++ b/tests/run/hash_T326.pyx @@ -0,0 +1,29 @@ +__doc__ = u""" + + >>> hash(A(5)) + 5 + >>> hash(A(-1)) + -2 + >>> hash(A(-2)) + -2 + >>> hash(A(100)) + Traceback (most recent call last): + ... + TypeError: That's kind of a round number... + + >>> __hash__(-1) + -1 +""" + +cdef class A: + cdef long a + def __init__(self, a): + self.a = a + def __hash__(self): + if self.a == 100: + raise TypeError, "That's kind of a round number..." + else: + return self.a + +cpdef long __hash__(long x): + return x diff --git a/tests/run/numpy_test.pyx b/tests/run/numpy_test.pyx index a5cf19d0de11747f4b36dd78b1d5d4c39fbf4c60..ec3909c40a5d0f54d1575a7049b25025ab4aab74 100644 --- a/tests/run/numpy_test.pyx +++ b/tests/run/numpy_test.pyx @@ -194,6 +194,11 @@ try: Traceback (most recent call last): ... ValueError: Item size of buffer (1 byte) does not match size of 'int' (4 bytes) + + >>> test_complextypes() + 1,1 + 1,1 + 8,16 """ except: @@ -376,3 +381,15 @@ def test_unpacked_align(np.ndarray[UnpackedStruct] arr): arr[0].a = 22 arr[0].b = 23 return repr(arr).replace('<', '!').replace('>', '!') + +def test_complextypes(): + cdef np.complex64_t x64 = 1, y64 = 1j + cdef np.complex128_t x128 = 1, y128 = 1j + x64 = x64 + y64 + print "%.0f,%.0f" % (x64.real, x64.imag) + x128 = x128 + y128 + print "%.0f,%.0f" % (x128.real, x128.imag) + print "%d,%d" % (sizeof(x64), sizeof(x128)) + + + diff --git a/tests/run/profile_test.pyx b/tests/run/profile_test.pyx new file mode 100644 index 0000000000000000000000000000000000000000..db433a5e004fbdd5c88c73efa8f20f24962c4af8 --- /dev/null +++ b/tests/run/profile_test.pyx @@ -0,0 +1,60 @@ +__doc__ = u""" + >>> import os, tempfile, cProfile as profile, pstats + >>> statsfile = tempfile.mkstemp()[1] + >>> profile.runctx("test_profile(100)", locals(), globals(), statsfile) + >>> s = pstats.Stats(statsfile) + >>> short_stats = dict([(k[2], v[1]) for k,v in s.stats.items()]) + >>> short_stats['f_def'] + 100 + >>> short_stats['f_cdef'] + 100 + >>> short_stats['f_inline'] + Traceback (most recent call last): + ... + KeyError: 'f_inline' + >>> short_stats['f_inline_prof'] + 100 + >>> short_stats['f_noprof'] + Traceback (most recent call last): + ... + KeyError: 'f_noprof' + >>> short_stats['f_raise'] + 100 + >>> os.unlink(statsfile) +""" + +cimport cython + +def test_profile(long N): + cdef long i, n = 0 + for i from 0 <= i < N: + n += f_def(i) + n += f_cdef(i) + n += f_inline(i) + n += f_inline_prof(i) + n += f_noprof(i) + try: + n += f_raise(i+2) + except RuntimeError: + pass + return n + +def f_def(long a): + return a + +cdef long f_cdef(long a): + return a + +cdef inline long f_inline(long a): + return a + +@cython.profile(True) +cdef inline long f_inline_prof(long a): + return a + +@cython.profile(False) +cdef int f_noprof(long a): + return a + +cdef long f_raise(long) except -2: + raise RuntimeError diff --git a/tests/run/typedfieldbug_T303.pyx b/tests/run/typedfieldbug_T303.pyx index d892b8ec5446473f5294a9ad61a2560aaec0d4c7..14410bd71edb95d0e1a703fb79bb1e30257c4554 100644 --- a/tests/run/typedfieldbug_T303.pyx +++ b/tests/run/typedfieldbug_T303.pyx @@ -1,31 +1,55 @@ """ >>> f() -42.0 42.0 42.0 +42.0 +42.0 +>>> global_vars(12.0) +12.0 12.0 >>> readonly() Traceback (most recent call last): ... -AttributeError: attribute 'var_nf' of 'typedfieldbug_T303.MyClass' objects is not writable +TypeError: readonly attribute +>>> longdouble_access() +Traceback (most recent call last): + ... +SystemError: bad memberdescr type + """ cdef extern from "external_defs.h": ctypedef float DoubleTypedef + ctypedef float LongDoubleTypedef + +cdef public DoubleTypedef global_tdef +cdef public double global_double cdef class MyClass: cdef readonly: - double var_d - DoubleTypedef var_nf - cdef public: - DoubleTypedef var_mutable + double actual_double + DoubleTypedef float_isreally_double + LongDoubleTypedef float_isreally_longdouble + def __init__(self): - self.var_d = 42.0 - self.var_nf = 42.0 - self.var_mutable = 1 + self.actual_double = 42.0 + self.float_isreally_double = 42.0 + self.float_isreally_longdouble = 42.0 + +def global_vars(x): + global global_tdef, global_double + global_tdef = x + global_double = x + print global_tdef, global_double def f(): c = MyClass() - c.var_mutable = 42.0 - print c.var_d, c.var_nf, c.var_mutable + print c.actual_double + print c.float_isreally_double + +def longdouble_access(): + c = MyClass() + print c.float_isreally_longdouble + def readonly(): c = MyClass() - c.var_nf = 3 + c.actual_double = 3 +