Commit 20fe9ab6 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Big merge of -devel

parents 082156ee afb437d5
...@@ -13,3 +13,4 @@ a4abf0156540db4d3ebaa95712b65811c43c5acb 0.11-beta ...@@ -13,3 +13,4 @@ a4abf0156540db4d3ebaa95712b65811c43c5acb 0.11-beta
4497f635d5fdbd38ebb841be4869fbfa2bbfdbb6 0.11.1.alpha 4497f635d5fdbd38ebb841be4869fbfa2bbfdbb6 0.11.1.alpha
7bc36a0f81723117a19f92ffde1676a0884fef65 0.11.1.beta 7bc36a0f81723117a19f92ffde1676a0884fef65 0.11.1.beta
6454db601984145f38e28d34176fca8a3a22329c 0.11.1 6454db601984145f38e28d34176fca8a3a22329c 0.11.1
af6f1bed8cd40a2edefb57d3eacbc9274a8788b4 0.11.2.rc1
This diff is collapsed.
...@@ -50,6 +50,7 @@ builtin_function_table = [ ...@@ -50,6 +50,7 @@ builtin_function_table = [
#('round', "", "", ""), #('round', "", "", ""),
('setattr', "OOO", "r", "PyObject_SetAttr"), ('setattr', "OOO", "r", "PyObject_SetAttr"),
#('sum', "", "", ""), #('sum', "", "", ""),
('type', "O", "O", "PyObject_Type"),
#('unichr', "", "", ""), #('unichr', "", "", ""),
#('unicode', "", "", ""), #('unicode', "", "", ""),
#('vars', "", "", ""), #('vars', "", "", ""),
......
...@@ -153,5 +153,9 @@ def parse_command_line(args): ...@@ -153,5 +153,9 @@ def parse_command_line(args):
sys.exit(1) sys.exit(1)
if len(sources) == 0 and not options.show_version: if len(sources) == 0 and not options.show_version:
bad_usage() bad_usage()
if Options.embed and len(sources) > 1:
sys.stderr.write(
"cython: Only one source file allowed when using -embed\n")
sys.exit(1)
return options, sources return options, sources
This diff is collapsed.
This diff is collapsed.
...@@ -125,6 +125,7 @@ class Context(object): ...@@ -125,6 +125,7 @@ class Context(object):
_check_c_declarations, _check_c_declarations,
AnalyseExpressionsTransform(self), AnalyseExpressionsTransform(self),
OptimizeBuiltinCalls(), OptimizeBuiltinCalls(),
ConstantFolding(),
IterationTransform(), IterationTransform(),
SwitchTransform(), SwitchTransform(),
FinalOptimizePhase(self), FinalOptimizePhase(self),
......
...@@ -100,6 +100,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -100,6 +100,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if h_types or h_vars or h_funcs or h_extension_types: if h_types or h_vars or h_funcs or h_extension_types:
result.h_file = replace_suffix(result.c_file, ".h") result.h_file = replace_suffix(result.c_file, ".h")
h_code = Code.CCodeWriter() h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
if options.generate_pxi: if options.generate_pxi:
result.i_file = replace_suffix(result.c_file, ".pxi") result.i_file = replace_suffix(result.c_file, ".pxi")
i_code = Code.PyrexCodeWriter(result.i_file) i_code = Code.PyrexCodeWriter(result.i_file)
...@@ -161,6 +162,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -161,6 +162,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if api_funcs or has_api_extension_types: if api_funcs or has_api_extension_types:
result.api_file = replace_suffix(result.c_file, "_api.h") result.api_file = replace_suffix(result.c_file, "_api.h")
h_code = Code.CCodeWriter() h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
name = self.api_name(env) name = self.api_name(env)
guard = Naming.api_guard_prefix + name guard = Naming.api_guard_prefix + name
h_code.put_h_guard(guard) h_code.put_h_guard(guard)
...@@ -237,23 +239,31 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -237,23 +239,31 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_c_code(self, env, options, result): def generate_c_code(self, env, options, result):
modules = self.referenced_modules modules = self.referenced_modules
if Options.annotate or options.annotate: if Options.annotate or options.annotate:
code = Annotate.AnnotationCCodeWriter() emit_linenums = False
rootwriter = Annotate.AnnotationCCodeWriter()
else: else:
code = Code.CCodeWriter(emit_linenums=options.emit_linenums) emit_linenums = options.emit_linenums
h_code = code.insertion_point() rootwriter = Code.CCodeWriter(emit_linenums=emit_linenums)
globalstate = Code.GlobalState(rootwriter, emit_linenums)
globalstate.initialize_main_c_code()
h_code = globalstate['h_code']
self.generate_module_preamble(env, modules, h_code) self.generate_module_preamble(env, modules, h_code)
code.globalstate.module_pos = self.pos globalstate.module_pos = self.pos
code.globalstate.directives = self.directives globalstate.directives = self.directives
code.globalstate.use_utility_code(refcount_utility_code) globalstate.use_utility_code(refcount_utility_code)
code = globalstate['before_global_var']
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name) code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("int %s%s = %s;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'), int(Options.embed)))
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of %s */" % env.qualified_name)
code.globalstate.insert_global_var_declarations_into(code) code = globalstate['all_the_rest']
self.generate_cached_builtins_decls(env, code) self.generate_cached_builtins_decls(env, code)
self.body.generate_function_definitions(env, code) self.body.generate_function_definitions(env, code)
...@@ -270,20 +280,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -270,20 +280,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.embed: if Options.embed:
self.generate_main_method(env, code) self.generate_main_method(env, code)
self.generate_filename_table(code) self.generate_filename_table(code)
self.generate_utility_functions(env, code, h_code)
self.generate_declarations_for_modules(env, modules, h_code) self.generate_declarations_for_modules(env, modules, globalstate)
h_code.write('\n') h_code.write('\n')
code.globalstate.close_global_decls() for codetup, name in env.utility_code_list:
globalstate.use_utility_code(codetup, name)
globalstate.finalize_main_c_code()
f = open_new_file(result.c_file) f = open_new_file(result.c_file)
code.copyto(f) rootwriter.copyto(f)
f.close() f.close()
result.c_file_generated = 1 result.c_file_generated = 1
if Options.annotate or options.annotate: if Options.annotate or options.annotate:
self.annotate(code) self.annotate(rootwriter)
code.save_annotation(result.main_source_file, result.c_file) rootwriter.save_annotation(result.main_source_file, result.c_file)
def find_referenced_modules(self, env, module_list, modules_seen): def find_referenced_modules(self, env, module_list, modules_seen):
if env not in modules_seen: if env not in modules_seen:
...@@ -381,18 +392,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -381,18 +392,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_exttype_vtable_struct(entry, code) self.generate_exttype_vtable_struct(entry, code)
self.generate_exttype_vtabptr_declaration(entry, code) self.generate_exttype_vtabptr_declaration(entry, code)
def generate_declarations_for_modules(self, env, modules, code): def generate_declarations_for_modules(self, env, modules, globalstate):
code.putln("") typecode = globalstate['type_declarations']
code.putln("/* Type declarations */") typecode.putln("")
typecode.putln("/* Type declarations */")
vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env) vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env)
self.generate_type_definitions( self.generate_type_definitions(
env, modules, vtab_list, vtabslot_list, code) env, modules, vtab_list, vtabslot_list, typecode)
modulecode = globalstate['module_declarations']
for module in modules: for module in modules:
defined_here = module is env defined_here = module is env
code.putln("/* Module declarations from %s */" % modulecode.putln("/* Module declarations from %s */" %
module.qualified_name.encode("ASCII", "ignore")) module.qualified_name.encode("ASCII", "ignore"))
self.generate_global_declarations(module, code, defined_here) self.generate_global_declarations(module, modulecode, defined_here)
self.generate_cfunction_predeclarations(module, code, defined_here) self.generate_cfunction_predeclarations(module, modulecode, defined_here)
def generate_module_preamble(self, env, cimported_modules, code): def generate_module_preamble(self, env, cimported_modules, code):
code.putln('/* Generated by Cython %s on %s */' % ( code.putln('/* Generated by Cython %s on %s */' % (
...@@ -508,6 +521,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -508,6 +521,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #ifndef __cdecl") code.putln(" #ifndef __cdecl")
code.putln(" #define __cdecl") code.putln(" #define __cdecl")
code.putln(" #endif") code.putln(" #endif")
code.putln(" #ifndef __fastcall")
code.putln(" #define __fastcall")
code.putln(" #endif")
code.putln("#else") code.putln("#else")
code.putln(" #define _USE_MATH_DEFINES") code.putln(" #define _USE_MATH_DEFINES")
code.putln("#endif") code.putln("#endif")
...@@ -534,6 +550,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -534,6 +550,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#include <math.h>") code.putln("#include <math.h>")
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env)) code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code) self.generate_includes(env, cimported_modules, code)
if env.directives['c99_complex']:
code.putln("#ifndef _Complex_I")
code.putln("#include <complex.h>")
code.putln("#endif")
code.putln("#define __PYX_USE_C99_COMPLEX defined(_Complex_I)")
code.putln('') code.putln('')
code.put(Nodes.utility_function_predeclarations) code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations) code.put(PyrexTypes.type_conversion_predeclarations)
...@@ -1805,14 +1826,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1805,14 +1826,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
env.module_cname, env.module_cname,
Naming.builtins_cname, Naming.builtins_cname,
code.error_goto(self.pos))) code.error_goto(self.pos)))
if Options.embed:
__main__name = code.globalstate.get_py_string_const( __main__name = code.globalstate.get_py_string_const(
EncodedString("__main__"), identifier=True) EncodedString("__main__"), identifier=True)
code.putln("if (%s%s) {" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln( code.putln(
'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % ( 'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % (
env.module_cname, env.module_cname,
__main__name.cname, __main__name.cname,
code.error_goto(self.pos))) code.error_goto(self.pos)))
code.putln("}")
if Options.pre_import is not None: if Options.pre_import is not None:
code.putln( code.putln(
'%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % ( '%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % (
...@@ -2040,22 +2064,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2040,22 +2064,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"%s = &%s;" % ( "%s = &%s;" % (
type.typeptr_cname, type.typeobj_cname)) type.typeptr_cname, type.typeobj_cname))
def generate_utility_functions(self, env, code, h_code):
for codetup, name in env.utility_code_list:
code.globalstate.use_utility_code(codetup, name)
code.globalstate.put_utility_code_protos(h_code)
code.putln("")
code.putln("/* Runtime support code */")
code.putln("")
code.putln("static void %s(void) {" % Naming.fileinit_cname)
code.putln("%s = %s;" %
(Naming.filetable_cname, Naming.filenames_cname))
code.putln("}")
code.globalstate.put_utility_code_defs(code)
code.put(PyrexTypes.type_conversion_functions)
code.putln("")
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# Runtime support code # Runtime support code
...@@ -2460,7 +2468,11 @@ static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL; ...@@ -2460,7 +2468,11 @@ static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL;
main_method = UtilityCode( main_method = UtilityCode(
impl = """ impl = """
#if PY_MAJOR_VERSION < 3 || (!defined(WIN32) && !defined(MS_WINDOWS))
int main(int argc, char** argv) { int main(int argc, char** argv) {
#else
int wmain(int argc, wchar_t **argv) {
#endif
int r = 0; int r = 0;
PyObject* m = NULL; PyObject* m = NULL;
Py_SetProgramName(argv[0]); Py_SetProgramName(argv[0]);
......
...@@ -44,6 +44,7 @@ vtabptr_prefix = pyrex_prefix + "vtabptr_" ...@@ -44,6 +44,7 @@ vtabptr_prefix = pyrex_prefix + "vtabptr_"
vtabstruct_prefix = pyrex_prefix + "vtabstruct_" vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
opt_arg_prefix = pyrex_prefix + "opt_args_" opt_arg_prefix = pyrex_prefix + "opt_args_"
convert_func_prefix = pyrex_prefix + "convert_" convert_func_prefix = pyrex_prefix + "convert_"
module_is_main = pyrex_prefix + "module_is_main_"
args_cname = pyrex_prefix + "args" args_cname = pyrex_prefix + "args"
pykwdlist_cname = pyrex_prefix + "pyargnames" pykwdlist_cname = pyrex_prefix + "pyargnames"
......
...@@ -569,6 +569,13 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -569,6 +569,13 @@ class CFuncDeclaratorNode(CDeclaratorNode):
nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable) nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
if self.optional_arg_count: if self.optional_arg_count:
func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type) func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
callspec = env.directives['callspec']
if callspec:
current = func_type.calling_convention
if current and current != callspec:
error(self.pos, "cannot have both '%s' and '%s' "
"calling conventions" % (current, callspec))
func_type.calling_convention = callspec
return self.base.analyse(func_type, env) return self.base.analyse(func_type, env)
...@@ -650,6 +657,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -650,6 +657,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
# is_basic_c_type boolean # is_basic_c_type boolean
# signed boolean # signed boolean
# longness integer # longness integer
# complex boolean
# is_self_arg boolean Is self argument of C method # is_self_arg boolean Is self argument of C method
child_attrs = [] child_attrs = []
...@@ -690,6 +698,11 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -690,6 +698,11 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
self.arg_name = self.name self.arg_name = self.name
else: else:
error(self.pos, "'%s' is not a type identifier" % self.name) error(self.pos, "'%s' is not a type identifier" % self.name)
if self.complex:
if not type.is_numeric or type.is_complex:
error(self.pos, "can only complexify c numeric types")
type = PyrexTypes.CComplexType(type)
type.create_declaration_utility_code(env)
if type: if type:
return type return type
else: else:
...@@ -763,15 +776,26 @@ class CVarDefNode(StatNode): ...@@ -763,15 +776,26 @@ class CVarDefNode(StatNode):
dest_scope = env dest_scope = env
self.dest_scope = dest_scope self.dest_scope = dest_scope
base_type = self.base_type.analyse(env) base_type = self.base_type.analyse(env)
need_property = False
if (dest_scope.is_c_class_scope if (dest_scope.is_c_class_scope
and self.visibility == 'public' and self.visibility == 'public'
and base_type.is_pyobject and base_type.is_pyobject
and (base_type.is_builtin_type or base_type.is_extension_type)): and (base_type.is_builtin_type or base_type.is_extension_type)):
self.need_properties = [] # If the field is settable and extension type, then the CPython mechanism does
# not do enough type-checking for us.
need_property = True 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).
need_property = True
if need_property:
visibility = 'private' visibility = 'private'
self.need_properties = []
else: else:
need_property = False
visibility = self.visibility visibility = self.visibility
for declarator in self.declarators: for declarator in self.declarators:
...@@ -1867,6 +1891,10 @@ class DefNode(FuncDefNode): ...@@ -1867,6 +1891,10 @@ class DefNode(FuncDefNode):
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
for arg in self.args:
if not arg.type.is_pyobject and arg.type.from_py_function is None:
arg.type.create_from_py_utility_code(env)
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")
...@@ -3069,10 +3097,10 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -3069,10 +3097,10 @@ class InPlaceAssignmentNode(AssignmentNode):
if c_op == "//": if c_op == "//":
c_op = "/" c_op = "/"
elif c_op == "**": elif c_op == "**":
if self.lhs.type.is_int and self.rhs.type.is_int:
error(self.pos, "** with two C int types is ambiguous")
else:
error(self.pos, "No C inplace power operator") error(self.pos, "No C inplace power operator")
elif self.lhs.type.is_complex and not code.globalstate.directives['c99_complex']:
error(self.pos, "Inplace operators not implemented for complex types.")
# have to do assignment directly to avoid side-effects # have to do assignment directly to avoid side-effects
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access: if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op) self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
......
...@@ -54,7 +54,7 @@ c_line_in_traceback = 1 ...@@ -54,7 +54,7 @@ c_line_in_traceback = 1
embed = False embed = False
# Declare pragmas # Declare compiler directives
option_defaults = { option_defaults = {
'boundscheck' : True, 'boundscheck' : True,
'nonecheck' : False, 'nonecheck' : False,
...@@ -64,6 +64,9 @@ option_defaults = { ...@@ -64,6 +64,9 @@ option_defaults = {
'cdivision': True, # Will be False in 0.12 'cdivision': True, # Will be False in 0.12
'cdivision_warnings': False, 'cdivision_warnings': False,
'always_allow_keywords': False, 'always_allow_keywords': False,
'wraparound' : True,
'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
'callspec' : "",
} }
# Override types possibilities above, if needed # Override types possibilities above, if needed
...@@ -94,6 +97,11 @@ def parse_option_value(name, value): ...@@ -94,6 +97,11 @@ def parse_option_value(name, value):
if value == "True": return True if value == "True": return True
elif value == "False": return False elif value == "False": return False
else: raise ValueError("%s directive must be set to True or False" % name) else: raise ValueError("%s directive must be set to True or False" % name)
elif type is int:
try:
return int(value)
except ValueError:
raise ValueError("%s directive must be set to an integer" % name)
else: else:
assert False assert False
......
...@@ -435,6 +435,11 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -435,6 +435,11 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
raise PostParseError(dec.function.pos, raise PostParseError(dec.function.pos,
'The %s option takes one compile-time boolean argument' % optname) 'The %s option takes one compile-time boolean argument' % optname)
return (optname, args[0].value) return (optname, args[0].value)
elif optiontype is str:
if kwds is not None or len(args) != 1 or not isinstance(args[0], StringNode):
raise PostParseError(dec.function.pos,
'The %s option takes one compile-time string argument' % optname)
return (optname, args[0].value)
elif optiontype is dict: elif optiontype is dict:
if len(args) != 0: if len(args) != 0:
raise PostParseError(dec.function.pos, raise PostParseError(dec.function.pos,
...@@ -589,62 +594,6 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -589,62 +594,6 @@ class WithTransform(CythonTransform, SkipDeclarations):
return node return node
class ComprehensionTransform(VisitorTransform):
"""Prevent the target of list/set/dict comprehensions from leaking by
moving it into a temp variable. This mimics the behaviour of all
comprehensions in Py3 and of generator expressions in Py2.x.
This must run before the IterationTransform, which might replace
for-loops with while-loops. We only handle for-loops here.
"""
def visit_ModuleNode(self, node):
self.comprehension_targets = {}
self.visitchildren(node)
return node
visit_Node = VisitorTransform.recurse_to_children
def visit_ComprehensionNode(self, node):
if type(node.loop) not in (Nodes.ForInStatNode,
Nodes.ForFromStatNode):
# this should not happen!
self.visitchildren(node)
return node
outer_comprehension_targets = self.comprehension_targets
self.comprehension_targets = outer_comprehension_targets.copy()
# find all NameNodes in the loop target
target_name_collector = NameNodeCollector()
target_name_collector.visit(node.loop.target)
targets = target_name_collector.name_nodes
# create a temp variable for each target name
temps = []
for target in targets:
handle = TempHandle(target.type)
temps.append(handle)
self.comprehension_targets[target.entry.cname] = handle.ref(node.pos)
# replace name references in the loop code by their temp node
self.visitchildren(node, ['loop'])
loop = node.loop
if type(loop) is Nodes.ForFromStatNode and loop.target.type.is_numeric:
loop.loopvar_node = loop.target
node.loop = TempsBlockNode(node.pos, body=node.loop, temps=temps)
self.comprehension_targets = outer_comprehension_targets
return node
def visit_NameNode(self, node):
if node.entry:
replacement = self.comprehension_targets.get(node.entry.cname)
if replacement is not None:
return replacement
return node
class DecoratorTransform(CythonTransform, SkipDeclarations): class DecoratorTransform(CythonTransform, SkipDeclarations):
def visit_DefNode(self, func_node): def visit_DefNode(self, func_node):
...@@ -676,6 +625,12 @@ property NAME: ...@@ -676,6 +625,12 @@ property NAME:
ATTR = value ATTR = value
""", level='c_class') """, level='c_class')
readonly_property = TreeFragment(u"""
property NAME:
def __get__(self):
return ATTR
""", level='c_class')
def __call__(self, root): def __call__(self, root):
self.env_stack = [root.scope] self.env_stack = [root.scope]
# needed to determine if a cdef var is declared after it's used. # needed to determine if a cdef var is declared after it's used.
...@@ -752,7 +707,7 @@ property NAME: ...@@ -752,7 +707,7 @@ property NAME:
# mechanism for them. # mechanism for them.
stats = [] stats = []
for entry in node.need_properties: for entry in node.need_properties:
property = self.create_Property(entry) property = self.create_Property(entry, node.visibility == 'readonly')
property.analyse_declarations(node.dest_scope) property.analyse_declarations(node.dest_scope)
self.visit(property) self.visit(property)
stats.append(property) stats.append(property)
...@@ -760,8 +715,12 @@ property NAME: ...@@ -760,8 +715,12 @@ property NAME:
else: else:
return None return None
def create_Property(self, entry): def create_Property(self, entry, readonly):
property = self.basic_property.substitute({ if readonly:
template = self.readonly_property
else:
template = self.basic_property
property = template.substitute({
u"ATTR": AttributeNode(pos=entry.pos, u"ATTR": AttributeNode(pos=entry.pos,
obj=NameNode(pos=entry.pos, name="self"), obj=NameNode(pos=entry.pos, name="self"),
attribute=entry.name), attribute=entry.name),
......
...@@ -1753,7 +1753,7 @@ def p_calling_convention(s): ...@@ -1753,7 +1753,7 @@ def p_calling_convention(s):
else: else:
return "" return ""
calling_convention_words = ("__stdcall", "__cdecl") calling_convention_words = ("__stdcall", "__cdecl", "__fastcall")
def p_c_complex_base_type(s): def p_c_complex_base_type(s):
# s.sy == '(' # s.sy == '('
...@@ -1770,6 +1770,7 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1770,6 +1770,7 @@ def p_c_simple_base_type(s, self_flag, nonempty):
is_basic = 0 is_basic = 0
signed = 1 signed = 1
longness = 0 longness = 0
complex = 0
module_path = [] module_path = []
pos = s.position() pos = s.position()
if not s.sy == 'IDENT': if not s.sy == 'IDENT':
...@@ -1788,6 +1789,9 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1788,6 +1789,9 @@ def p_c_simple_base_type(s, self_flag, nonempty):
s.next() s.next()
else: else:
name = 'int' name = 'int'
if s.sy == 'IDENT' and s.systring == 'complex':
complex = 1
s.next()
elif looking_at_dotted_name(s): elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position() #print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring name = s.systring
...@@ -1816,7 +1820,8 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1816,7 +1820,8 @@ def p_c_simple_base_type(s, self_flag, nonempty):
type_node = Nodes.CSimpleBaseTypeNode(pos, type_node = Nodes.CSimpleBaseTypeNode(pos,
name = name, module_path = module_path, name = name, module_path = module_path,
is_basic_c_type = is_basic, signed = signed, is_basic_c_type = is_basic, signed = signed,
longness = longness, is_self_arg = self_flag) complex = complex, longness = longness,
is_self_arg = self_flag)
# Treat trailing [] on type as buffer access if it appears in a context # Treat trailing [] on type as buffer access if it appears in a context
...@@ -2561,7 +2566,7 @@ def p_code(s, level=None): ...@@ -2561,7 +2566,7 @@ def p_code(s, level=None):
repr(s.sy), repr(s.systring))) repr(s.sy), repr(s.systring)))
return body return body
COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*cython:\s*([a-z_]+)\s*=(.*)$") COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*cython:\s*(\w+)\s*=(.*)$")
def p_compiler_directive_comments(s): def p_compiler_directive_comments(s):
result = {} result = {}
...@@ -2571,10 +2576,10 @@ def p_compiler_directive_comments(s): ...@@ -2571,10 +2576,10 @@ def p_compiler_directive_comments(s):
name = m.group(1) name = m.group(1)
try: try:
value = Options.parse_option_value(str(name), str(m.group(2).strip())) value = Options.parse_option_value(str(name), str(m.group(2).strip()))
except ValueError, e:
s.error(e.args[0], fatal=False)
if value is not None: # can be False! if value is not None: # can be False!
result[name] = value result[name] = value
except ValueError, e:
s.error(e.args[0], fatal=False)
s.next() s.next()
return result return result
......
This diff is collapsed.
...@@ -335,7 +335,7 @@ class Scope(object): ...@@ -335,7 +335,7 @@ class Scope(object):
cname = name cname = name
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
type = PyrexTypes.CTypedefType(cname, base_type) type = PyrexTypes.CTypedefType(cname, base_type, (visibility == 'extern'))
entry = self.declare_type(name, type, pos, cname, visibility) entry = self.declare_type(name, type, pos, cname, visibility)
type.qualified_name = entry.qualified_name type.qualified_name = entry.qualified_name
return entry return entry
......
...@@ -154,7 +154,14 @@ class SlotDescriptor(object): ...@@ -154,7 +154,14 @@ class SlotDescriptor(object):
code.putln("#if PY_MAJOR_VERSION >= 3") code.putln("#if PY_MAJOR_VERSION >= 3")
if flag: if flag:
code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag) code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag)
if py3k == '<RESERVED>':
code.putln("#if PY_MAJOR_VERSION >= 3")
code.putln("0, /*reserved*/")
code.putln("#else")
code.putln("%s, /*%s*/" % (value, self.slot_name)) code.putln("%s, /*%s*/" % (value, self.slot_name))
if py3k == '<RESERVED>':
code.putln("#endif")
if flag or (not py3k or not py2) or self.ifdef: if flag or (not py3k or not py2) or self.ifdef:
code.putln("#endif") code.putln("#endif")
...@@ -212,9 +219,12 @@ class MethodSlot(SlotDescriptor): ...@@ -212,9 +219,12 @@ class MethodSlot(SlotDescriptor):
def slot_code(self, scope): def slot_code(self, scope):
entry = scope.lookup_here(self.method_name) entry = scope.lookup_here(self.method_name)
if entry: if entry and entry.func_cname:
return entry.func_cname
if self.default is not None:
entry = scope.lookup_here(self.default)
if entry and entry.func_cname:
return entry.func_cname return entry.func_cname
else:
return "0" return "0"
...@@ -557,8 +567,8 @@ PyNumberMethods = ( ...@@ -557,8 +567,8 @@ PyNumberMethods = (
MethodSlot(binaryfunc, "nb_xor", "__xor__"), MethodSlot(binaryfunc, "nb_xor", "__xor__"),
MethodSlot(binaryfunc, "nb_or", "__or__"), MethodSlot(binaryfunc, "nb_or", "__or__"),
EmptySlot("nb_coerce", py3k = False), EmptySlot("nb_coerce", py3k = False),
MethodSlot(unaryfunc, "nb_int", "__int__"), MethodSlot(unaryfunc, "nb_int", "__int__", default="__long__"),
MethodSlot(unaryfunc, "nb_long", "__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", default="__int__", py3k = "<RESERVED>"),
MethodSlot(unaryfunc, "nb_float", "__float__"), MethodSlot(unaryfunc, "nb_float", "__float__"),
MethodSlot(unaryfunc, "nb_oct", "__oct__", py3k = False), MethodSlot(unaryfunc, "nb_oct", "__oct__", py3k = False),
MethodSlot(unaryfunc, "nb_hex", "__hex__", py3k = False), MethodSlot(unaryfunc, "nb_hex", "__hex__", py3k = False),
......
version = '0.11.1' version = '0.11.2.rc1'
# NumPy static imports for Cython
#
# 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.
DEF _buffer_format_string_len = 255
cimport python_buffer as pybuf cimport python_buffer as pybuf
cimport stdlib cimport stdlib
...@@ -29,6 +42,8 @@ cdef extern from "numpy/arrayobject.h": ...@@ -29,6 +42,8 @@ cdef extern from "numpy/arrayobject.h":
ctypedef class numpy.dtype [object PyArray_Descr]: ctypedef class numpy.dtype [object PyArray_Descr]:
cdef int type_num cdef int type_num
cdef int itemsize "elsize"
cdef char byteorder
cdef object fields cdef object fields
cdef object names cdef object names
...@@ -53,6 +68,9 @@ cdef extern from "numpy/arrayobject.h": ...@@ -53,6 +68,9 @@ cdef extern from "numpy/arrayobject.h":
# In particular strided access is always provided regardless # In particular strided access is always provided regardless
# of flags # of flags
cdef int copy_shape, i, ndim cdef int copy_shape, i, ndim
cdef int endian_detector = 1
cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
ndim = PyArray_NDIM(self) ndim = PyArray_NDIM(self)
if sizeof(npy_intp) != sizeof(Py_ssize_t): if sizeof(npy_intp) != sizeof(Py_ssize_t):
...@@ -89,17 +107,10 @@ cdef extern from "numpy/arrayobject.h": ...@@ -89,17 +107,10 @@ cdef extern from "numpy/arrayobject.h":
cdef char* f = NULL cdef char* f = NULL
cdef dtype descr = self.descr cdef dtype descr = self.descr
cdef list stack cdef list stack
cdef int offset
cdef bint hasfields = PyDataType_HASFIELDS(descr) cdef bint hasfields = PyDataType_HASFIELDS(descr)
# Ugly hack warning:
# Cython currently will not support helper functions in
# pxd files -- so we must keep our own, manual stack!
# In addition, avoid allocation of the stack in the common
# case that we are dealing with a single non-nested datatype...
# (this would look much prettier if we could use utility
# functions).
if not hasfields and not copy_shape: if not hasfields and not copy_shape:
# do not call releasebuffer # do not call releasebuffer
info.obj = None info.obj = None
...@@ -109,6 +120,9 @@ cdef extern from "numpy/arrayobject.h": ...@@ -109,6 +120,9 @@ cdef extern from "numpy/arrayobject.h":
if not hasfields: if not hasfields:
t = descr.type_num t = descr.type_num
if ((descr.byteorder == '>' and little_endian) or
(descr.byteorder == '<' and not little_endian)):
raise ValueError("Non-native byte order not supported")
if t == NPY_BYTE: f = "b" if t == NPY_BYTE: f = "b"
elif t == NPY_UBYTE: f = "B" elif t == NPY_UBYTE: f = "B"
elif t == NPY_SHORT: f = "h" elif t == NPY_SHORT: f = "h"
...@@ -131,8 +145,12 @@ cdef extern from "numpy/arrayobject.h": ...@@ -131,8 +145,12 @@ cdef extern from "numpy/arrayobject.h":
info.format = f info.format = f
return return
else: else:
info.format = <char*>stdlib.malloc(255) # static size info.format = <char*>stdlib.malloc(_buffer_format_string_len)
f = _util_dtypestring(descr, info.format, info.format + 255) info.format[0] = '^' # Native data types, manual alignment
offset = 0
f = _util_dtypestring(descr, info.format + 1,
info.format + _buffer_format_string_len,
&offset)
f[0] = 0 # Terminate format string f[0] = 0 # Terminate format string
def __releasebuffer__(ndarray self, Py_buffer* info): def __releasebuffer__(ndarray self, Py_buffer* info):
...@@ -155,53 +173,59 @@ cdef extern from "numpy/arrayobject.h": ...@@ -155,53 +173,59 @@ cdef extern from "numpy/arrayobject.h":
cdef int PyDataType_HASFIELDS(dtype obj) cdef int PyDataType_HASFIELDS(dtype obj)
ctypedef signed int npy_byte ctypedef signed char npy_byte
ctypedef signed int npy_short ctypedef signed short npy_short
ctypedef signed int npy_int ctypedef signed int npy_int
ctypedef signed int npy_long ctypedef signed long npy_long
ctypedef signed int npy_longlong ctypedef signed long long npy_longlong
ctypedef unsigned int npy_ubyte ctypedef unsigned char npy_ubyte
ctypedef unsigned int npy_ushort ctypedef unsigned short npy_ushort
ctypedef unsigned int npy_uint ctypedef unsigned int npy_uint
ctypedef unsigned int npy_ulong ctypedef unsigned long npy_ulong
ctypedef unsigned int npy_ulonglong ctypedef unsigned long long npy_ulonglong
ctypedef float npy_float ctypedef float npy_float
ctypedef float npy_double ctypedef double npy_double
ctypedef float npy_longdouble ctypedef long double npy_longdouble
ctypedef signed int npy_int8 ctypedef signed char npy_int8
ctypedef signed int npy_int16 ctypedef signed short npy_int16
ctypedef signed int npy_int32 ctypedef signed int npy_int32
ctypedef signed int npy_int64 ctypedef signed long long npy_int64
ctypedef signed int npy_int96 ctypedef signed long long npy_int96
ctypedef signed int npy_int128 ctypedef signed long long npy_int128
ctypedef unsigned int npy_uint8 ctypedef unsigned char npy_uint8
ctypedef unsigned int npy_uint16 ctypedef unsigned short npy_uint16
ctypedef unsigned int npy_uint32 ctypedef unsigned int npy_uint32
ctypedef unsigned int npy_uint64 ctypedef unsigned long long npy_uint64
ctypedef unsigned int npy_uint96 ctypedef unsigned long long npy_uint96
ctypedef unsigned int npy_uint128 ctypedef unsigned long long npy_uint128
ctypedef float npy_float32 ctypedef float npy_float32
ctypedef float npy_float64 ctypedef double npy_float64
ctypedef float npy_float80 ctypedef long double npy_float80
ctypedef float npy_float96 ctypedef long double npy_float96
ctypedef float npy_float128 ctypedef long double npy_float128
ctypedef float complex npy_complex64
ctypedef double complex npy_complex128
ctypedef long double complex npy_complex120
ctypedef long double complex npy_complex192
ctypedef long double complex npy_complex256
ctypedef struct npy_cfloat: ctypedef struct npy_cfloat:
float real float real
float imag float imag
ctypedef struct npy_cdouble: ctypedef struct npy_cdouble:
double real float real
double imag float imag
ctypedef struct npy_clongdouble: ctypedef struct npy_clongdouble:
long double real float real
long double imag float imag
# Typedefs that matches the runtime dtype objects in # Typedefs that matches the runtime dtype objects in
# the numpy module. # the numpy module.
...@@ -228,11 +252,15 @@ ctypedef npy_float64 float64_t ...@@ -228,11 +252,15 @@ ctypedef npy_float64 float64_t
#ctypedef npy_float80 float80_t #ctypedef npy_float80 float80_t
#ctypedef npy_float128 float128_t #ctypedef npy_float128 float128_t
ctypedef npy_complex64 complex64_t
ctypedef npy_complex128 complex128_t
# The int types are mapped a bit surprising -- # The int types are mapped a bit surprising --
# numpy.int corresponds to 'l' and numpy.long to 'q' # numpy.int corresponds to 'l' and numpy.long to 'q'
ctypedef npy_long int_t ctypedef npy_long int_t
ctypedef npy_longlong long_t ctypedef npy_longlong long_t
ctypedef npy_ulong uint_t ctypedef npy_ulong uint_t
ctypedef npy_ulonglong ulong_t ctypedef npy_ulonglong ulong_t
...@@ -244,18 +272,47 @@ ctypedef npy_cfloat cfloat_t ...@@ -244,18 +272,47 @@ ctypedef npy_cfloat cfloat_t
ctypedef npy_cdouble cdouble_t ctypedef npy_cdouble cdouble_t
ctypedef npy_clongdouble clongdouble_t ctypedef npy_clongdouble clongdouble_t
ctypedef npy_cdouble complex_t
cdef inline char* _util_dtypestring(dtype descr, char* f, char* end) except NULL: cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL:
# Recursive utility function used in __getbuffer__ to get format # Recursive utility function used in __getbuffer__ to get format
# string. The new location in the format string is returned. # string. The new location in the format string is returned.
cdef dtype child cdef dtype child
cdef int delta_offset
cdef tuple i cdef tuple i
cdef int endian_detector = 1
cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
for i in descr.fields.itervalues(): for i in descr.fields.itervalues():
child = i[0] child = i[0]
new_offset = i[1]
if (end - f) - (new_offset - offset[0]) < 15:
raise RuntimeError("Format string allocated too short, see comment in numpy.pxd")
if ((child.byteorder == '>' and little_endian) or
(child.byteorder == '<' and not little_endian)):
raise ValueError("Non-native byte order not supported")
# One could encode it in the format string and have Cython
# complain instead, BUT: < and > in format strings also imply
# standardized sizes for datatypes, and we rely on native in
# order to avoid reencoding data types based on their size.
#
# A proper PEP 3118 exporter for other clients than Cython
# must deal properly with this!
# Output padding bytes
while offset[0] < new_offset:
f[0] = 120 # "x"; pad byte
f += 1
offset[0] += 1
offset[0] += child.itemsize
if not PyDataType_HASFIELDS(child): if not PyDataType_HASFIELDS(child):
t = child.type_num t = child.type_num
if end - f < 15: # this should leave room for "T{" and "}" as well if end - f < 5:
raise RuntimeError("Format string allocated too short.") raise RuntimeError("Format string allocated too short.")
# Until ticket #99 is fixed, use integers to avoid warnings # Until ticket #99 is fixed, use integers to avoid warnings
...@@ -272,19 +329,16 @@ cdef inline char* _util_dtypestring(dtype descr, char* f, char* end) except NULL ...@@ -272,19 +329,16 @@ cdef inline char* _util_dtypestring(dtype descr, char* f, char* end) except NULL
elif t == NPY_FLOAT: f[0] = 102 #"f" elif t == NPY_FLOAT: f[0] = 102 #"f"
elif t == NPY_DOUBLE: f[0] = 100 #"d" elif t == NPY_DOUBLE: f[0] = 100 #"d"
elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg
elif t == NPY_OBJECT: f[0] = 79 #"O" elif t == NPY_OBJECT: f[0] = 79 #"O"
else: else:
raise ValueError("unknown dtype code in numpy.pxd (%d)" % t) raise ValueError("unknown dtype code in numpy.pxd (%d)" % t)
f += 1 f += 1
else: else:
f[0] = 84 #"T" # Cython ignores struct boundary information ("T{...}"),
f[1] = 123 #"{" # so don't output it
f += 2 f = _util_dtypestring(child, f, end, offset)
f = _util_dtypestring(child, f, end)
f[0] = 125 #"}"
f += 1
return f return f
cdef extern int f() cdef extern int f1()
cdef extern int __stdcall g() cdef extern int __cdecl f2()
cdef extern int __cdecl h() cdef extern int __stdcall f3()
cdef extern int (__stdcall *p)() cdef extern int __fastcall f4()
cdef extern int (*p1)()
cdef extern int (__cdecl *p2)()
cdef extern int (__stdcall *p3)()
cdef extern int (__fastcall *p4)()
p1 = f1
p2 = f2
p3 = f3
p4 = f4
...@@ -4,7 +4,11 @@ cdef void foo(obj): ...@@ -4,7 +4,11 @@ cdef void foo(obj):
cdef int *p2 cdef int *p2
i1 = p1 # error i1 = p1 # error
p2 = obj # error p2 = obj # error
obj = p2 # error
_ERRORS = u""" _ERRORS = u"""
5:16: Cannot assign type 'char *' to 'int' 5:16: Cannot assign type 'char *' to 'int'
6:17: Cannot convert Python object to 'int *' 6:17: Cannot convert Python object to 'int *'
8:17: Cannot convert 'int *' to Python object
""" """
cimport cython
@cython.callspec("")
cdef void h1(): pass
@cython.callspec("__cdecl")
cdef void __cdecl h2(): pass
@cython.callspec("__stdcall")
cdef void __stdcall h3(): pass
@cython.callspec("__fastcall")
cdef void __fastcall h4(): pass
@cython.callspec("__cdecl")
cdef void __stdcall h5(): pass # fail
@cython.callspec("__cdecl")
cdef void __fastcall h6(): pass # fail
cdef void (*p1)()
cdef void (__cdecl *p2)()
cdef void (__stdcall *p3)()
cdef void (__fastcall *p4)()
p1 = h1
p2 = h2
p3 = h3
p4 = h4
#p1 = h2 # fail
#p1 = h3 # fail
#p1 = h4 # fail
#p2 = h1 # fail
#p2 = h3 # fail
#p2 = h4 # fail
_ERRORS = u"""
16:22: cannot have both '__stdcall' and '__cdecl' calling conventions
19:23: cannot have both '__fastcall' and '__cdecl' calling conventions
"""
#31:14: Cannot assign type 'void (__cdecl )(void)' to 'void (*)(void)'
#32:14: Cannot assign type 'void (__stdcall )(void)' to 'void (*)(void)'
#33:14: Cannot assign type 'void (__fastcall )(void)' to 'void (*)(void)'
#35:14: Cannot assign type 'void (void)' to 'void (__cdecl *)(void)'
#36:14: Cannot assign type 'void (__stdcall )(void)' to 'void (__cdecl *)(void)'
#37:14: Cannot assign type 'void (__fastcall )(void)' to 'void (__cdecl *)(void)'
cdef object blarg cdef object blarg
def foo(obj): def foo(obj):
cdef int *p cdef void *p
p = <int *>blarg # okay p = <void *>blarg # ok
p = <int *>(foo + blarg) # error - temporary p = <void *>(obj + blarg) # error - temporary
_ERRORS = u""" _ERRORS = u"""
6:5: Casting temporary Python object to non-numeric non-Python type 6:5: Casting temporary Python object to non-numeric non-Python type
""" """
...@@ -25,7 +25,7 @@ cdef object m(): ...@@ -25,7 +25,7 @@ cdef object m():
i = 42 i = 42
obj = None obj = None
17L 17L
7j <object>7j
help help
`"Hello"` `"Hello"`
import fred import fred
...@@ -85,7 +85,7 @@ _ERRORS = u""" ...@@ -85,7 +85,7 @@ _ERRORS = u"""
15: 5: Calling gil-requiring function not allowed without gil 15: 5: Calling gil-requiring function not allowed without gil
24: 9: Calling gil-requiring function not allowed without gil 24: 9: Calling gil-requiring function not allowed without gil
26:12: Assignment of Python object not allowed without gil 26:12: Assignment of Python object not allowed without gil
28: 8: Constructing complex number not allowed without gil 28:16: Constructing complex number not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil 29:12: Accessing Python global or builtin not allowed without gil
30: 8: Backquote expression not allowed without gil 30: 8: Backquote expression not allowed without gil
31:15: Assignment of Python object not allowed without gil 31:15: Assignment of Python object not allowed without gil
......
a = 3
cdef void* allowed = <void*>a
cdef double* disallowed = <double*>a
_ERRORS = u"""
5:26: Python objects cannot be casted to pointers of primitive types
"""
...@@ -341,60 +341,6 @@ def explicitly_release_buffer(): ...@@ -341,60 +341,6 @@ 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]
@testcase
def wrong_string(object[int] buf):
"""
>>> wrong_string(IntMockBuffer(None, [1,2], format="if"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected end, got float)
>>> wrong_string(IntMockBuffer(None, [1,2], format="$$"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected int, got unparseable format string)
"""
print buf[1]
@testcase
def int_and_long_are_same():
"""
>>> int_and_long_are_same()
"""
cdef object[int] intarr
cdef object[long] longarr
if sizeof(int) == sizeof(long):
intarr = IntMockBuffer(None, [1,2], format='l')
longarr = IntMockBuffer(None, [1,2])
# #
# Getting items and index bounds checking # Getting items and index bounds checking
# #
...@@ -532,38 +478,25 @@ def no_negative_indices(object[int, negative_indices=False] buf, int idx): ...@@ -532,38 +478,25 @@ def no_negative_indices(object[int, negative_indices=False] buf, int idx):
""" """
return buf[idx] return buf[idx]
#
# Buffer type mismatch examples. Varying the type and access
# method simultaneously, the odds of an interaction is virtually
# zero.
#
@testcase @testcase
def fmtst1(buf): @cython.wraparound(False)
""" def wraparound_directive(object[int] buf, int pos_idx, int neg_idx):
>>> fmtst1(IntMockBuffer("A", range(3)))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected float, got int)
""" """
cdef object[float] a = buf Again, the most interesting thing here is to inspect the C source.
@testcase >>> A = IntMockBuffer(None, range(4))
def fmtst2(object[int] buf): >>> wraparound_directive(A, 2, -1)
""" 5
>>> fmtst2(FloatMockBuffer("A", range(3))) >>> wraparound_directive(A, -1, 2)
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected int, got float) IndexError: Out of bounds on buffer access (axis 0)
""" """
cdef int byneg
with cython.wraparound(True):
byneg = buf[neg_idx]
return buf[pos_idx] + byneg
@testcase
def ndim1(object[int, ndim=2] buf):
"""
>>> ndim1(IntMockBuffer("A", range(3)))
Traceback (most recent call last):
...
ValueError: Buffer has wrong number of dimensions (expected 2, got 1)
"""
# #
# Test which flags are passed. # Test which flags are passed.
...@@ -860,8 +793,7 @@ def printbuf_td_cy_int(object[td_cy_int] buf, shape): ...@@ -860,8 +793,7 @@ def printbuf_td_cy_int(object[td_cy_int] buf, shape):
>>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,)) >>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected bufaccess.td_cy_int, got short) ValueError: Buffer dtype mismatch, expected 'bufaccess.td_cy_int' but got 'short'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -876,7 +808,7 @@ def printbuf_td_h_short(object[td_h_short] buf, shape): ...@@ -876,7 +808,7 @@ def printbuf_td_h_short(object[td_h_short] buf, shape):
>>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected bufaccess.td_h_short, got int) ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_short' but got 'int'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -891,7 +823,7 @@ def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape): ...@@ -891,7 +823,7 @@ def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape):
>>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected bufaccess.td_h_cy_short, got int) ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_cy_short' but got 'int'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -906,7 +838,7 @@ def printbuf_td_h_ushort(object[td_h_ushort] buf, shape): ...@@ -906,7 +838,7 @@ def printbuf_td_h_ushort(object[td_h_ushort] buf, shape):
>>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,)) >>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected bufaccess.td_h_ushort, got short) ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_ushort' but got 'short'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -921,7 +853,7 @@ def printbuf_td_h_double(object[td_h_double] buf, shape): ...@@ -921,7 +853,7 @@ def printbuf_td_h_double(object[td_h_double] buf, shape):
>>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,)) >>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected bufaccess.td_h_double, got float) ValueError: Buffer dtype mismatch, expected 'bufaccess.td_h_double' but got 'float'
""" """
cdef int i cdef int i
for i in range(shape[0]): for i in range(shape[0]):
...@@ -1033,7 +965,7 @@ def buffer_cast_fails(object[char, cast=True] buf): ...@@ -1033,7 +965,7 @@ def buffer_cast_fails(object[char, cast=True] buf):
>>> buffer_cast_fails(IntMockBuffer(None, [0])) >>> buffer_cast_fails(IntMockBuffer(None, [0]))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Attempted cast of buffer to datatype of different size. ValueError: Item size of buffer (4 bytes) does not match size of 'char' (1 byte)
""" """
return buf[0] return buf[0]
...@@ -1366,48 +1298,31 @@ cdef class NestedStructMockBuffer(MockBuffer): ...@@ -1366,48 +1298,31 @@ cdef class NestedStructMockBuffer(MockBuffer):
@testcase @testcase
def basic_struct(object[MyStruct] buf): def basic_struct(object[MyStruct] buf):
""" """
See also buffmt.pyx
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)])) >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
1 2 3 4 5 1 2 3 4 5
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii")) >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii"))
1 2 3 4 5 1 2 3 4 5
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="23bqii"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected long long, got char)
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="i"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected char, got int)
""" """
print buf[0].a, buf[0].b, buf[0].c, buf[0].d, buf[0].e print buf[0].a, buf[0].b, buf[0].c, buf[0].d, buf[0].e
@testcase @testcase
def nested_struct(object[NestedStruct] buf): def nested_struct(object[NestedStruct] buf):
""" """
See also buffmt.pyx
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)])) >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
1 2 3 4 5 1 2 3 4 5
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i")) >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i"))
1 2 3 4 5 1 2 3 4 5
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="iiiii"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected SmallStruct, got int)
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{iii}T{ii}i"))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch (expected end of SmallStruct struct, got int)
""" """
print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z
cdef struct LongComplex: cdef struct LongComplex:
long double real long double real
long double imag long double imag
cdef struct MixedComplex:
long double real
float imag
cdef class LongComplexMockBuffer(MockBuffer): cdef class LongComplexMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1: cdef int write(self, char* buf, object value) except -1:
cdef LongComplex* s cdef LongComplex* s
...@@ -1418,24 +1333,33 @@ cdef class LongComplexMockBuffer(MockBuffer): ...@@ -1418,24 +1333,33 @@ cdef class LongComplexMockBuffer(MockBuffer):
cdef get_itemsize(self): return sizeof(LongComplex) cdef get_itemsize(self): return sizeof(LongComplex)
cdef get_default_format(self): return b"Zg" cdef get_default_format(self): return b"Zg"
#cdef extern from "complex.h":
# pass
@testcase @testcase
def complex_struct_dtype(object[LongComplex] buf): def complex_dtype(object[long double complex] buf):
""" """
Note that the format string is "Zg" rather than "2g"... >>> complex_dtype(LongComplexMockBuffer(None, [(0, -1)]))
>>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)])) -1j
0.0 -1.0
""" """
print buf[0].real, buf[0].imag print buf[0]
@testcase @testcase
def mixed_complex_struct_dtype(object[MixedComplex] buf): def complex_inplace(object[long double complex] buf):
""" """
Triggering a specific execution path for this case. >>> complex_inplace(LongComplexMockBuffer(None, [(0, -1)]))
(1+1j)
"""
buf[0] = buf[0] + 1 + 2j
print buf[0]
>>> mixed_complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)])) @testcase
Traceback (most recent call last): def complex_struct_dtype(object[LongComplex] buf):
... """
ValueError: Cannot store complex number in 'MixedComplex' as 'long double' differs from 'float' in size. Note that the format string is "Zg" rather than "2g", yet a struct
is accessed.
>>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)]))
0.0 -1.0
""" """
print buf[0].real, buf[0].imag print buf[0].real, buf[0].imag
......
from __future__ import unicode_literals
# Tests buffer format string parsing.
__test__ = {}
def testcase(func):
__test__[func.__name__] = func.__doc__
return func
cimport stdlib
def little_endian():
cdef unsigned int n = 1
return (<unsigned char*>&n)[0] != 0
if little_endian():
current_endian = '<'
other_endian = '>'
else:
current_endian = '>'
other_endian = '<'
cdef struct align_of_float_helper:
char ch
float d
cdef struct align_of_int_helper:
char ch
int i
float_align = sizeof(align_of_float_helper) - sizeof(float)
int_align = sizeof(align_of_int_helper) - sizeof(int)
if float_align != 4 or sizeof(float) != 4:
raise RuntimeError("Alignment or size of float is %d on this system, please report to cython-dev for a testcase fix" % float_align)
if int_align != 4 or sizeof(int) != 4:
raise RuntimeError("Alignment or size of int is %d on this system, please report to cython-dev for a testcase fix" % int_align)
cdef class MockBuffer:
cdef Py_ssize_t zero
cdef Py_ssize_t minusone
cdef object format
cdef object itemsize
def __init__(self, format, itemsize):
self.format = unicode(format).encode(u"ASCII")
self.itemsize = itemsize
self.zero = 0
self.minusone = -1
def __getbuffer__(self, Py_buffer* info, int flags):
info.buf = NULL
info.strides = &self.zero
info.suboffsets = &self.minusone
info.shape = &self.zero
info.ndim = 1
info.format = self.format
info.itemsize = self.itemsize
@testcase
def _int(fmt):
"""
>>> _int("i")
>>> _int("b")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'int' but got 'char'
>>> _int("if")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected end but got 'float'
>>> _int("$$")
Traceback (most recent call last):
...
ValueError: Does not understand character buffer dtype format string ('$')
"""
cdef object[int] buf = MockBuffer(fmt, sizeof(int))
@testcase
def _ulong(fmt):
"""
>>> _ulong("L")
"""
cdef object[unsigned long] buf = MockBuffer(fmt, sizeof(unsigned long))
@testcase
def wrongsize():
"""
>>> wrongsize()
Traceback (most recent call last):
...
ValueError: Item size of buffer (1 byte) does not match size of 'float' (4 bytes)
"""
cdef object[float] buf = MockBuffer("f", 1)
@testcase
def _obj(fmt):
"""
>>> _obj("O")
>>> _obj("i")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'Python object' but got 'int'
"""
cdef object[object] buf = MockBuffer(fmt, sizeof(void*))
cdef struct ComplexFloat:
float real
float imag
ctypedef struct Char3Int:
char a
int b
int c
int d
cdef struct CharIntCFloat:
char a
int b
ComplexFloat c
float d
cdef struct UnpackedStruct1:
char a
int b
ComplexFloat c
float c2
Char3Int d
ctypedef struct UnpackedStruct2:
CharIntCFloat a
Char3Int b
ctypedef struct UnpackedStruct3:
CharIntCFloat a
char b
int c, d, e
cdef struct UnpackedStruct4:
char a
int b
ComplexFloat c
float c2
char d
int e, f, g
@testcase
def char3int(fmt):
"""
>>> char3int("ciii")
>>> char3int("c1i1i1i")
>>> char3int("c3i")
>>> char3int("ci2i")
#TODO > char3int("c@i@2i")
Extra pad bytes (assuming int size is 4 or more)
>>> char3int("cxiii")
>>> char3int("c3xiii")
>>> char3int("cxxxiii")
Standard alignment (assming int size is 4)
>>> char3int("=c3xiii")
>>> char3int("=ciii")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
#TODO char3int("=cxxx@iii")
Error:
>>> char3int("cii")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'int' but got end in 'Char3Int.d'
"""
obj = MockBuffer(fmt, sizeof(Char3Int))
cdef object[Char3Int, ndim=1] buf = obj
@testcase
def unpacked_struct(fmt):
"""
Native formats:
>>> unpacked_struct("biZffbiii")
>>> unpacked_struct("@bi3fb3i")
>>> unpacked_struct("@biZffbi2i")
>>> unpacked_struct("biZffT{biii}")
>>> unpacked_struct("bT{ifffb2i}i")
>>> unpacked_struct("biZffb3T{i}")
>>> unpacked_struct("T{b}T{T{iZffT{bi}}}2T{T{i}}")
"""
assert (sizeof(UnpackedStruct1) == sizeof(UnpackedStruct2)
== sizeof(UnpackedStruct3) == sizeof(UnpackedStruct4))
obj = MockBuffer(fmt, sizeof(UnpackedStruct1))
cdef object[UnpackedStruct1, ndim=1] buf1 = obj
cdef object[UnpackedStruct2, ndim=1] buf2 = obj
cdef object[UnpackedStruct3, ndim=1] buf3 = obj
cdef object[UnpackedStruct4, ndim=1] buf4 = obj
cdef struct ComplexTest:
ComplexFloat a, b, c
@testcase
def complex_test(fmt):
"""
>>> complex_test("ZfZfZf")
>>> complex_test("3Zf")
>>> complex_test("6f")
>>> complex_test("3T{Zf}")
>>> complex_test("fZfZff")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'float' but got 'complex float' in 'ComplexFloat.imag'
"""
obj = MockBuffer(fmt, sizeof(ComplexTest))
cdef object[ComplexTest] buf1 = obj
@testcase
def alignment_string(fmt, exc=None):
"""
>>> alignment_string("@i")
>>> alignment_string("%si" % current_endian)
>>> alignment_string("%si" % other_endian, "X-endian buffer not supported on X-endian compiler")
>>> alignment_string("=i")
"""
cdef object[int] buf
try:
buf = MockBuffer(fmt, sizeof(int))
except ValueError, e:
msg = unicode(e).replace("Big", "X").replace("Little", "X").replace("big", "X").replace("little", "X")
if msg != exc:
print msg
print " is not equal to"
print exc
return
if exc:
print "fail"
@testcase
def int_and_long_are_same():
"""
>>> int_and_long_are_same()
"""
cdef object[int] intarr
cdef object[long] longarr
if sizeof(int) == sizeof(long):
intarr = MockBuffer("l", sizeof(int))
longarr = MockBuffer("i", sizeof(int))
cdef struct MixedComplex:
double real
float imag
@testcase
def mixed_complex_struct():
"""
Triggering a specific execution path for this case.
>>> mixed_complex_struct()
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'double' but got 'complex double' in 'MixedComplex.real'
"""
cdef object[MixedComplex] buf = MockBuffer("Zd",
sizeof(MixedComplex))
cdef packed struct PackedSubStruct:
char x
int y
cdef packed struct PackedStruct:
char a
int b
PackedSubStruct sub
@testcase
def packed_struct(fmt):
"""
Assuming int is four bytes:
>>> packed_struct("^cici")
>>> packed_struct("=cibi")
>>> packed_struct("^c@i^ci")
Traceback (most recent call last):
...
ValueError: Buffer packing mode currently only allowed at beginning of format string (this is a defect)
However aligned access won't work:
>>> packed_struct("@cici")
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch; next field is at offset 4 but 1 expected
"""
cdef object[PackedStruct] buf = MockBuffer(fmt, sizeof(PackedStruct))
# TODO: empty struct
# TODO: Incomplete structs
# TODO: mixed structs
...@@ -666,6 +666,17 @@ class MyBadInt(MyInt): ...@@ -666,6 +666,17 @@ class MyBadInt(MyInt):
def __int__(self): def __int__(self):
return u"%s" % self.value return u"%s" % self.value
class MyInt2:
def __init__(self, value):
self.value = value
def __int__(self):
print(u"MyInt.__int__()")
return self.value
class MyBadInt2(MyInt2):
def __int__(self):
return u"%s" % self.value
def test_convert_pyint(x): def test_convert_pyint(x):
u""" u"""
>>> test_convert_pyint(None) >>> test_convert_pyint(None)
......
__doc__ = u''' __doc__ = u'''
>>> no_cdef() >>> no_cdef()
>>> with_cdef() >>> with_cdef()
<<<<<<< local
>>> test_list(range(11), -2, None) >>> test_list(range(11), -2, None)
=======
>>> test_list(list(range(11)), -2, None)
>>>>>>> other
[0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10] [0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10]
<<<<<<< local
>>> test_list(range(11), "invalid index", None) >>> test_list(range(11), "invalid index", None)
=======
>>> test_list(list(range(11)), "invalid index", None) #doctest: +ELLIPSIS
>>>>>>> other
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: list indices must be integers, not str TypeError: list indices must be integers...
''' '''
def no_cdef(): def no_cdef():
lst = range(11) lst = list(range(11))
ob = 10L ob = 10L
lst[ob] = -10 lst[ob] = -10
dd = {} dd = {}
dd[ob] = -10 dd[ob] = -10
def with_cdef(): def with_cdef():
cdef list lst = range(11) cdef list lst = list(range(11))
ob = 10L ob = 10L
lst[ob] = -10 lst[ob] = -10
cdef dict dd = {} cdef dict dd = {}
......
...@@ -14,11 +14,11 @@ cdef char* s = 'abcdef' ...@@ -14,11 +14,11 @@ cdef char* s = 'abcdef'
def global_c_and_s(): def global_c_and_s():
pys = s pys = s
print c print c
print pys.decode('ASCII') print (pys.decode(u'ASCII'))
def local_c_and_s(): def local_c_and_s():
cdef char c = 'b' cdef char c = 'b'
cdef char* s = 'bcdefg' cdef char* s = 'bcdefg'
pys = s pys = s
print c print c
print pys.decode('ASCII') print (pys.decode(u'ASCII'))
__doc__ = u"""
>>> test_object_conversion(2)
((2+0j), (2+0j))
>>> test_object_conversion(2j - 0.5)
((-0.5+2j), (-0.5+2j))
>>> test_arithmetic(2j, 4j)
(-2j, 6j, -2j, (-8+0j), (0.5+0j))
>>> test_arithmetic(6+12j, 3j)
((-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j))
>>> test_arithmetic(5-10j, 3+4j)
((-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
>>> test_div_by_zero(4j)
-0.25j
>>> test_div_by_zero(0)
Traceback (most recent call last):
...
ZeroDivisionError: float division
>>> test_coercion(1, 1.5, 2.5, 4+1j, 10j)
(1+0j)
(1.5+0j)
(2.5+0j)
(4+1j)
10j
(9+21j)
>>> test_compare(3, 3)
(True, False)
>>> test_compare(3j, 3j)
(True, False)
>>> test_compare(3j, 4j)
(False, True)
>>> test_compare(3, 4)
(False, True)
>>> test_compare_coerce(3, 4)
(False, True)
>>> test_compare_coerce(4+1j, 4)
(False, True)
>>> test_compare_coerce(4, 4)
(True, False)
>>> test_literal()
(5j, (1-2.5j))
>>> test_real_imag(1-3j)
(1.0, -3.0)
>>> test_real_imag(5)
(5.0, 0.0)
>>> test_real_imag(1.5j)
(0.0, 1.5)
>>> test_real_imag_assignment(1, 2)
(1+2j)
>>> test_real_imag_assignment(1.5, -3.5)
(1.5-3.5j)
"""
#cdef extern from "complex.h":
# pass
cimport cython
def test_object_conversion(o):
cdef float complex a = o
cdef double complex z = o
return (a, z)
def test_arithmetic(double complex z, double complex w):
return -z, z+w, z-w, z*w, z/w
@cython.cdivision(False)
def test_div_by_zero(double complex z):
return 1/z
def test_coercion(int a, float b, double c, float complex d, double complex e):
cdef double complex z
z = a; print z
z = b; print z
z = c; print z
z = d; print z
z = e; print z
return z + a + b + c + d + e
def test_compare(double complex a, double complex b):
return a == b, a != b
def test_compare_coerce(double complex a, int b):
return a == b, a != b
def test_literal():
return 5j, 1-2.5j
def test_real_imag(double complex z):
return z.real, z.imag
def test_real_imag_assignment(object a, double b):
cdef double complex z
z.real = a
z.imag = b
return z
typedef double DoubleTypedef;
...@@ -32,29 +32,29 @@ __doc__ = u""" ...@@ -32,29 +32,29 @@ __doc__ = u"""
def double_target(a, b): def double_target(a, b):
cdef double x cdef double x
for x from a <= x < b: for x from a <= x < b:
print "at", x print u"at", x
return x return x
def double_step(a, b, dx): def double_step(a, b, dx):
cdef double x cdef double x
for x from a <= x < b by dx: for x from a <= x < b by dx:
print "at", x print u"at", x
return x return x
def double_step_typed(a, b, double dx): def double_step_typed(a, b, double dx):
cdef double x cdef double x
for x from a <= x < b by dx: for x from a <= x < b by dx:
print "at", x print u"at", x
return x return x
def double_step_py_target(a, b, double dx): def double_step_py_target(a, b, double dx):
cdef object x cdef object x
for x from a <= x < b by dx: for x from a <= x < b by dx:
print "at", x print u"at", x
return x return x
def int_step_py_target(a, b, int dx): def int_step_py_target(a, b, int dx):
cdef object x cdef object x
for x from a <= x < b by dx: for x from a <= x < b by dx:
print "at", x print u"at", x
return x return x
...@@ -2,6 +2,17 @@ ...@@ -2,6 +2,17 @@
cimport numpy as np cimport numpy as np
def little_endian():
cdef int endian_detector = 1
return (<char*>&endian_detector)[0] != 0
if little_endian():
my_endian = '<'
other_endian = '>'
else:
my_endian = '>'
other_endian = '<'
try: try:
import numpy as np import numpy as np
__doc__ = u""" __doc__ = u"""
...@@ -111,6 +122,7 @@ try: ...@@ -111,6 +122,7 @@ try:
>>> test_dtype('I', inc1_uint) >>> test_dtype('I', inc1_uint)
>>> test_dtype('l', inc1_long) >>> test_dtype('l', inc1_long)
>>> test_dtype('L', inc1_ulong) >>> test_dtype('L', inc1_ulong)
>>> test_dtype('f', inc1_float) >>> test_dtype('f', inc1_float)
>>> test_dtype('d', inc1_double) >>> test_dtype('d', inc1_double)
>>> test_dtype('g', inc1_longdouble) >>> test_dtype('g', inc1_longdouble)
...@@ -118,6 +130,9 @@ try: ...@@ -118,6 +130,9 @@ try:
>>> test_dtype('F', inc1_cfloat) # numpy format codes differ from buffer ones here >>> test_dtype('F', inc1_cfloat) # numpy format codes differ from buffer ones here
>>> test_dtype('D', inc1_cdouble) >>> test_dtype('D', inc1_cdouble)
>>> test_dtype('G', inc1_clongdouble) >>> test_dtype('G', inc1_clongdouble)
>>> test_dtype('F', inc1_cfloat_struct)
>>> test_dtype('D', inc1_cdouble_struct)
>>> test_dtype('G', inc1_clongdouble_struct)
>>> test_dtype(np.int, inc1_int_t) >>> test_dtype(np.int, inc1_int_t)
>>> test_dtype(np.long, inc1_long_t) >>> test_dtype(np.long, inc1_long_t)
...@@ -129,34 +144,62 @@ try: ...@@ -129,34 +144,62 @@ try:
>>> test_dtype(np.int32, inc1_int32_t) >>> test_dtype(np.int32, inc1_int32_t)
>>> test_dtype(np.float64, inc1_float64_t) >>> test_dtype(np.float64, inc1_float64_t)
Endian tests:
>>> test_dtype('%si' % my_endian, inc1_int)
>>> test_dtype('%si' % other_endian, inc1_int)
Traceback (most recent call last):
...
ValueError: Non-native byte order not supported
>>> test_recordarray() >>> test_recordarray()
>>> test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\
('a', np.dtype('i,i')),\ ('a', np.dtype('i,i')),\
('b', np.dtype('i,i'))\ ('b', np.dtype('i,i'))\
]))) ]))))
array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))], array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))],
dtype=[('a', [('f0', '<i4'), ('f1', '<i4')]), ('b', [('f0', '<i4'), ('f1', '<i4')])]) dtype=[('a', [('f0', '!i4'), ('f1', '!i4')]), ('b', [('f0', '!i4'), ('f1', '!i4')])])
>>> test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\
('a', np.dtype('i,f')),\ ('a', np.dtype('i,f')),\
('b', np.dtype('i,i'))\ ('b', np.dtype('i,i'))\
]))) ]))))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'int' but got 'float' in 'DoubleInt.y'
>>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=False))))
array([(22, 23)],
dtype=[('f0', '|i1'), ('f1', '!i4')])
>>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=True))))
array([(22, 23)],
dtype=[('f0', '|i1'), ('', '|V3'), ('f1', '!i4')])
>>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=True))))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch; next field is at offset 4 but 1 expected
>>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=False))))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Buffer dtype mismatch (expected int, got float) ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
>>> test_good_cast() >>> test_good_cast()
True True
>>> test_bad_cast() >>> test_bad_cast()
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: Attempted cast of buffer to datatype of different size. ValueError: Item size of buffer (1 byte) does not match size of 'int' (4 bytes)
""" """
except: except:
__doc__ = u"" __doc__ = u""
def ndarray_str(arr): def ndarray_str(arr):
u""" u"""
Since Py2.3 doctest don't support <BLANKLINE>, manually replace blank lines Since Py2.3 doctest don't support <BLANKLINE>, manually replace blank lines
...@@ -218,15 +261,19 @@ def inc1_float(np.ndarray[float] arr): arr[1] += 1 ...@@ -218,15 +261,19 @@ def inc1_float(np.ndarray[float] arr): arr[1] += 1
def inc1_double(np.ndarray[double] arr): arr[1] += 1 def inc1_double(np.ndarray[double] arr): arr[1] += 1
def inc1_longdouble(np.ndarray[long double] arr): arr[1] += 1 def inc1_longdouble(np.ndarray[long double] arr): arr[1] += 1
def inc1_cfloat(np.ndarray[np.cfloat_t] arr): def inc1_cfloat(np.ndarray[float complex] arr): arr[1] = arr[1] + 1 + 1j
def inc1_cdouble(np.ndarray[double complex] arr): arr[1] = (arr[1] + 1) + 1j
def inc1_clongdouble(np.ndarray[long double complex] arr): arr[1] = arr[1] + (1 + 1j)
def inc1_cfloat_struct(np.ndarray[np.cfloat_t] arr):
arr[1].real += 1 arr[1].real += 1
arr[1].imag += 1 arr[1].imag += 1
def inc1_cdouble(np.ndarray[np.cdouble_t] arr): def inc1_cdouble_struct(np.ndarray[np.cdouble_t] arr):
arr[1].real += 1 arr[1].real += 1
arr[1].imag += 1 arr[1].imag += 1
def inc1_clongdouble(np.ndarray[np.clongdouble_t] arr): def inc1_clongdouble_struct(np.ndarray[np.clongdouble_t] arr):
cdef long double x cdef long double x
x = arr[1].real + 1 x = arr[1].real + 1
arr[1].real = x arr[1].real = x
...@@ -297,7 +344,7 @@ def test_nested_dtypes(obj): ...@@ -297,7 +344,7 @@ def test_nested_dtypes(obj):
arr[1].b.x = arr[0].a.y + 1 arr[1].b.x = arr[0].a.y + 1
arr[1].b.y = 4 arr[1].b.y = 4
arr[2] = arr[1] arr[2] = arr[1]
return arr return repr(arr).replace('<', '!').replace('>', '!')
def test_bad_nested_dtypes(): def test_bad_nested_dtypes():
cdef object[BadNestedStruct] arr cdef object[BadNestedStruct] arr
...@@ -310,4 +357,22 @@ def test_good_cast(): ...@@ -310,4 +357,22 @@ def test_good_cast():
def test_bad_cast(): def test_bad_cast():
# This should raise an exception # This should raise an exception
cdef np.ndarray[long, cast=True] arr = np.array([1], dtype=b'b') cdef np.ndarray[int, cast=True] arr = np.array([1], dtype=b'b')
cdef packed struct PackedStruct:
char a
int b
cdef struct UnpackedStruct:
char a
int b
def test_packed_align(np.ndarray[PackedStruct] arr):
arr[0].a = 22
arr[0].b = 23
return repr(arr).replace('<', '!').replace('>', '!')
def test_unpacked_align(np.ndarray[UnpackedStruct] arr):
arr[0].a = 22
arr[0].b = 23
return repr(arr).replace('<', '!').replace('>', '!')
# Ensure casting still works to void*
"""
>>> o = f()
>>> print(o[0])
teststring
>>> print(o[1])
teststring
"""
cdef extern from *:
ctypedef void PyObject
def f():
cdef void* p1
cdef PyObject* p2
a = u"teststring"
p1 = <void*>a
p2 = <PyObject*>a
return (<object>p1, <object>p2)
...@@ -74,66 +74,66 @@ at 4 ...@@ -74,66 +74,66 @@ at 4
5 5
""" """
cdef int get_bound(int m): cdef int get_bound(int m):
print "get_bound(%s)"%m print u"get_bound(%s)"%m
return m return m
def for_from_range(a, b): def for_from_range(a, b):
cdef int i = 100 cdef int i = 100
print "range(%s)" % a print u"range(%s)" % a
for i in range(a): for i in range(a):
print "at", i print u"at", i
print "range(%s, %s)" % (a, b) print u"range(%s, %s)" % (a, b)
for i in range(a, b): for i in range(a, b):
print "at", i print u"at", i
print "range(%s, %s, %s)" % (a, b, 2) print u"range(%s, %s, %s)" % (a, b, 2)
for i in range(a, b, 2): for i in range(a, b, 2):
print "at", i print u"at", i
return i return i
def for_from_bound_reassignment(int bound, int fake_bound): def for_from_bound_reassignment(int bound, int fake_bound):
cdef int i = 100 cdef int i = 100
for i from 0 <= i < bound: for i from 0 <= i < bound:
print "at", i print u"at", i
bound = fake_bound bound = fake_bound
return i return i
def for_from_step_reassignment(int bound, int step, int fake_step): def for_from_step_reassignment(int bound, int step, int fake_step):
cdef int i = 100 cdef int i = 100
for i from 0 <= i < bound by step: for i from 0 <= i < bound by step:
print "at", i print u"at", i
step = fake_step step = fake_step
return i return i
def for_from_target_reassignment(int bound, int factor): def for_from_target_reassignment(int bound, int factor):
cdef int i = 100 cdef int i = 100
for i from 0 <= i < bound: for i from 0 <= i < bound:
print "at", i print u"at", i
i *= factor i *= factor
return i return i
def for_from_py_target_reassignment(int bound, int factor): def for_from_py_target_reassignment(int bound, int factor):
cdef object i cdef object i
for i from 0 <= i < bound: for i from 0 <= i < bound:
print "at", i print u"at", i
i *= factor i *= factor
return i return i
def for_from_py_global_target_reassignment(int bound, int factor): def for_from_py_global_target_reassignment(int bound, int factor):
global g_var global g_var
for g_var from 0 <= g_var < bound: for g_var from 0 <= g_var < bound:
print "at", g_var print u"at", g_var
g_var *= factor g_var *= factor
return g_var return g_var
def for_in_target_reassignment(int bound, int factor): def for_in_target_reassignment(int bound, int factor):
cdef int i = 100 cdef int i = 100
for i in range(bound): for i in range(bound):
print "at", i print u"at", i
i *= factor i *= factor
return i return i
def test_func(int n): def test_func(int n):
cdef int i = 100 cdef int i = 100
for i from 0 <= i < get_bound(n): for i from 0 <= i < get_bound(n):
print "at", i print u"at", i
return i return i
__doc__ = u"""
>>> print( "%d" % Int() )
2
>>> print( "%d" % Long() )
3
>>> print( "%d" % IntLongA() )
2
>>> print( "%d" % IntLongB() )
2
>>> print( "%d" % IntLongC() )
3
>>> getint( Int() )
2
>>> getint( Long() )
3
>>> getint( IntLongA() )
2
>>> getint( IntLongB() )
2
>>> getint( IntLongC() )
3
>>> getlong( Int() )
2
>>> getlong( Long() )
3
>>> getlong( IntLongA() )
2
>>> getlong( IntLongB() )
2
>>> getlong( IntLongC() )
3
"""
def getint(int i):
return i
def getlong(long long i):
return <int>i
cdef class Int:
def __int__(self):
return 2
cdef class Long:
def __long__(self):
return 3
cdef class IntLongA:
def __int__(self):
return 2
def __long__(self):
return 3
cdef class IntLongB:
def __int__(self):
return 2
__long__ = __int__
cdef class IntLongC:
def __long__(self):
return 3
__int__ = __long__
...@@ -22,10 +22,10 @@ __doc__ = u""" ...@@ -22,10 +22,10 @@ __doc__ = u"""
>>> slice_list_assign(l2, dict(zip(l,l))) >>> slice_list_assign(l2, dict(zip(l,l)))
[1, 1, 2, 3, 4, 4] [1, 1, 2, 3, 4, 4]
>>> slice_charp('abcdefg') >>> print("%s" % slice_charp('abcdefg'))
'bc' bc
>>> slice_charp_repeat('abcdefg') >>> print("%s" % slice_charp_repeat('abcdefg'))
'cd' cd
""" """
def slice_list(list l): def slice_list(list l):
...@@ -51,12 +51,14 @@ def slice_list_assign(list l, value): ...@@ -51,12 +51,14 @@ def slice_list_assign(list l, value):
return l return l
def slice_charp(str py_string): def slice_charp(py_string_arg):
cdef str py_string = py_string_arg.encode(u'ASCII')
cdef char* s = py_string cdef char* s = py_string
return s[1:3] return s[1:3].decode(u'ASCII')
def slice_charp_repeat(str py_string): def slice_charp_repeat(py_string_arg):
cdef str py_string = py_string_arg.encode(u'ASCII')
cdef char* s = py_string cdef char* s = py_string
cdef str slice_val = s[1:6] cdef str slice_val = s[1:6]
s = slice_val s = slice_val
return s[1:3] return s[1:3].decode(u'ASCII')
"""
>>> f()
42.0 42.0 42.0
>>> readonly()
Traceback (most recent call last):
...
AttributeError: attribute 'var_nf' of 'typedfieldbug_T303.MyClass' objects is not writable
"""
cdef extern from "external_defs.h":
ctypedef float DoubleTypedef
cdef class MyClass:
cdef readonly:
double var_d
DoubleTypedef var_nf
cdef public:
DoubleTypedef var_mutable
def __init__(self):
self.var_d = 42.0
self.var_nf = 42.0
self.var_mutable = 1
def f():
c = MyClass()
c.var_mutable = 42.0
print c.var_d, c.var_nf, c.var_mutable
def readonly():
c = MyClass()
c.var_nf = 3
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