Commit 0532e356 authored by Robert Bradshaw's avatar Robert Bradshaw

Merge branch 'master' into ctuple

Conflicts:
	Cython/Compiler/PyrexTypes.py
	Cython/Utility/TypeConversion.c
	tests/run/arrayassign.pyx
parents ed84c09d 611f4187
...@@ -49,3 +49,6 @@ c1a18ab6b0808e87f68d2f9d914c01934510aef5 0.18b1 ...@@ -49,3 +49,6 @@ c1a18ab6b0808e87f68d2f9d914c01934510aef5 0.18b1
52beb5b16df5b8a92bb6c8c47faf42370d73cb0f 0.19b2 52beb5b16df5b8a92bb6c8c47faf42370d73cb0f 0.19b2
4818f5b68eb4b4ea6ad7e415f6672b491e2461bc 0.19rc1 4818f5b68eb4b4ea6ad7e415f6672b491e2461bc 0.19rc1
48407fa3f3c9da84ab3dc103a6a2b1ca4c1beb2a 0.19 48407fa3f3c9da84ab3dc103a6a2b1ca4c1beb2a 0.19
58fc9a3feb83f571623a492256885d21945decb4 0.21.1
58fc9a3feb83f571623a492256885d21945decb4 0.21.1
d05a4acd45fca9bdc12cef82890ca569fbaae1a5 0.21.1
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
Cython Changelog Cython Changelog
================ ================
Latest Latest changes
====== ==============
Features added Features added
-------------- --------------
...@@ -11,12 +11,31 @@ Features added ...@@ -11,12 +11,31 @@ Features added
* C functions can coerce to Python functions, which allows passing them * C functions can coerce to Python functions, which allows passing them
around as callable objects. around as callable objects.
* New ``cythonize`` option ``-a`` to generate the annotated HTML source view. * C arrays can be assigned by value and auto-coerce from Python iterables
and to Python lists (and tuples).
* Extern C functions can now be declared as cpdef to export them to * Extern C functions can now be declared as cpdef to export them to
the module's Python namespace. Extern C functions in pxd files export the module's Python namespace. Extern C functions in pxd files export
their values to their own module, iff it exists. their values to their own module, iff it exists.
Bugs fixed
----------
* Mismatching 'except' declarations on signatures in .pxd and .pyx files failed
to produce a compile error.
Other changes
-------------
0.21.1 (2014-10-18)
===================
Features added
--------------
* New ``cythonize`` option ``-a`` to generate the annotated HTML source view.
* Missing C-API declarations in ``cpython.unicode`` were added. * Missing C-API declarations in ``cpython.unicode`` were added.
* Passing ``language='c++'`` into cythonize() globally enables C++ mode for * Passing ``language='c++'`` into cythonize() globally enables C++ mode for
...@@ -35,9 +54,6 @@ Features added ...@@ -35,9 +54,6 @@ Features added
Bugs fixed Bugs fixed
---------- ----------
* Mismatching 'except' declarations on signatures in .pxd and .pyx files failed
to produce a compile error.
* Reference leak for non-simple Python expressions in boolean and/or expressions. * Reference leak for non-simple Python expressions in boolean and/or expressions.
* To fix a name collision and to reflect availability on host platforms, * To fix a name collision and to reflect availability on host platforms,
...@@ -55,6 +71,8 @@ Bugs fixed ...@@ -55,6 +71,8 @@ Bugs fixed
if the already created module was used later on (e.g. through a if the already created module was used later on (e.g. through a
stale reference in sys.modules or elsewhere). stale reference in sys.modules or elsewhere).
* ``cythonize.py`` script was not installed on MS-Windows.
Other changes Other changes
------------- -------------
......
...@@ -966,14 +966,15 @@ class GlobalState(object): ...@@ -966,14 +966,15 @@ class GlobalState(object):
w.putln("") w.putln("")
w.putln("static void __Pyx_CleanupGlobals(void) {") w.putln("static void __Pyx_CleanupGlobals(void) {")
# code = self.parts['utility_code_proto']
# utility_code_def code.putln("")
# code.putln("/* --- Runtime support code (head) --- */")
code = self.parts['utility_code_def'] code = self.parts['utility_code_def']
if self.emit_linenums: if self.emit_linenums:
code.write('\n#line 1 "cython_utility"\n') code.write('\n#line 1 "cython_utility"\n')
code.putln("") code.putln("")
code.putln("/* Runtime support code */") code.putln("/* --- Runtime support code --- */")
def finalize_main_c_code(self): def finalize_main_c_code(self):
self.close_global_decls() self.close_global_decls()
......
...@@ -1727,19 +1727,18 @@ class NameNode(AtomicExprNode): ...@@ -1727,19 +1727,18 @@ class NameNode(AtomicExprNode):
def analyse_target_types(self, env): def analyse_target_types(self, env):
self.analyse_entry(env, is_target=True) self.analyse_entry(env, is_target=True)
if (not self.is_lvalue() and self.entry.is_cfunction and if self.entry.is_cfunction and self.entry.as_variable:
self.entry.fused_cfunction and self.entry.as_variable): if self.entry.is_overridable or not self.is_lvalue() and self.entry.fused_cfunction:
# We need this for the fused 'def' TreeFragment # We need this for assigning to cpdef names and for the fused 'def' TreeFragment
self.entry = self.entry.as_variable self.entry = self.entry.as_variable
self.type = self.entry.type self.type = self.entry.type
if self.type.is_const: if self.type.is_const:
error(self.pos, "Assignment to const '%s'" % self.name) error(self.pos, "Assignment to const '%s'" % self.name)
if self.type.is_reference: if self.type.is_reference:
error(self.pos, "Assignment to reference '%s'" % self.name) error(self.pos, "Assignment to reference '%s'" % self.name)
if not self.is_lvalue(): if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue '%s'" error(self.pos, "Assignment to non-lvalue '%s'" % self.name)
% self.name)
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
self.entry.used = 1 self.entry.used = 1
if self.entry.type.is_buffer: if self.entry.type.is_buffer:
...@@ -1863,9 +1862,13 @@ class NameNode(AtomicExprNode): ...@@ -1863,9 +1862,13 @@ class NameNode(AtomicExprNode):
return True return True
def is_lvalue(self): def is_lvalue(self):
return self.entry.is_variable and \ return (
not self.entry.type.is_array and \ self.entry.is_variable and
not self.entry.is_readonly not self.entry.is_readonly
) or (
self.entry.is_cfunction and
self.entry.is_overridable
)
def is_addressable(self): def is_addressable(self):
return self.entry.is_variable and not self.type.is_memoryviewslice return self.entry.is_variable and not self.type.is_memoryviewslice
...@@ -1969,7 +1972,7 @@ class NameNode(AtomicExprNode): ...@@ -1969,7 +1972,7 @@ class NameNode(AtomicExprNode):
return # There was an error earlier return # There was an error earlier
if (self.entry.type.is_ptr and isinstance(rhs, ListNode) if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
and not self.lhs_of_first_assignment and not rhs.in_module_scope): and not self.lhs_of_first_assignment and not rhs.in_module_scope):
error(self.pos, "Literal list must be assigned to pointer at time of declaration") error(self.pos, "Literal list must be assigned to pointer at time of declaration")
# is_pyglobal seems to be True for module level-globals only. # is_pyglobal seems to be True for module level-globals only.
...@@ -3436,9 +3439,6 @@ class IndexNode(ExprNode): ...@@ -3436,9 +3439,6 @@ class IndexNode(ExprNode):
elif self.type.is_ptr: elif self.type.is_ptr:
# non-const pointers can always be reassigned # non-const pointers can always be reassigned
return True return True
elif self.type.is_array:
# fixed-sized arrays aren't l-values
return False
# Just about everything else returned by the index operator # Just about everything else returned by the index operator
# can be an lvalue. # can be an lvalue.
return True return True
...@@ -3914,7 +3914,13 @@ class SliceIndexNode(ExprNode): ...@@ -3914,7 +3914,13 @@ class SliceIndexNode(ExprNode):
check_negative_indices(self.start, self.stop) check_negative_indices(self.start, self.stop)
base_type = self.base.type base_type = self.base.type
if base_type.is_string or base_type.is_cpp_string: if base_type.is_array and not getting:
# cannot assign directly to C array => try to assign by making a copy
if not self.start and not self.stop:
self.type = base_type
else:
self.type = PyrexTypes.CPtrType(base_type.base_type)
elif base_type.is_string or base_type.is_cpp_string:
self.type = default_str_type(env) self.type = default_str_type(env)
elif base_type.is_pyunicode_ptr: elif base_type.is_pyunicode_ptr:
self.type = unicode_type self.type = unicode_type
...@@ -4089,25 +4095,37 @@ class SliceIndexNode(ExprNode): ...@@ -4089,25 +4095,37 @@ class SliceIndexNode(ExprNode):
has_c_start, has_c_stop, has_c_start, has_c_stop,
bool(code.globalstate.directives['wraparound']))) bool(code.globalstate.directives['wraparound'])))
else: else:
start_offset = '' start_offset = self.start_code() if self.start else '0'
if self.start:
start_offset = self.start_code()
if start_offset == '0':
start_offset = ''
else:
start_offset += '+'
if rhs.type.is_array: if rhs.type.is_array:
array_length = rhs.type.size array_length = rhs.type.size
self.generate_slice_guard_code(code, array_length) self.generate_slice_guard_code(code, array_length)
else: else:
error(self.pos, array_length = '%s - %s' % (self.stop_code(), start_offset)
"Slice assignments from pointers are not yet supported.")
# FIXME: fix the array size according to start/stop def copy_carray(dst, src, item_type, start, count, depth):
array_length = self.base.type.size var_name = Naming.quick_temp_cname
for i in range(array_length): if depth:
code.putln("%s[%s%s] = %s[%d];" % ( var_name += str(depth)
self.base.result(), start_offset, i, dst_item, src_item = '{dst}[{i}+{start}] = {src}[{i}]'.format(
rhs.result(), i)) src=src,
dst=dst,
start=start,
i=var_name
).split(' = ')
code.putln('{')
code.putln('Py_ssize_t %s;' % var_name)
code.put('for ({i}=0; {i} < {count}; {i}++) '.format(
i=var_name,
count=count))
if item_type.is_array:
copy_carray(dst_item, src_item, item_type.base_type, 0, item_type.size, depth + 1)
else:
code.putln('%s = %s;' % (dst_item, src_item))
code.putln('}')
copy_carray(self.base.result(), rhs.result(), rhs.type.base_type,
start_offset, array_length, 0)
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code) self.free_subexpr_temps(code)
rhs.generate_disposal_code(code) rhs.generate_disposal_code(code)
...@@ -4155,47 +4173,77 @@ class SliceIndexNode(ExprNode): ...@@ -4155,47 +4173,77 @@ class SliceIndexNode(ExprNode):
if not self.base.type.is_array: if not self.base.type.is_array:
return return
slice_size = self.base.type.size slice_size = self.base.type.size
try:
total_length = slice_size = int(slice_size)
except ValueError:
total_length = None
start = stop = None start = stop = None
if self.stop: if self.stop:
stop = self.stop.result() stop = self.stop.result()
try: try:
stop = int(stop) stop = int(stop)
if stop < 0: if stop < 0:
slice_size = self.base.type.size + stop if total_length is None:
slice_size = '%s + %d' % (slice_size, stop)
else:
slice_size += stop
else: else:
slice_size = stop slice_size = stop
stop = None stop = None
except ValueError: except ValueError:
pass pass
if self.start: if self.start:
start = self.start.result() start = self.start.result()
try: try:
start = int(start) start = int(start)
if start < 0: if start < 0:
start = self.base.type.size + start if total_length is None:
slice_size -= start start = '%s + %d' % (self.base.type.size, start)
else:
start += total_length
if isinstance(slice_size, (int, long)):
slice_size -= start
else:
slice_size = '%s - (%s)' % (slice_size, start)
start = None start = None
except ValueError: except ValueError:
pass pass
check = None
if slice_size < 0: runtime_check = None
if target_size > 0: compile_time_check = False
try:
int_target_size = int(target_size)
except ValueError:
int_target_size = None
else:
compile_time_check = isinstance(slice_size, (int, long))
if compile_time_check and slice_size < 0:
if int_target_size > 0:
error(self.pos, "Assignment to empty slice.") error(self.pos, "Assignment to empty slice.")
elif start is None and stop is None: elif compile_time_check and start is None and stop is None:
# we know the exact slice length # we know the exact slice length
if target_size != slice_size: if int_target_size != slice_size:
error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % ( error(self.pos, "Assignment to slice of wrong length, expected %s, got %s" % (
slice_size, target_size)) slice_size, target_size))
elif start is not None: elif start is not None:
if stop is None: if stop is None:
stop = slice_size stop = slice_size
check = "(%s)-(%s)" % (stop, start) runtime_check = "(%s)-(%s)" % (stop, start)
else: # stop is not None: elif stop is not None:
check = stop runtime_check = stop
if check: else:
code.putln("if (unlikely((%s) != %d)) {" % (check, target_size)) runtime_check = slice_size
code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d", (Py_ssize_t)%d, (Py_ssize_t)(%s));' % (
target_size, check)) if runtime_check:
code.putln("if (unlikely((%s) != (%s))) {" % (runtime_check, target_size))
code.putln(
'PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length,'
' expected %%" CYTHON_FORMAT_SSIZE_T "d, got %%" CYTHON_FORMAT_SSIZE_T "d",'
' (Py_ssize_t)(%s), (Py_ssize_t)(%s));' % (
target_size, runtime_check))
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
code.putln("}") code.putln("}")
...@@ -5736,7 +5784,7 @@ class AttributeNode(ExprNode): ...@@ -5736,7 +5784,7 @@ class AttributeNode(ExprNode):
def is_lvalue(self): def is_lvalue(self):
if self.obj: if self.obj:
return not self.type.is_array return True
else: else:
return NameNode.is_lvalue(self) return NameNode.is_lvalue(self)
...@@ -6590,7 +6638,7 @@ class ListNode(SequenceNode): ...@@ -6590,7 +6638,7 @@ class ListNode(SequenceNode):
error(self.pos, "Cannot coerce list to type '%s'" % dst_type) error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
elif self.mult_factor: elif self.mult_factor:
error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type) error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type)
elif dst_type.is_ptr and dst_type.base_type is not PyrexTypes.c_void_type: elif (dst_type.is_array or dst_type.is_ptr) and dst_type.base_type is not PyrexTypes.c_void_type:
base_type = dst_type.base_type base_type = dst_type.base_type
self.type = PyrexTypes.CArrayType(base_type, len(self.args)) self.type = PyrexTypes.CArrayType(base_type, len(self.args))
for i in range(len(self.original_args)): for i in range(len(self.original_args)):
...@@ -6631,13 +6679,14 @@ class ListNode(SequenceNode): ...@@ -6631,13 +6679,14 @@ class ListNode(SequenceNode):
if self.type.is_array: if self.type.is_array:
# To be valid C++, we must allocate the memory on the stack # To be valid C++, we must allocate the memory on the stack
# manually and be sure not to reuse it for something else. # manually and be sure not to reuse it for something else.
# Yes, this means that we leak a temp array variable.
pass pass
else: else:
SequenceNode.release_temp_result(self, env) SequenceNode.release_temp_result(self, env)
def calculate_constant_result(self): def calculate_constant_result(self):
if self.mult_factor: if self.mult_factor:
raise ValueError() # may exceed the compile time memory raise ValueError() # may exceed the compile time memory
self.constant_result = [ self.constant_result = [
arg.constant_result for arg in self.args] arg.constant_result for arg in self.args]
...@@ -6655,15 +6704,15 @@ class ListNode(SequenceNode): ...@@ -6655,15 +6704,15 @@ class ListNode(SequenceNode):
elif self.type.is_array: elif self.type.is_array:
for i, arg in enumerate(self.args): for i, arg in enumerate(self.args):
code.putln("%s[%s] = %s;" % ( code.putln("%s[%s] = %s;" % (
self.result(), self.result(),
i, i,
arg.result())) arg.result()))
elif self.type.is_struct: elif self.type.is_struct:
for arg, member in zip(self.args, self.type.scope.var_entries): for arg, member in zip(self.args, self.type.scope.var_entries):
code.putln("%s.%s = %s;" % ( code.putln("%s.%s = %s;" % (
self.result(), self.result(),
member.cname, member.cname,
arg.result())) arg.result()))
else: else:
raise InternalError("List type never specified") raise InternalError("List type never specified")
...@@ -11178,6 +11227,7 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -11178,6 +11227,7 @@ class CoerceToPyTypeNode(CoercionNode):
# to a Python object. # to a Python object.
type = py_object_type type = py_object_type
target_type = py_object_type
is_temp = 1 is_temp = 1
def __init__(self, arg, env, type=py_object_type): def __init__(self, arg, env, type=py_object_type):
...@@ -11197,22 +11247,17 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -11197,22 +11247,17 @@ class CoerceToPyTypeNode(CoercionNode):
self.type = unicode_type self.type = unicode_type
elif arg.type.is_complex: elif arg.type.is_complex:
self.type = Builtin.complex_type self.type = Builtin.complex_type
self.target_type = self.type
elif arg.type.is_string or arg.type.is_cpp_string: elif arg.type.is_string or arg.type.is_cpp_string:
if (type not in (bytes_type, bytearray_type) if (type not in (bytes_type, bytearray_type)
and not env.directives['c_string_encoding']): and not env.directives['c_string_encoding']):
error(arg.pos, error(arg.pos,
"default encoding required for conversion from '%s' to '%s'" % "default encoding required for conversion from '%s' to '%s'" %
(arg.type, type)) (arg.type, type))
self.type = type self.type = self.target_type = type
else: else:
# FIXME: check that the target type and the resulting type are compatible # FIXME: check that the target type and the resulting type are compatible
pass self.target_type = type
if arg.type.is_memoryviewslice:
# Register utility codes at this point
arg.type.get_to_py_function(env, arg)
self.env = env
gil_message = "Converting to Python object" gil_message = "Converting to Python object"
...@@ -11240,21 +11285,11 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -11240,21 +11285,11 @@ class CoerceToPyTypeNode(CoercionNode):
return self return self
def generate_result_code(self, code): def generate_result_code(self, code):
arg_type = self.arg.type code.putln('%s; %s' % (
if arg_type.is_memoryviewslice: self.arg.type.to_py_call_code(
funccall = arg_type.get_to_py_function(self.env, self.arg) self.arg.result(),
else: self.result(),
func = arg_type.to_py_function self.target_type),
if arg_type.is_string or arg_type.is_cpp_string:
if self.type in (bytes_type, str_type, unicode_type):
func = func.replace("Object", self.type.name.title(), 1)
elif self.type is bytearray_type:
func = func.replace("Object", "ByteArray", 1)
funccall = "%s(%s)" % (func, self.arg.result())
code.putln('%s = %s; %s' % (
self.result(),
funccall,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
...@@ -11322,18 +11357,11 @@ class CoerceFromPyTypeNode(CoercionNode): ...@@ -11322,18 +11357,11 @@ class CoerceFromPyTypeNode(CoercionNode):
return self return self
def is_ephemeral(self): def is_ephemeral(self):
return self.type.is_ptr and self.arg.is_ephemeral() return (self.type.is_ptr and not self.type.is_array) and self.arg.is_ephemeral()
def generate_result_code(self, code): def generate_result_code(self, code):
function = self.type.from_py_function code.putln(self.type.from_py_call_code(
operand = self.arg.py_result() self.arg.py_result(), self.result(), self.pos, code))
rhs = "%s(%s)" % (function, operand)
if self.type.is_enum:
rhs = typecast(self.type, c_long_type, rhs)
code.putln('%s = %s; %s' % (
self.result(),
rhs,
code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
if self.type.is_pyobject: if self.type.is_pyobject:
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
......
...@@ -1312,10 +1312,9 @@ class CVarDefNode(StatNode): ...@@ -1312,10 +1312,9 @@ class CVarDefNode(StatNode):
return return
if type.is_cfunction: if type.is_cfunction:
self.entry = dest_scope.declare_cfunction(name, type, declarator.pos, self.entry = dest_scope.declare_cfunction(name, type, declarator.pos,
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd, cname=cname, visibility=self.visibility, in_pxd=self.in_pxd,
api = self.api, modifiers = self.modifiers) api=self.api, modifiers=self.modifiers, overridable=self.overridable)
if self.entry is not None: if self.entry is not None:
self.entry.is_overridable = self.overridable
self.entry.directive_locals = copy.copy(self.directive_locals) self.entry.directive_locals = copy.copy(self.directive_locals)
if 'staticmethod' in env.directives: if 'staticmethod' in env.directives:
type.is_static_method = True type.is_static_method = True
...@@ -2274,8 +2273,9 @@ class CFuncDefNode(FuncDefNode): ...@@ -2274,8 +2273,9 @@ class CFuncDefNode(FuncDefNode):
type.is_static_method = self.is_static_method type.is_static_method = self.is_static_method
self.entry = env.declare_cfunction( self.entry = env.declare_cfunction(
name, type, self.pos, name, type, self.pos,
cname = cname, visibility = self.visibility, api = self.api, cname=cname, visibility=self.visibility, api=self.api,
defining = self.body is not None, modifiers = self.modifiers) defining=self.body is not None, modifiers=self.modifiers,
overridable=self.overridable)
self.entry.inline_func_in_pxd = self.inline_in_pxd self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type self.return_type = type.return_type
if self.return_type.is_array and self.visibility != 'extern': if self.return_type.is_array and self.visibility != 'extern':
...@@ -4776,14 +4776,20 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4776,14 +4776,20 @@ class SingleAssignmentNode(AssignmentNode):
self.lhs.memslice_broadcast = True self.lhs.memslice_broadcast = True
self.rhs.memslice_broadcast = True self.rhs.memslice_broadcast = True
is_index_node = isinstance(self.lhs, ExprNodes.IndexNode) if (self.lhs.is_subscript and not self.rhs.type.is_memoryviewslice and
if (is_index_node and not self.rhs.type.is_memoryviewslice and (self.lhs.memslice_slice or self.lhs.is_memslice_copy) and
(self.lhs.memslice_slice or self.lhs.is_memslice_copy) and (self.lhs.type.dtype.assignable_from(self.rhs.type) or
(self.lhs.type.dtype.assignable_from(self.rhs.type) or self.rhs.type.is_pyobject)):
self.rhs.type.is_pyobject)):
# scalar slice assignment # scalar slice assignment
self.lhs.is_memslice_scalar_assignment = True self.lhs.is_memslice_scalar_assignment = True
dtype = self.lhs.type.dtype dtype = self.lhs.type.dtype
elif self.lhs.type.is_array:
if not isinstance(self.lhs, ExprNodes.SliceIndexNode):
# cannot assign to C array, only to its full slice
self.lhs = ExprNodes.SliceIndexNode(
self.lhs.pos, base=self.lhs, start=None, stop=None)
self.lhs = self.lhs.analyse_target_types(env)
dtype = self.lhs.type
else: else:
dtype = self.lhs.type dtype = self.lhs.type
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import re
import copy import copy
import re import re
...@@ -430,6 +431,21 @@ class CTypedefType(BaseType): ...@@ -430,6 +431,21 @@ class CTypedefType(BaseType):
# delegation # delegation
return self.typedef_base_type.create_from_py_utility_code(env) return self.typedef_base_type.create_from_py_utility_code(env)
def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None):
if to_py_function is None:
to_py_function = self.to_py_function
return self.typedef_base_type.to_py_call_code(
source_code, result_code, result_type, to_py_function)
def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None):
if from_py_function is None:
from_py_function = self.from_py_function
if error_condition is None:
error_condition = self.error_condition(result_code)
return self.typedef_base_type.from_py_call_code(
source_code, result_code, error_pos, code, from_py_function, error_condition)
def overflow_check_binop(self, binop, env, const_rhs=False): def overflow_check_binop(self, binop, env, const_rhs=False):
env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) env.use_utility_code(UtilityCode.load("Common", "Overflow.c"))
type = self.empty_declaration_code() type = self.empty_declaration_code()
...@@ -703,16 +719,18 @@ class MemoryViewSliceType(PyrexType): ...@@ -703,16 +719,18 @@ class MemoryViewSliceType(PyrexType):
return True return True
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
self._dtype_to_py_func, self._dtype_from_py_func = self.dtype_object_conversion_funcs(env)
return True return True
def get_to_py_function(self, env, obj): def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None):
to_py_func, from_py_func = self.dtype_object_conversion_funcs(env) assert self._dtype_to_py_func
to_py_func = "(PyObject *(*)(char *)) " + to_py_func assert self._dtype_from_py_func
from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func
to_py_func = "(PyObject *(*)(char *)) " + self._dtype_to_py_func
from_py_func = "(int (*)(char *, PyObject *)) " + self._dtype_from_py_func
tup = (obj.result(), self.ndim, to_py_func, from_py_func, tup = (result_code, source_code, self.ndim, to_py_func, from_py_func, self.dtype.is_pyobject)
self.dtype.is_pyobject) return "%s = __pyx_memoryview_fromslice(%s, %s, %s, %s, %d);" % tup
return "__pyx_memoryview_fromslice(%s, %s, %s, %s, %d);" % tup
def dtype_object_conversion_funcs(self, env): def dtype_object_conversion_funcs(self, env):
get_function = "__pyx_memview_get_%s" % self.dtype_name get_function = "__pyx_memview_get_%s" % self.dtype_name
...@@ -1225,6 +1243,29 @@ class CType(PyrexType): ...@@ -1225,6 +1243,29 @@ class CType(PyrexType):
else: else:
return 0 return 0
def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None):
func = self.to_py_function if to_py_function is None else to_py_function
assert func
if self.is_string or self.is_cpp_string:
if result_type.is_builtin_type:
result_type_name = result_type.name
if result_type_name in ('bytes', 'str', 'unicode'):
func = func.replace("Object", result_type_name.title(), 1)
elif result_type_name == 'bytearray':
func = func.replace("Object", "ByteArray", 1)
return '%s = %s(%s)' % (
result_code,
func,
source_code or 'NULL')
def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None):
return '%s = %s(%s); %s' % (
result_code,
from_py_function or self.from_py_function,
source_code,
code.error_goto_if(error_condition or self.error_condition(result_code), error_pos))
class CConstType(BaseType): class CConstType(BaseType):
...@@ -1259,6 +1300,9 @@ class CConstType(BaseType): ...@@ -1259,6 +1300,9 @@ class CConstType(BaseType):
def deduce_template_params(self, actual): def deduce_template_params(self, actual):
return self.const_base_type.deduce_template_params(actual) return self.const_base_type.deduce_template_params(actual)
def can_coerce_to_pyobject(self, env):
return self.const_base_type.can_coerce_to_pyobject(env)
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
if self.const_base_type.create_to_py_utility_code(env): if self.const_base_type.create_to_py_utility_code(env):
self.to_py_function = self.const_base_type.to_py_function self.to_py_function = self.const_base_type.to_py_function
...@@ -1315,6 +1359,7 @@ class CVoidType(CType): ...@@ -1315,6 +1359,7 @@ class CVoidType(CType):
# #
is_void = 1 is_void = 1
to_py_function = "__Pyx_void_to_None"
def __repr__(self): def __repr__(self):
return "<CVoidType>" return "<CVoidType>"
...@@ -1427,6 +1472,9 @@ class CIntType(CNumericType): ...@@ -1427,6 +1472,9 @@ class CIntType(CNumericType):
from_py_function = None from_py_function = None
exception_value = -1 exception_value = -1
def can_coerce_to_pyobject(self, env):
return True
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
if type(self).to_py_function is None: if type(self).to_py_function is None:
self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name() self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name()
...@@ -1772,6 +1820,9 @@ class CComplexType(CNumericType): ...@@ -1772,6 +1820,9 @@ class CComplexType(CNumericType):
is_float = self.real_type.is_float)) is_float = self.real_type.is_float))
return True return True
def can_coerce_to_pyobject(self, env):
return True
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
env.use_utility_code(complex_real_imag_utility_code) env.use_utility_code(complex_real_imag_utility_code)
env.use_utility_code(complex_to_py_utility_code) env.use_utility_code(complex_to_py_utility_code)
...@@ -2102,15 +2153,16 @@ class CPointerBaseType(CType): ...@@ -2102,15 +2153,16 @@ class CPointerBaseType(CType):
self.is_pyunicode_ptr = 1 self.is_pyunicode_ptr = 1
if self.is_string and not base_type.is_error: if self.is_string and not base_type.is_error:
if base_type.signed: if base_type.signed == 2:
self.to_py_function = "__Pyx_PyObject_FromCString"
if self.is_ptr:
self.from_py_function = "__Pyx_PyObject_AsSString"
elif base_type.signed:
self.to_py_function = "__Pyx_PyObject_FromString" self.to_py_function = "__Pyx_PyObject_FromString"
if self.is_ptr: if self.is_ptr:
if base_type.signed == 2: self.from_py_function = "__Pyx_PyObject_AsString"
self.from_py_function = "__Pyx_PyObject_AsSString"
else:
self.from_py_function = "__Pyx_PyObject_AsString"
else: else:
self.to_py_function = "__Pyx_PyObject_FromUString" self.to_py_function = "__Pyx_PyObject_FromCString"
if self.is_ptr: if self.is_ptr:
self.from_py_function = "__Pyx_PyObject_AsUString" self.from_py_function = "__Pyx_PyObject_AsUString"
self.exception_value = "NULL" self.exception_value = "NULL"
...@@ -2139,6 +2191,7 @@ class CArrayType(CPointerBaseType): ...@@ -2139,6 +2191,7 @@ class CArrayType(CPointerBaseType):
# size integer or None Number of elements # size integer or None Number of elements
is_array = 1 is_array = 1
to_tuple_function = None
def __init__(self, base_type, size): def __init__(self, base_type, size):
super(CArrayType, self).__init__(base_type) super(CArrayType, self).__init__(base_type)
...@@ -2161,8 +2214,12 @@ class CArrayType(CPointerBaseType): ...@@ -2161,8 +2214,12 @@ class CArrayType(CPointerBaseType):
or other_type is error_type) or other_type is error_type)
def assignable_from_resolved_type(self, src_type): def assignable_from_resolved_type(self, src_type):
# Can't assign to a variable of an array type # C arrays are assigned by value, either Python containers or C arrays/pointers
return 0 if src_type.is_pyobject:
return True
if src_type.is_ptr or src_type.is_array:
return self.base_type.assignable_from(src_type.base_type)
return False
def element_ptr_type(self): def element_ptr_type(self):
return c_ptr_type(self.base_type) return c_ptr_type(self.base_type)
...@@ -2190,7 +2247,7 @@ class CArrayType(CPointerBaseType): ...@@ -2190,7 +2247,7 @@ class CArrayType(CPointerBaseType):
if base_type == self.base_type: if base_type == self.base_type:
return self return self
else: else:
return CArrayType(base_type) return CArrayType(base_type, self.size)
def deduce_template_params(self, actual): def deduce_template_params(self, actual):
if isinstance(actual, CArrayType): if isinstance(actual, CArrayType):
...@@ -2198,6 +2255,74 @@ class CArrayType(CPointerBaseType): ...@@ -2198,6 +2255,74 @@ class CArrayType(CPointerBaseType):
else: else:
return None return None
def create_to_py_utility_code(self, env):
if self.to_py_function is not None:
return self.to_py_function
if not self.base_type.create_to_py_utility_code(env):
return False
base_type = self.base_type.declaration_code("", pyrex=1)
safe_typename = re.sub('[^a-zA-Z0-9]', '__', base_type)
to_py_function = "__Pyx_carray_to_py_%s" % safe_typename
to_tuple_function = "__Pyx_carray_to_tuple_%s" % safe_typename
from .UtilityCode import CythonUtilityCode
context = {
'cname': to_py_function,
'to_tuple_cname': to_tuple_function,
'base_type': base_type,
}
env.use_utility_code(CythonUtilityCode.load(
"carray.to_py", "CConvert.pyx",
outer_module_scope=env.global_scope(), # need access to types declared in module
context=context, compiler_directives=dict(env.global_scope().directives)))
self.to_tuple_function = to_tuple_function
self.to_py_function = to_py_function
return True
def to_py_call_code(self, source_code, result_code, result_type, to_py_function=None):
func = self.to_py_function if to_py_function is None else to_py_function
if self.is_string or self.is_pyunicode_ptr:
return '%s = %s(%s)' % (
result_code,
func,
source_code)
target_is_tuple = result_type.is_builtin_type and result_type.name == 'tuple'
return '%s = %s(%s, %s)' % (
result_code,
self.to_tuple_function if target_is_tuple else func,
source_code,
self.size)
def create_from_py_utility_code(self, env):
if self.from_py_function is not None:
return self.from_py_function
if not self.base_type.create_from_py_utility_code(env):
return False
base_type = self.base_type.declaration_code("", pyrex=1)
safe_typename = re.sub('[^a-zA-Z0-9]', '__', base_type)
from_py_function = "__Pyx_carray_from_py_%s" % safe_typename
from .UtilityCode import CythonUtilityCode
context = {
'cname': from_py_function,
'base_type': base_type,
}
env.use_utility_code(CythonUtilityCode.load(
"carray.from_py", "CConvert.pyx",
outer_module_scope=env.global_scope(), # need access to types declared in module
context=context, compiler_directives=dict(env.global_scope().directives)))
self.from_py_function = from_py_function
return True
def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None):
call_code = "%s(%s, %s, %s)" % (
from_py_function or self.from_py_function,
source_code, result_code, self.size)
return code.error_goto_if_neg(call_code, error_pos)
class CPtrType(CPointerBaseType): class CPtrType(CPointerBaseType):
# base_type CType Reference type # base_type CType Reference type
...@@ -2273,6 +2398,7 @@ class CPtrType(CPointerBaseType): ...@@ -2273,6 +2398,7 @@ class CPtrType(CPointerBaseType):
return self.base_type.find_cpp_operation_type(operator, operand_type) return self.base_type.find_cpp_operation_type(operator, operand_type)
return None return None
class CNullPtrType(CPtrType): class CNullPtrType(CPtrType):
is_null_ptr = 1 is_null_ptr = 1
...@@ -2404,9 +2530,8 @@ class CFuncType(CType): ...@@ -2404,9 +2530,8 @@ class CFuncType(CType):
# is exempt from compatibility checking (the proper check # is exempt from compatibility checking (the proper check
# is performed elsewhere). # is performed elsewhere).
for i in range(as_cmethod, nargs): for i in range(as_cmethod, nargs):
if not self.args[i].type.same_as( if not self.args[i].type.same_as(other_type.args[i].type):
other_type.args[i].type): return 0
return 0
if self.has_varargs != other_type.has_varargs: if self.has_varargs != other_type.has_varargs:
return 0 return 0
if self.optional_arg_count != other_type.optional_arg_count: if self.optional_arg_count != other_type.optional_arg_count:
...@@ -2657,22 +2782,33 @@ class CFuncType(CType): ...@@ -2657,22 +2782,33 @@ class CFuncType(CType):
assert not self.is_fused assert not self.is_fused
specialize_entry(entry, cname) specialize_entry(entry, cname)
def create_to_py_utility_code(self, env): def can_coerce_to_pyobject(self, env):
# FIXME: it seems we're trying to coerce in more cases than we should # duplicating the decisions from create_to_py_utility_code() here avoids writing out unused code
if self.has_varargs or self.optional_arg_count: if self.has_varargs or self.optional_arg_count:
return False return False
if self.to_py_function is not None: if self.to_py_function is not None:
return self.to_py_function return self.to_py_function
for arg in self.args:
if not arg.type.is_pyobject and not arg.type.can_coerce_to_pyobject(env):
return False
if not self.return_type.is_pyobject and not self.return_type.can_coerce_to_pyobject(env):
return False
return True
def create_to_py_utility_code(self, env):
# FIXME: it seems we're trying to coerce in more cases than we should
if self.to_py_function is not None:
return self.to_py_function
if not self.can_coerce_to_pyobject(env):
return False
from .UtilityCode import CythonUtilityCode from .UtilityCode import CythonUtilityCode
import re
safe_typename = re.sub('[^a-zA-Z0-9]', '__', self.declaration_code("", pyrex=1)) safe_typename = re.sub('[^a-zA-Z0-9]', '__', self.declaration_code("", pyrex=1))
to_py_function = "__Pyx_CFunc_%s_to_py" % safe_typename to_py_function = "__Pyx_CFunc_%s_to_py" % safe_typename
for arg in self.args: for arg in self.args:
if not arg.type.is_pyobject and not arg.type.create_from_py_utility_code(env): if not arg.type.is_pyobject and not arg.type.create_from_py_utility_code(env):
return False return False
if not (self.return_type.is_pyobject or self.return_type.is_void or if not self.return_type.is_pyobject and not self.return_type.create_to_py_utility_code(env):
self.return_type.create_to_py_utility_code(env)):
return False return False
def declared_type(ctype): def declared_type(ctype):
...@@ -2719,9 +2855,9 @@ class CFuncType(CType): ...@@ -2719,9 +2855,9 @@ class CFuncType(CType):
} }
# FIXME: directives come from first defining environment and do not adapt for reuse # FIXME: directives come from first defining environment and do not adapt for reuse
env.use_utility_code(CythonUtilityCode.load( env.use_utility_code(CythonUtilityCode.load(
"cfunc.to_py", "CFuncConvert.pyx", "cfunc.to_py", "CConvert.pyx",
outer_module_scope=env.global_scope(), # need access to types declared in module outer_module_scope=env.global_scope(), # need access to types declared in module
context=context, compiler_directives=dict(env.directives))) context=context, compiler_directives=dict(env.global_scope().directives)))
self.to_py_function = to_py_function self.to_py_function = to_py_function
return True return True
...@@ -2871,11 +3007,12 @@ class ToPyStructUtilityCode(object): ...@@ -2871,11 +3007,12 @@ class ToPyStructUtilityCode(object):
requires = None requires = None
def __init__(self, type, forward_decl): def __init__(self, type, forward_decl, env):
self.type = type self.type = type
self.header = "static PyObject* %s(%s)" % (type.to_py_function, self.header = "static PyObject* %s(%s)" % (type.to_py_function,
type.declaration_code('s')) type.declaration_code('s'))
self.forward_decl = forward_decl self.forward_decl = forward_decl
self.env = env
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, ToPyStructUtilityCode) and self.header == other.header return isinstance(other, ToPyStructUtilityCode) and self.header == other.header
...@@ -2896,8 +3033,8 @@ class ToPyStructUtilityCode(object): ...@@ -2896,8 +3033,8 @@ class ToPyStructUtilityCode(object):
code.putln("res = PyDict_New(); if (res == NULL) return NULL;") code.putln("res = PyDict_New(); if (res == NULL) return NULL;")
for member in self.type.scope.var_entries: for member in self.type.scope.var_entries:
nameconst_cname = code.get_py_string_const(member.name, identifier=True) nameconst_cname = code.get_py_string_const(member.name, identifier=True)
code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % ( code.putln("%s; if (member == NULL) goto bad;" % (
member.type.to_py_function, member.cname)) member.type.to_py_call_code('s.%s' % member.cname, 'member', member.type)))
code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % nameconst_cname) code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % nameconst_cname)
code.putln("Py_DECREF(member);") code.putln("Py_DECREF(member);")
code.putln("return res;") code.putln("return res;")
...@@ -2938,9 +3075,8 @@ class CStructOrUnionType(CType): ...@@ -2938,9 +3075,8 @@ class CStructOrUnionType(CType):
self.scope = scope self.scope = scope
self.typedef_flag = typedef_flag self.typedef_flag = typedef_flag
self.is_struct = kind == 'struct' self.is_struct = kind == 'struct'
if self.is_struct: self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname)
self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname)
self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname)
self.exception_check = True self.exception_check = True
self._convert_to_py_code = None self._convert_to_py_code = None
self._convert_from_py_code = None self._convert_from_py_code = None
...@@ -2959,8 +3095,8 @@ class CStructOrUnionType(CType): ...@@ -2959,8 +3095,8 @@ class CStructOrUnionType(CType):
self.to_py_function = None self.to_py_function = None
self._convert_to_py_code = False self._convert_to_py_code = False
return False return False
forward_decl = (self.entry.visibility != 'extern') forward_decl = self.entry.visibility != 'extern' and not self.typedef_flag
self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl) self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl, env)
env.use_utility_code(self._convert_to_py_code) env.use_utility_code(self._convert_to_py_code)
return True return True
...@@ -2980,12 +3116,15 @@ class CStructOrUnionType(CType): ...@@ -2980,12 +3116,15 @@ class CStructOrUnionType(CType):
return False return False
context = dict( context = dict(
struct_type_decl=self.empty_declaration_code(), struct_name=self.name,
var_entries=self.scope.var_entries, var_entries=self.scope.var_entries,
funcname=self.from_py_function, funcname=self.from_py_function,
) )
self._convert_from_py_code = TempitaUtilityCode.load( from .UtilityCode import CythonUtilityCode
"FromPyStructUtility", "TypeConversion.c", context=context) self._convert_from_py_code = CythonUtilityCode.load(
"FromPyStructUtility", "CConvert.pyx",
outer_module_scope=env.global_scope(), # need access to types declared in module
context=context)
env.use_utility_code(self._convert_from_py_code) env.use_utility_code(self._convert_from_py_code)
return True return True
...@@ -3152,7 +3291,8 @@ class CppClassType(CType): ...@@ -3152,7 +3291,8 @@ class CppClassType(CType):
'type': self.cname, 'type': self.cname,
} }
from .UtilityCode import CythonUtilityCode from .UtilityCode import CythonUtilityCode
env.use_utility_code(CythonUtilityCode.load(cls.replace('unordered_', '') + ".from_py", "CppConvert.pyx", context=context)) env.use_utility_code(CythonUtilityCode.load(
cls.replace('unordered_', '') + ".from_py", "CppConvert.pyx", context=context))
self.from_py_function = cname self.from_py_function = cname
return True return True
...@@ -3358,6 +3498,7 @@ class TemplatePlaceholderType(CType): ...@@ -3358,6 +3498,7 @@ class TemplatePlaceholderType(CType):
else: else:
return False return False
class CEnumType(CType): class CEnumType(CType):
# name string # name string
# cname string or None # cname string or None
...@@ -3394,6 +3535,17 @@ class CEnumType(CType): ...@@ -3394,6 +3535,17 @@ class CEnumType(CType):
base_code = public_decl(base_code, dll_linkage) base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code) return self.base_declaration_code(base_code, entity_code)
def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None):
rhs = "%s(%s)" % (
from_py_function or self.from_py_function,
source_code)
return '%s = %s;%s' % (
result_code,
typecast(self, c_long_type, rhs),
' %s' % code.error_goto_if(error_condition or self.error_condition(result_code), error_pos))
class CTupleType(CType): class CTupleType(CType):
# components [PyrexType] # components [PyrexType]
......
...@@ -684,8 +684,8 @@ class Scope(object): ...@@ -684,8 +684,8 @@ class Scope(object):
self.pyfunc_entries.append(entry) self.pyfunc_entries.append(entry)
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', api = 0, in_pxd = 0, cname=None, visibility='private', api=0, in_pxd=0,
defining = 0, modifiers = (), utility_code = None): defining=0, modifiers=(), utility_code=None, overridable=False):
# Add an entry for a C function. # Add an entry for a C function.
if not cname: if not cname:
if visibility != 'private' or api: if visibility != 'private' or api:
...@@ -696,6 +696,9 @@ class Scope(object): ...@@ -696,6 +696,9 @@ class Scope(object):
if entry: if entry:
if visibility != 'private' and visibility != entry.visibility: if visibility != 'private' and visibility != entry.visibility:
warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1) warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
if overridable != entry.is_overridable:
warning(pos, "Function '%s' previously declared as '%s'" % (
name, 'cpdef' if overridable else 'cdef'), 1)
if not entry.type.same_as(type): if not entry.type.same_as(type):
if visibility == 'extern' and entry.visibility == 'extern': if visibility == 'extern' and entry.visibility == 'extern':
can_override = False can_override = False
...@@ -721,6 +724,7 @@ class Scope(object): ...@@ -721,6 +724,7 @@ class Scope(object):
else: else:
entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
entry.func_cname = cname entry.func_cname = cname
entry.is_overridable = overridable
if in_pxd and visibility != 'extern': if in_pxd and visibility != 'extern':
entry.defined_in_pxd = 1 entry.defined_in_pxd = 1
if api: if api:
...@@ -734,6 +738,13 @@ class Scope(object): ...@@ -734,6 +738,13 @@ class Scope(object):
if utility_code: if utility_code:
assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname) assert not entry.utility_code, "duplicate utility code definition in entry %s (%s)" % (name, cname)
entry.utility_code = utility_code entry.utility_code = utility_code
if overridable:
# names of cpdef functions can be used as variables and can be assigned to
var_entry = Entry(name, cname, py_object_type) # FIXME: cname?
var_entry.is_variable = 1
var_entry.is_pyglobal = 1
var_entry.scope = entry.scope
entry.as_variable = var_entry
type.entry = entry type.entry = entry
return entry return entry
...@@ -892,13 +903,12 @@ class BuiltinScope(Scope): ...@@ -892,13 +903,12 @@ class BuiltinScope(Scope):
else: else:
warning(pos, "undeclared name not builtin: %s" % name, 2) warning(pos, "undeclared name not builtin: %s" % name, 2)
def declare_builtin_cfunction(self, name, type, cname, python_equiv = None, def declare_builtin_cfunction(self, name, type, cname, python_equiv=None, utility_code=None):
utility_code = None):
# If python_equiv == "*", the Python equivalent has the same name # If python_equiv == "*", the Python equivalent has the same name
# as the entry, otherwise it has the name specified by python_equiv. # as the entry, otherwise it has the name specified by python_equiv.
name = EncodedString(name) name = EncodedString(name)
entry = self.declare_cfunction(name, type, None, cname, visibility='extern', entry = self.declare_cfunction(name, type, None, cname, visibility='extern',
utility_code = utility_code) utility_code=utility_code)
if python_equiv: if python_equiv:
if python_equiv == "*": if python_equiv == "*":
python_equiv = name python_equiv = name
...@@ -1225,8 +1235,8 @@ class ModuleScope(Scope): ...@@ -1225,8 +1235,8 @@ class ModuleScope(Scope):
return entry return entry
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', api = 0, in_pxd = 0, cname=None, visibility='private', api=0, in_pxd=0,
defining = 0, modifiers = (), utility_code = None): defining=0, modifiers=(), utility_code=None, overridable=False):
# Add an entry for a C function. # Add an entry for a C function.
if not cname: if not cname:
if visibility == 'extern' or (visibility == 'public' and defining): if visibility == 'extern' or (visibility == 'public' and defining):
...@@ -1243,8 +1253,9 @@ class ModuleScope(Scope): ...@@ -1243,8 +1253,9 @@ class ModuleScope(Scope):
entry.func_cname = cname entry.func_cname = cname
entry = Scope.declare_cfunction( entry = Scope.declare_cfunction(
self, name, type, pos, self, name, type, pos,
cname = cname, visibility = visibility, api = api, in_pxd = in_pxd, cname=cname, visibility=visibility, api=api, in_pxd=in_pxd,
defining = defining, modifiers = modifiers, utility_code = utility_code) defining=defining, modifiers=modifiers, utility_code=utility_code,
overridable=overridable)
return entry return entry
def declare_global(self, name, pos): def declare_global(self, name, pos):
...@@ -1683,8 +1694,10 @@ class StructOrUnionScope(Scope): ...@@ -1683,8 +1694,10 @@ class StructOrUnionScope(Scope):
return entry return entry
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', api = 0, in_pxd = 0, cname=None, visibility='private', api=0, in_pxd=0,
defining = 0, modifiers = ()): # currently no utility code ... defining=0, modifiers=(), overridable=False): # currently no utility code ...
if overridable:
error(pos, "C struct/union member cannot be declared 'cpdef'")
return self.declare_var(name, type, pos, return self.declare_var(name, type, pos,
cname=cname, visibility=visibility) cname=cname, visibility=visibility)
...@@ -1953,8 +1966,8 @@ class CClassScope(ClassScope): ...@@ -1953,8 +1966,8 @@ class CClassScope(ClassScope):
return entry return entry
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', api = 0, in_pxd = 0, cname=None, visibility='private', api=0, in_pxd=0,
defining = 0, modifiers = (), utility_code = None): defining=0, modifiers=(), utility_code=None, overridable=False):
if get_special_method_signature(name) and not self.parent_type.is_builtin_type: if get_special_method_signature(name) and not self.parent_type.is_builtin_type:
error(pos, "Special methods must be declared with 'def', not 'cdef'") error(pos, "Special methods must be declared with 'def', not 'cdef'")
args = type.args args = type.args
...@@ -1989,8 +2002,7 @@ class CClassScope(ClassScope): ...@@ -1989,8 +2002,7 @@ class CClassScope(ClassScope):
error(pos, error(pos,
"C method '%s' not previously declared in definition part of" "C method '%s' not previously declared in definition part of"
" extension type" % name) " extension type" % name)
entry = self.add_cfunction(name, type, pos, cname, entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
visibility, modifiers)
if defining: if defining:
entry.func_cname = self.mangle(Naming.func_prefix, name) entry.func_cname = self.mangle(Naming.func_prefix, name)
entry.utility_code = utility_code entry.utility_code = utility_code
...@@ -2020,7 +2032,7 @@ class CClassScope(ClassScope): ...@@ -2020,7 +2032,7 @@ class CClassScope(ClassScope):
# equivalent that must be accessible to support bound methods # equivalent that must be accessible to support bound methods
name = EncodedString(name) name = EncodedString(name)
entry = self.declare_cfunction(name, type, None, cname, visibility='extern', entry = self.declare_cfunction(name, type, None, cname, visibility='extern',
utility_code = utility_code) utility_code=utility_code)
var_entry = Entry(name, name, py_object_type) var_entry = Entry(name, name, py_object_type)
var_entry.is_variable = 1 var_entry.is_variable = 1
var_entry.is_builtin = 1 var_entry.is_builtin = 1
...@@ -2127,40 +2139,10 @@ class CppClassScope(Scope): ...@@ -2127,40 +2139,10 @@ class CppClassScope(Scope):
"C++ class member cannot be a Python object") "C++ class member cannot be a Python object")
return entry return entry
def check_base_default_constructor(self, pos):
# Look for default constructors in all base classes.
if self.default_constructor is None:
entry = self.lookup(self.name)
if not entry.type.base_classes:
self.default_constructor = True
return
for base_class in entry.type.base_classes:
if base_class is PyrexTypes.error_type:
continue
temp_entry = base_class.scope.lookup_here("<init>")
found = False
if temp_entry is None:
continue
for alternative in temp_entry.all_alternatives():
type = alternative.type
if type.is_ptr:
type = type.base_type
if not type.args:
found = True
break
if not found:
self.default_constructor = temp_entry.scope.name
error(pos, "no matching function for call to " \
"%s::%s()" % (temp_entry.scope.name, temp_entry.scope.name))
elif not self.default_constructor:
error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor))
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'extern', api = 0, in_pxd = 0, cname=None, visibility='extern', api=0, in_pxd=0,
defining = 0, modifiers = (), utility_code = None): defining=0, modifiers=(), utility_code=None, overridable=False):
if name in (self.name.split('::')[-1], '__init__') and cname is None: if name in (self.name.split('::')[-1], '__init__') and cname is None:
self.check_base_default_constructor(pos)
cname = self.type.cname cname = self.type.cname
name = '<init>' name = '<init>'
type.return_type = PyrexTypes.InvisibleVoidType() type.return_type = PyrexTypes.InvisibleVoidType()
...@@ -2197,9 +2179,9 @@ class CppClassScope(Scope): ...@@ -2197,9 +2179,9 @@ class CppClassScope(Scope):
for base_entry in base_scope.cfunc_entries: for base_entry in base_scope.cfunc_entries:
entry = self.declare_cfunction(base_entry.name, base_entry.type, entry = self.declare_cfunction(base_entry.name, base_entry.type,
base_entry.pos, base_entry.cname, base_entry.pos, base_entry.cname,
base_entry.visibility, 0, base_entry.visibility, api=0,
modifiers = base_entry.func_modifiers, modifiers=base_entry.func_modifiers,
utility_code = base_entry.utility_code) utility_code=base_entry.utility_code)
entry.is_inherited = 1 entry.is_inherited = 1
def specialize(self, values, type_entry): def specialize(self, values, type_entry):
...@@ -2218,7 +2200,7 @@ class CppClassScope(Scope): ...@@ -2218,7 +2200,7 @@ class CppClassScope(Scope):
e.type.specialize(values), e.type.specialize(values),
e.pos, e.pos,
e.cname, e.cname,
utility_code = e.utility_code) utility_code=e.utility_code)
else: else:
scope.declare_var(entry.name, scope.declare_var(entry.name,
entry.type.specialize(values), entry.type.specialize(values),
......
...@@ -91,10 +91,13 @@ class CythonUtilityCode(Code.UtilityCodeBase): ...@@ -91,10 +91,13 @@ class CythonUtilityCode(Code.UtilityCodeBase):
if isinstance(other, CythonUtilityCode): if isinstance(other, CythonUtilityCode):
return self._equality_params() == other._equality_params() return self._equality_params() == other._equality_params()
else: else:
return False return False
def _equality_params(self): def _equality_params(self):
return self.impl, self.outer_module_scope, self.compiler_directives outer_scope = self.outer_module_scope
while isinstance(outer_scope, NonManglingModuleScope):
outer_scope = outer_scope.outer_scope
return self.impl, outer_scope, self.compiler_directives
def __hash__(self): def __hash__(self):
return hash(self.impl) return hash(self.impl)
......
...@@ -35,49 +35,38 @@ def test_gdb(): ...@@ -35,49 +35,38 @@ def test_gdb():
if have_gdb is not None: if have_gdb is not None:
return have_gdb return have_gdb
have_gdb = False
try: try:
p = subprocess.Popen(['gdb', '-v'], stdout=subprocess.PIPE) p = subprocess.Popen(['gdb', '-nx', '--version'], stdout=subprocess.PIPE)
have_gdb = True
except OSError: except OSError:
# gdb was not installed # gdb not found
have_gdb = False gdb_version = None
else: else:
gdb_version = p.stdout.read().decode('ascii', 'ignore') stdout, _ = p.communicate()
p.wait()
p.stdout.close()
if have_gdb:
# Based on Lib/test/test_gdb.py # Based on Lib/test/test_gdb.py
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)" regex = "GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = list(map(int, re.search(regex, gdb_version).groups())) gdb_version = re.match(regex, stdout.decode('ascii', 'ignore'))
if gdb_version:
gdb_version_number = list(map(int, gdb_version.groups()))
if gdb_version_number >= [7, 2]: if gdb_version_number >= [7, 2]:
python_version_script = tempfile.NamedTemporaryFile(mode='w+') have_gdb = True
try: with tempfile.NamedTemporaryFile(mode='w+') as python_version_script:
python_version_script.write( python_version_script.write(
'python import sys; print("%s %s" % sys.version_info[:2])') 'python import sys; print("%s %s" % sys.version_info[:2])')
python_version_script.flush() python_version_script.flush()
p = subprocess.Popen(['gdb', '-batch', '-x', python_version_script.name], p = subprocess.Popen(['gdb', '-batch', '-x', python_version_script.name],
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
stdout, _ = p.communicate()
try: try:
python_version = p.stdout.read().decode('ascii') internal_python_version = list(map(int, stdout.decode('ascii', 'ignore').split()))
p.wait() if internal_python_version < [2, 6]:
finally: have_gdb = False
p.stdout.close()
try:
python_version_number = list(map(int, python_version.split()))
except ValueError: except ValueError:
have_gdb = False have_gdb = False
finally:
python_version_script.close() if not have_gdb:
warnings.warn('Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6')
# Be Python 3 compatible
if (not have_gdb
or gdb_version_number < [7, 2]
or python_version_number < [2, 6]):
warnings.warn(
'Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6')
have_gdb = False
return have_gdb return have_gdb
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# than the standard C cast operator which can be written "<T>(expression)" in # than the standard C cast operator which can be written "<T>(expression)" in
# Cython. # Cython.
cdef extern from *: cdef extern from * nogil:
cdef T dynamic_cast[T](void *) except + # nullptr may also indicate failure cdef T dynamic_cast[T](void *) except + # nullptr may also indicate failure
cdef T static_cast[T](void *) cdef T static_cast[T](void *)
cdef T reinterpret_cast[T](void *) cdef T reinterpret_cast[T](void *)
......
# cython.* namespace for pure mode. # cython.* namespace for pure mode.
__version__ = "0.21.1pre" __version__ = "0.21.1"
# BEGIN shameless copy from Cython/minivect/minitypes.py # BEGIN shameless copy from Cython/minivect/minitypes.py
...@@ -365,6 +365,15 @@ to_repr = { ...@@ -365,6 +365,15 @@ to_repr = {
gs = globals() gs = globals()
# note: cannot simply name the unicode type here as 2to3 gets in the way and replaces it by str
try:
import __builtin__ as builtins
except ImportError: # Py3
import builtins
gs['unicode'] = typedef(getattr(builtins, 'unicode', str), 'unicode')
del builtins
for name in int_types: for name in int_types:
reprname = to_repr(name, name) reprname = to_repr(name, name)
gs[name] = typedef(py_int, reprname) gs[name] = typedef(py_int, reprname)
......
#################### FromPyStructUtility ####################
cdef extern from *:
ctypedef struct PyTypeObject:
char* tp_name
PyTypeObject *Py_TYPE(obj)
bint PyMapping_Check(obj)
object PyErr_Format(exc, const char *format, ...)
@cname("{{funcname}}")
cdef {{struct_name}} {{funcname}}(obj) except *:
cdef {{struct_name}} result
if not PyMapping_Check(obj):
PyErr_Format(TypeError, b"Expected %.16s, got %.200s", b"a mapping", Py_TYPE(obj).tp_name)
{{for member in var_entries:}}
try:
value = obj['{{member.name}}']
except KeyError:
raise ValueError("No value specified for struct attribute '{{member.name}}'")
result.{{member.cname}} = value
{{endfor}}
return result
#################### cfunc.to_py ####################
@cname("{{cname}}")
cdef object {{cname}}({{return_type.ctype}} (*f)({{ ', '.join(arg.type_cname for arg in args) }}) {{except_clause}}):
def wrap({{ ', '.join('{arg.ctype} {arg.name}'.format(arg=arg) for arg in args) }}):
"""wrap({{', '.join(('{arg.name}: {arg.type_displayname}'.format(arg=arg) if arg.type_displayname else arg.name) for arg in args)}}){{if return_type.type_displayname}} -> {{return_type.type_displayname}}{{endif}}"""
{{'' if return_type.type.is_void else 'return '}}f({{ ', '.join(arg.name for arg in args) }})
return wrap
#################### carray.from_py ####################
cdef extern from *:
object PyErr_Format(exc, const char *format, ...)
@cname("{{cname}}")
cdef int {{cname}}(object o, {{base_type}} *v, Py_ssize_t length) except -1:
cdef Py_ssize_t i = length
try:
i = len(o)
except (TypeError, OverflowError):
pass
if i == length:
for i, item in enumerate(o):
if i >= length:
break
v[i] = item
else:
i += 1 # convert index to length
if i == length:
return 0
PyErr_Format(
IndexError,
("too many values found during array assignment, expected %zd"
if i >= length else
"not enough values found during array assignment, expected %zd, got %zd"),
length, i)
#################### carray.to_py ####################
cdef extern from *:
void Py_INCREF(object o)
tuple PyTuple_New(Py_ssize_t size)
list PyList_New(Py_ssize_t size)
void PyTuple_SET_ITEM(object p, Py_ssize_t pos, object o)
void PyList_SET_ITEM(object p, Py_ssize_t pos, object o)
@cname("{{cname}}")
cdef inline list {{cname}}({{base_type}} *v, Py_ssize_t length):
cdef size_t i
cdef object value
l = PyList_New(length)
for i in range(<size_t>length):
value = v[i]
Py_INCREF(value)
PyList_SET_ITEM(l, i, value)
return l
@cname("{{to_tuple_cname}}")
cdef inline tuple {{to_tuple_cname}}({{base_type}} *v, Py_ssize_t length):
cdef size_t i
cdef object value
t = PyTuple_New(length)
for i in range(<size_t>length):
value = v[i]
Py_INCREF(value)
PyTuple_SET_ITEM(t, i, value)
return t
#################### cfunc.to_py ####################
@cname("{{cname}}")
cdef object {{cname}}({{return_type.ctype}} (*f)({{ ', '.join(arg.type_cname for arg in args) }}) {{except_clause}}):
def wrap({{ ', '.join('{arg.ctype} {arg.name}'.format(arg=arg) for arg in args) }}):
"""wrap({{', '.join(('{arg.name}: {arg.type_displayname}'.format(arg=arg) if arg.type_displayname else arg.name) for arg in args)}}){{if return_type.type_displayname}} -> {{return_type.type_displayname}}{{endif}}"""
{{'' if return_type.type.is_void else 'return '}}f({{ ', '.join(arg.name for arg in args) }})
return wrap
...@@ -587,7 +587,7 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject ...@@ -587,7 +587,7 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject
if (size == 0) if (size == 0)
return (*meth)(self, NULL); return (*meth)(self, NULL);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)", "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)",
f->m_ml->ml_name, size); f->m_ml->ml_name, size);
return NULL; return NULL;
} }
...@@ -598,7 +598,7 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject ...@@ -598,7 +598,7 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject
if (size == 1) if (size == 1)
return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); return (*meth)(self, PyTuple_GET_ITEM(arg, 0));
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)", "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)",
f->m_ml->ml_name, size); f->m_ml->ml_name, size);
return NULL; return NULL;
} }
......
...@@ -215,6 +215,8 @@ static CYTHON_INLINE float __PYX_NAN() { ...@@ -215,6 +215,8 @@ static CYTHON_INLINE float __PYX_NAN() {
} }
#endif #endif
#define __Pyx_void_to_None(void_result) (void_result, Py_INCREF(Py_None), Py_None)
// Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor // Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor
#ifdef __cplusplus #ifdef __cplusplus
template<typename T> template<typename T>
......
...@@ -32,11 +32,11 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); ...@@ -32,11 +32,11 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*);
#define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) #define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s))
#define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) #define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s))
#define __Pyx_PyObject_FromUString(s) __Pyx_PyObject_FromString((const char*)s) #define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s)
#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((const char*)s) #define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s)
#define __Pyx_PyByteArray_FromUString(s) __Pyx_PyByteArray_FromString((const char*)s) #define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s)
#define __Pyx_PyStr_FromUString(s) __Pyx_PyStr_FromString((const char*)s) #define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s)
#define __Pyx_PyUnicode_FromUString(s) __Pyx_PyUnicode_FromString((const char*)s) #define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s)
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
...@@ -309,42 +309,6 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { ...@@ -309,42 +309,6 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
return PyInt_FromSize_t(ival); return PyInt_FromSize_t(ival);
} }
/////////////// FromPyStructUtility.proto ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyStructUtility ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject * o) {
{{struct_type_decl}} result;
PyObject *value = NULL;
if (!PyMapping_Check(o)) {
PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "a mapping", Py_TYPE(o)->tp_name);
goto bad;
}
{{for member in var_entries:}}
{{py:attr = "result." + member.cname}}
value = PyObject_GetItem(o, PYIDENT("{{member.name}}"));
if (!value) {
PyErr_Format(PyExc_ValueError, \
"No value specified for struct attribute '%.{{max(200, len(member.name))}}s'", "{{member.name}}");
goto bad;
}
{{attr}} = {{member.type.from_py_function}}(value);
if ({{member.type.error_condition(attr)}})
goto bad;
Py_DECREF(value);
{{endfor}}
return result;
bad:
Py_XDECREF(value);
return result;
}
/////////////// ToPyCTupleUtility.proto /////////////// /////////////// ToPyCTupleUtility.proto ///////////////
...@@ -395,6 +359,7 @@ bad: ...@@ -395,6 +359,7 @@ bad:
return result; return result;
} }
/////////////// ObjectAsUCS4.proto /////////////// /////////////// ObjectAsUCS4.proto ///////////////
static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*); static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*);
......
...@@ -28,6 +28,7 @@ clean: ...@@ -28,6 +28,7 @@ clean:
@rm -f core */core @rm -f core */core
@rm -f Cython/Compiler/*.c @rm -f Cython/Compiler/*.c
@rm -f Cython/Plex/*.c @rm -f Cython/Plex/*.c
@rm -f Cython/Tempita/*.c
@rm -f Cython/Runtime/refnanny.c @rm -f Cython/Runtime/refnanny.c
@(cd Demos; $(MAKE) clean) @(cd Demos; $(MAKE) clean)
......
docs/_static/cython-logo-light.png

4.68 KB | W: | H:

docs/_static/cython-logo-light.png

4.08 KB | W: | H:

docs/_static/cython-logo-light.png
docs/_static/cython-logo-light.png
docs/_static/cython-logo-light.png
docs/_static/cython-logo-light.png
  • 2-up
  • Swipe
  • Onion skin
docs/_static/cythonlogo.png

4.52 KB | W: | H:

docs/_static/cythonlogo.png

4.09 KB | W: | H:

docs/_static/cythonlogo.png
docs/_static/cythonlogo.png
docs/_static/cythonlogo.png
docs/_static/cythonlogo.png
  • 2-up
  • Swipe
  • Onion skin
docs/src/quickstart/htmlreport.png

50.4 KB | W: | H:

docs/src/quickstart/htmlreport.png

35.4 KB | W: | H:

docs/src/quickstart/htmlreport.png
docs/src/quickstart/htmlreport.png
docs/src/quickstart/htmlreport.png
docs/src/quickstart/htmlreport.png
  • 2-up
  • Swipe
  • Onion skin
docs/src/quickstart/ipython.png

125 KB | W: | H:

docs/src/quickstart/ipython.png

83.2 KB | W: | H:

docs/src/quickstart/ipython.png
docs/src/quickstart/ipython.png
docs/src/quickstart/ipython.png
docs/src/quickstart/ipython.png
  • 2-up
  • Swipe
  • Onion skin
docs/src/quickstart/sage.png

76.4 KB | W: | H:

docs/src/quickstart/sage.png

56.8 KB | W: | H:

docs/src/quickstart/sage.png
docs/src/quickstart/sage.png
docs/src/quickstart/sage.png
docs/src/quickstart/sage.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -158,7 +158,7 @@ Sharing C Functions ...@@ -158,7 +158,7 @@ Sharing C Functions
C functions defined at the top level of a module can be made available via C functions defined at the top level of a module can be made available via
:keyword:`cimport` by putting headers for them in the ``.pxd`` file, for :keyword:`cimport` by putting headers for them in the ``.pxd`` file, for
example,:: example:
:file:`volume.pxd`:: :file:`volume.pxd`::
......
...@@ -1714,7 +1714,7 @@ def main(): ...@@ -1714,7 +1714,7 @@ def main():
action="store_true", default=False, action="store_true", default=False,
help="only compile pyx to c, do not run C compiler or run the tests") help="only compile pyx to c, do not run C compiler or run the tests")
parser.add_option("--no-refnanny", dest="with_refnanny", parser.add_option("--no-refnanny", dest="with_refnanny",
action="store_false", default=True, action="store_false", default=not IS_PYPY,
help="do not regression test reference counting") help="do not regression test reference counting")
parser.add_option("--no-fork", dest="fork", parser.add_option("--no-fork", dest="fork",
action="store_false", default=True, action="store_false", default=True,
......
# mode: error
ctypedef int[1] int_array
ctypedef int[2] int_array2
cdef int_array x, y
x = y # not an error
cdef int_array *x_ptr = &x
x_ptr[0] = y # not an error
cdef class A:
cdef int_array value
def __init__(self):
self.value = x # not an error
cdef int_array2 z
z = x # error
x = z # error
cdef enum:
SIZE = 2
ctypedef int[SIZE] int_array_dyn
cdef int_array_dyn d
d = z # not an error
_ERRORS = u"""
20:2: Assignment to slice of wrong length, expected 2, got 1
21:2: Assignment to slice of wrong length, expected 1, got 2
"""
...@@ -10,24 +10,7 @@ cdef void foo(obj): ...@@ -10,24 +10,7 @@ cdef void foo(obj):
obj = p2 # error obj = p2 # error
ctypedef int[1] int_array
cdef int_array x, y
x = y # error
cdef int_array *x_ptr = &x
x_ptr[0] = y # error
cdef class A:
cdef int_array value
def __init__(self):
self.value = x # error
_ERRORS = u""" _ERRORS = u"""
17:2: Assignment to non-lvalue 'x'
20:5: Assignment to non-lvalue of type 'int_array'
25:12: Assignment to non-lvalue of type 'int_array'
7:19: Cannot assign type 'char *' to 'int' 7:19: Cannot assign type 'char *' to 'int'
8:20: Cannot convert Python object to 'int *' 8:20: Cannot convert Python object to 'int *'
10:20: Cannot convert 'int *' to Python object 10:20: Cannot convert 'int *' to Python object
......
...@@ -1935,9 +1935,9 @@ def test_borrowed_slice(): ...@@ -1935,9 +1935,9 @@ def test_borrowed_slice():
5 5
5 5
""" """
cdef int i, carray[10] cdef int i
for i in range(10): cdef int[10] carray
carray[i] = i carray[:] = range(10)
_borrowed(carray) _borrowed(carray)
_not_borrowed(carray) _not_borrowed(carray)
_not_borrowed2(carray) _not_borrowed2(carray)
......
# this doesn't work - it would reassign the array address! # mode: run
#
#def test_literal_list(): def test_literal_list():
# cdef int a[5] """
# a = [1,2,3,4,5] >>> test_literal_list()
# return (a[0], a[1], a[2], a[3], a[4]) (1, 2, 3, 4, 5)
"""
cdef int a[5]
a = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4])
def test_literal_list_slice_all(): def test_literal_list_slice_all():
""" """
...@@ -128,20 +132,6 @@ def test_ptr_literal_list_slice_end(): ...@@ -128,20 +132,6 @@ def test_ptr_literal_list_slice_end():
a[:5] = [1,2,3,4,5] a[:5] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4]) return (a[0], a[1], a[2], a[3], a[4])
# tuples aren't supported (yet)
#
#def test_literal_tuple():
# cdef int a[5]
# a = (1,2,3,4,5)
# return (a[0], a[1], a[2], a[3], a[4])
# this would be nice to have:
#
#def test_list(list l):
# cdef int a[5]
# a[:] = l
# return (a[0], a[1], a[2], a[3], a[4])
def test_multiple_from_slice(): def test_multiple_from_slice():
""" """
>>> test_multiple_from_slice() >>> test_multiple_from_slice()
...@@ -159,3 +149,169 @@ def test_slice_from_multiple(): ...@@ -159,3 +149,169 @@ def test_slice_from_multiple():
cdef int *a = [6,5,4,3,2,1] cdef int *a = [6,5,4,3,2,1]
a[1:4] = -1, -2, -3 a[1:4] = -1, -2, -3
return a[0], a[1], a[2], a[3], a[4], a[5] return a[0], a[1], a[2], a[3], a[4], a[5]
def test_literal_tuple():
"""
>>> test_literal_tuple()
(1, 2, 3, 4, 5)
"""
cdef int a[5]
a = (1,2,3,4,5)
return (a[0], a[1], a[2], a[3], a[4])
def test_list(list l):
"""
>>> test_list([1, 2, 3, 4, 5])
(1, 2, 3, 4, 5)
"""
cdef int a[5]
a[:] = l
return (a[0], a[1], a[2], a[3], a[4])
def assign_all_from_pointer():
"""
>>> assign_all_from_pointer()
(1, 2, 3, 4, 5)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a = v
return (a[0], a[1], a[2], a[3], a[4])
def assign_full_from_pointer():
"""
>>> assign_full_from_pointer()
(1, 2, 3, 4, 5)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a[:] = v
return (a[0], a[1], a[2], a[3], a[4])
def assign_slice_end_from_pointer():
"""
>>> assign_slice_end_from_pointer()
(1, 2, 3, 4, 123)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a[4] = 123
a[:4] = v
return (a[0], a[1], a[2], a[3], a[4])
def assign_slice_start_from_pointer():
"""
>>> assign_slice_start_from_pointer()
(123, 234, 1, 2, 3)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a[0] = 123
a[1] = 234
a[2:] = v
return (a[0], a[1], a[2], a[3], a[4])
def assign_slice_start_end_from_pointer():
"""
>>> assign_slice_start_end_from_pointer()
(123, 234, 1, 2, 345)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a[0] = 123
a[1] = 234
a[4] = 345
a[2:4] = v
return (a[0], a[1], a[2], a[3], a[4])
'''
# FIXME: make this work:
def assign_slice_start_end_from_sliced_pointer():
"""
>>> assign_slice_start_end_from_sliced_pointer()
(123, 234, 3, 4, 345)
"""
cdef int *v = [1, 2, 3, 4, 5]
cdef int[5] a
a[0] = 123
a[1] = 234
a[4] = 345
a[2:4] = v[2:4]
return (a[0], a[1], a[2], a[3], a[4])
def assign_from_longer_array_slice():
"""
>>> assign_from_longer_array_slice()
[3, 4, 5]
"""
cdef int[5] a
cdef int[3] b
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
b[0] = 11
b[1] = 12
b[2] = 13
b = a[2:]
return b
'''
def assign_slice_from_shorter_array():
"""
>>> assign_slice_from_shorter_array()
[1, 11, 12, 13, 5]
"""
cdef int[5] a
cdef int[3] b
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
b[0] = 11
b[1] = 12
b[2] = 13
a[1:4] = b
return a
cdef enum:
SIZE = 2
ctypedef int[SIZE] int_array_dyn
def assign_ptr_to_unknown_csize():
"""
>>> assign_ptr_to_unknown_csize()
[1, 2]
"""
cdef int* v = [1, 2, 3, 4, 5]
cdef int_array_dyn d
d = v
return d
def assign_to_wrong_csize():
"""
>>> assign_to_wrong_csize()
Traceback (most recent call last):
ValueError: Assignment to slice of wrong length, expected 3, got 2
"""
cdef int_array_dyn d
cdef int v[3]
v[0] = 1
v[1] = 2
v[2] = 3
d = v
return d
def from_int_array():
"""
>>> from_int_array()
[1, 2, 3]
"""
cdef int[3] v
v[0] = 1
v[1] = 2
v[2] = 3
return v
cpdef tuple tuple_from_int_array():
"""
>>> tuple_from_int_array()
(1, 2, 3)
"""
cdef int[3] v
v[0] = 1
v[1] = 2
v[2] = 3
assert isinstance(<tuple>v, tuple)
return v
cdef extern from "stdint.h":
ctypedef unsigned long uint32_t
def from_typedef_int_array():
"""
>>> from_typedef_int_array()
[1, 2, 3]
"""
cdef uint32_t[3] v
v[0] = 1
v[1] = 2
v[2] = 3
return v
cpdef tuple tuple_from_typedef_int_array():
"""
>>> tuple_from_typedef_int_array()
(1, 2, 3)
"""
cdef uint32_t[3] v
v[0] = 1
v[1] = 2
v[2] = 3
return v
def from_int_array_array():
"""
>>> from_int_array_array()
[[11, 12, 13], [21, 22, 23]]
"""
cdef int[2][3] v
v[0][0] = 11
v[0][1] = 12
v[0][2] = 13
v[1][0] = 21
v[1][1] = 22
v[1][2] = 23
return v
ctypedef struct MyStructType:
int x
double y
cdef struct MyStruct:
int x
double y
def from_struct_array():
"""
>>> a, b = from_struct_array()
>>> a['x'], a['y']
(1, 2.0)
>>> b['x'], b['y']
(3, 4.0)
"""
cdef MyStructType[2] v
cdef MyStruct[2] w
v[0] = MyStructType(1, 2)
v[1] = MyStructType(3, 4)
assert isinstance(<tuple>v, tuple)
assert isinstance(v, list)
w[0] = MyStruct(1, 2)
w[1] = MyStruct(3, 4)
assert (<object>w) == v
assert w == (<object>v)
return v
def to_int_array(x):
"""
>>> to_int_array([1, 2, 3])
(1, 2, 3)
>>> to_int_array([1, 2])
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> to_int_array([1, 2, 3, 4])
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
"""
cdef int[3] v = x
return v[0], v[1], v[2]
def to_int_array_array(x):
"""
>>> to_int_array_array([[1, 2, 3], [4, 5, 6]])
(1, 2, 3, 4, 5, 6)
>>> to_int_array_array(iter([[1, 2, 3], [4, 5, 6]]))
(1, 2, 3, 4, 5, 6)
>>> to_int_array_array([[1, 2, 3]])
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 2, got 1
>>> to_int_array_array(iter([[1, 2, 3]]))
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 2, got 1
>>> to_int_array_array([[1, 2, 3], [4, 5]])
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> to_int_array_array(iter([[1, 2, 3], [4, 5]]))
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> to_int_array_array([[1, 2, 3, 4], [5, 6, 7]])
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
>>> to_int_array_array(iter([[1, 2, 3, 4], [5, 6, 7]]))
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
"""
cdef int[2][3] v = x
return v[0][0], v[0][1], v[0][2], v[1][0], v[1][1], v[1][2]
'''
# FIXME: this isn't currently allowed
cdef enum:
SIZE_A = 2
SIZE_B = 3
def to_int_array_array_enumsize(x):
"""
>>> to_int_array_array([[1, 2, 3], [4, 5, 6]])
(1, 2, 3, 4, 5, 6)
>>> to_int_array_array(iter([[1, 2, 3], [4, 5, 6]]))
(1, 2, 3, 4, 5, 6)
>>> to_int_array([1, 2])
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> to_int_array([1, 2, 3, 4])
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
"""
cdef int[SIZE_A][SIZE_B] v = x
return v[0][0], v[0][1], v[0][2], v[1][0], v[1][1], v[1][2]
'''
'''
# FIXME: this isn't currently supported
def array_as_argument(int[2] x):
"""
>>> array_as_argument([1, 2])
(1, 2)
"""
return x[0], x[1]
'''
def to_int_array_slice(x):
"""
>>> to_int_array_slice([1, 2, 3])
(1, 2, 3)
>>> to_int_array_slice([1, 2])
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> to_int_array_slice([1, 2, 3, 4])
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
"""
cdef int[3] v
v[:] = x[:3]
assert v[0] == x[0]
assert v[1] == x[1]
assert v[2] == x[2]
v[:3] = [0, 0, 0]
assert v[0] == 0
assert v[1] == 0
assert v[2] == 0
v[:] = x
return v[0], v[1], v[2]
def iterable_to_int_array(x):
"""
>>> iterable_to_int_array(iter([1, 2, 3]))
(1, 2, 3)
>>> iterable_to_int_array(iter([1, 2]))
Traceback (most recent call last):
IndexError: not enough values found during array assignment, expected 3, got 2
>>> iterable_to_int_array(iter([1, 2, 3, 4]))
Traceback (most recent call last):
IndexError: too many values found during array assignment, expected 3
"""
cdef int[3] v
v[:] = x
return v[0], v[1], v[2]
def to_struct_array(x):
"""
>>> a, b = to_struct_array(({'x': 1, 'y': 2}, {'x': 3, 'y': 4}))
>>> a['x'], a['y']
(1, 2.0)
>>> b['x'], b['y']
(3, 4.0)
"""
cdef MyStructType[2] v
v[:] = x
cdef MyStruct[2] w
w[:] = x
assert w[0].x == v[0].x
assert w[0].y == v[0].y
assert w[1].x == v[1].x
assert w[1].y == v[1].y
return v[0], w[1]
def to_struct_array_array(x):
"""
>>> (a1, a2, a3), (b1, b2, b3) = to_struct_array_array([
... ({'x': 11, 'y': 12}, {'x': 13, 'y': 14}, {'x': 15, 'y': 16}),
... ({'x': 21, 'y': 22}, {'x': 23, 'y': 24}, {'x': 25, 'y': 26}),
... ])
>>> a1['x'], a1['y']
(11, 12.0)
>>> b3['x'], b3['y']
(25, 26.0)
"""
cdef MyStructType[2][3] v = x
return v[0], v[1]
cpdef void unraisable():
"""
>>> unraisable()
here
"""
print('here')
raise RuntimeError()
cpdef void raisable() except *:
"""
>>> raisable()
Traceback (most recent call last):
...
RuntimeError
"""
print('here')
raise RuntimeError()
...@@ -14,6 +14,8 @@ Traceback (most recent call last): ...@@ -14,6 +14,8 @@ Traceback (most recent call last):
NameError: name 'log' is not defined NameError: name 'log' is not defined
>>> strchr('abcabc', ord('c')) >>> strchr('abcabc', ord('c'))
'cabc' 'cabc'
>>> strchr(needle=ord('c'), haystack='abcabc')
'cabc'
""" """
cdef extern from "math.h": cdef extern from "math.h":
......
cdef extern from "math.h":
cpdef double pxd_sqrt "sqrt"(double)
"""
>>> pxd_sqrt(9)
3.0
"""
import cython
if not cython.compiled:
from math import sqrt as pxd_sqrt
@cython.test_assert_path_exists('//SimpleCallNode/NameNode[@type.is_pyobject = False]')
def call_pxd_sqrt(x):
"""
>>> call_pxd_sqrt(9)
3.0
"""
return pxd_sqrt(x)
...@@ -7,7 +7,10 @@ cdef extern from "shapes.h" namespace "shapes": ...@@ -7,7 +7,10 @@ cdef extern from "shapes.h" namespace "shapes":
cdef cppclass Shape: cdef cppclass Shape:
float area() float area()
cdef cppclass Circle(Shape): cdef cppclass Ellipse(Shape):
Ellipse(int a, int b) except +
cdef cppclass Circle(Ellipse):
int radius int radius
Circle(int r) except + Circle(int r) except +
......
...@@ -40,11 +40,17 @@ namespace shapes { ...@@ -40,11 +40,17 @@ namespace shapes {
Square(int side) : Rectangle(side, side) { this->side = side; } Square(int side) : Rectangle(side, side) { this->side = side; }
int side; int side;
}; };
class Circle : public Shape { class Ellipse : public Shape {
public:
Ellipse(int a, int b) { this->a = a; this->b = b; }
float area() const { return 3.1415926535897931f * a * b; }
int a, b;
};
class Circle : public Ellipse {
public: public:
Circle(int radius) { this->radius = radius; } Circle(int radius) : Ellipse(radius, radius) { this->radius = radius; }
float area() const { return 3.1415926535897931f * radius; }
int radius; int radius;
}; };
......
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