Commit c3fdb80e authored by Stefan Behnel's avatar Stefan Behnel

merged in latest cython-devel

parents 2b59143d 50b5656a
...@@ -127,7 +127,7 @@ function toggleDiv(id) { ...@@ -127,7 +127,7 @@ function toggleDiv(id) {
""") """)
f.write(u'<body>\n') f.write(u'<body>\n')
f.write(u'<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime())) f.write(u'<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime()))
c_file = Utils.encode_filename(os.path.basename(target_filename)) c_file = Utils.decode_filename(os.path.basename(target_filename))
f.write(u'<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file)) f.write(u'<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file))
k = 0 k = 0
......
...@@ -981,6 +981,23 @@ class UnicodeNode(PyConstNode): ...@@ -981,6 +981,23 @@ class UnicodeNode(PyConstNode):
def can_coerce_to_char_literal(self): def can_coerce_to_char_literal(self):
return len(self.value) == 1 return len(self.value) == 1
def contains_surrogates(self):
# Check if the unicode string contains surrogate code points
# on a CPython platform with wide (UCS-4) or narrow (UTF-16)
# Unicode, i.e. characters that would be spelled as two
# separate code units on a narrow platform.
for c in map(ord, self.value):
if c > 65535: # can only happen on wide platforms
return True
# We only look for the first code unit (D800-DBFF) of a
# surrogate pair - if we find one, the other one
# (DC00-DFFF) is likely there, too. If we don't find it,
# any second code unit cannot make for a surrogate pair by
# itself.
if c >= 0xD800 and c <= 0xDBFF:
return True
return False
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
self.result_code = code.get_py_string_const(self.value) self.result_code = code.get_py_string_const(self.value)
...@@ -3423,7 +3440,8 @@ class AttributeNode(ExprNode): ...@@ -3423,7 +3440,8 @@ class AttributeNode(ExprNode):
def generate_deletion_code(self, code): def generate_deletion_code(self, code):
interned_attr_cname = code.intern_identifier(self.attribute) interned_attr_cname = code.intern_identifier(self.attribute)
self.obj.generate_evaluation_code(code) self.obj.generate_evaluation_code(code)
if self.is_py_attr: if self.is_py_attr or (isinstance(self.entry.scope, Symtab.PropertyScope)
and self.entry.scope.entries.has_key(u'__del__')):
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
'PyObject_DelAttr(%s, %s)' % ( 'PyObject_DelAttr(%s, %s)' % (
self.obj.py_result(), self.obj.py_result(),
...@@ -4569,7 +4587,11 @@ class UnopNode(ExprNode): ...@@ -4569,7 +4587,11 @@ class UnopNode(ExprNode):
self.compile_time_value_error(e) self.compile_time_value_error(e)
def infer_type(self, env): def infer_type(self, env):
return self.operand.infer_type(env) operand_type = self.operand.infer_type(env)
if operand_type.is_pyobject:
return py_object_type
else:
return operand_type
def analyse_types(self, env): def analyse_types(self, env):
self.operand.analyse_types(env) self.operand.analyse_types(env)
...@@ -5563,13 +5585,12 @@ class PowNode(NumBinopNode): ...@@ -5563,13 +5585,12 @@ class PowNode(NumBinopNode):
self.operand2.result()) self.operand2.result())
# Note: This class is temporary "shut down" into an ineffective mode temp # Note: This class is temporarily "shut down" into an ineffective temp
# allocation mode. # allocation mode.
# #
# More sophisticated temp reuse was going on before, # More sophisticated temp reuse was going on before, one could have a
# one could have a look at adding this again after /all/ classes # look at adding this again after /all/ classes are converted to the
# are converted to the new temp scheme. (The temp juggling cannot work # new temp scheme. (The temp juggling cannot work otherwise).
# otherwise).
class BoolBinopNode(ExprNode): class BoolBinopNode(ExprNode):
# Short-circuiting boolean operation. # Short-circuiting boolean operation.
# #
...@@ -6494,7 +6515,12 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -6494,7 +6515,12 @@ class CoerceToPyTypeNode(CoercionNode):
return False return False
def coerce_to_boolean(self, env): def coerce_to_boolean(self, env):
return self.arg.coerce_to_boolean(env).coerce_to_temp(env) arg_type = self.arg.type
if (arg_type == PyrexTypes.c_bint_type or
(arg_type.is_pyobject and arg_type.name == 'bool')):
return self.arg.coerce_to_temp(env)
else:
return CoerceToBooleanNode(self, env)
def coerce_to_integer(self, env): def coerce_to_integer(self, env):
# If not already some C integer type, coerce to longint. # If not already some C integer type, coerce to longint.
......
...@@ -481,7 +481,7 @@ class Context(object): ...@@ -481,7 +481,7 @@ class Context(object):
def parse(self, source_desc, scope, pxd, full_module_name): def parse(self, source_desc, scope, pxd, full_module_name):
if not isinstance(source_desc, FileSourceDescriptor): if not isinstance(source_desc, FileSourceDescriptor):
raise RuntimeError("Only file sources for code supported") raise RuntimeError("Only file sources for code supported")
source_filename = Utils.encode_filename(source_desc.filename) source_filename = source_desc.filename
scope.cpp = self.cpp scope.cpp = self.cpp
# Parse the given source file and return a parse tree. # Parse the given source file and return a parse tree.
try: try:
......
...@@ -2243,10 +2243,10 @@ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *s ...@@ -2243,10 +2243,10 @@ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *s
goto bad; goto bad;
} }
tmp.fp = f; tmp.fp = f;
#if PY_VERSION_HEX < 0x03010000 #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#else
cobj = PyCapsule_New(tmp.p, sig, 0); cobj = PyCapsule_New(tmp.p, sig, 0);
#else
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#endif #endif
if (!cobj) if (!cobj)
goto bad; goto bad;
...@@ -2277,9 +2277,6 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (** ...@@ -2277,9 +2277,6 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
void (*fp)(void); void (*fp)(void);
void *p; void *p;
} tmp; } tmp;
#if PY_VERSION_HEX < 0x03010000
const char *desc, *s1, *s2;
#endif
d = PyObject_GetAttrString(module, (char *)"%(API)s"); d = PyObject_GetAttrString(module, (char *)"%(API)s");
if (!d) if (!d)
...@@ -2291,7 +2288,16 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (** ...@@ -2291,7 +2288,16 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
PyModule_GetName(module), funcname); PyModule_GetName(module), funcname);
goto bad; goto bad;
} }
#if PY_VERSION_HEX < 0x03010000 #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
if (!PyCapsule_IsValid(cobj, sig)) {
PyErr_Format(PyExc_TypeError,
"C function %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj));
goto bad;
}
tmp.p = PyCapsule_GetPointer(cobj, sig);
#else
{const char *desc, *s1, *s2;
desc = (const char *)PyCObject_GetDesc(cobj); desc = (const char *)PyCObject_GetDesc(cobj);
if (!desc) if (!desc)
goto bad; goto bad;
...@@ -2303,15 +2309,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (** ...@@ -2303,15 +2309,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
PyModule_GetName(module), funcname, sig, desc); PyModule_GetName(module), funcname, sig, desc);
goto bad; goto bad;
} }
tmp.p = PyCObject_AsVoidPtr(cobj); tmp.p = PyCObject_AsVoidPtr(cobj);}
#else
if (!PyCapsule_IsValid(cobj, sig)) {
PyErr_Format(PyExc_TypeError,
"C function %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj));
goto bad;
}
tmp.p = PyCapsule_GetPointer(cobj, sig);
#endif #endif
*f = tmp.fp; *f = tmp.fp;
if (!(*f)) if (!(*f))
......
...@@ -5216,17 +5216,26 @@ class FromImportStatNode(StatNode): ...@@ -5216,17 +5216,26 @@ class FromImportStatNode(StatNode):
break break
else: else:
entry = env.lookup(target.name) entry = env.lookup(target.name)
if (entry.is_type and # check whether or not entry is already cimported
entry.type.name == name and if (entry.is_type and entry.type.name == name
entry.type.module_name == self.module.module_name.value): and hasattr(entry.type, 'module_name')):
continue # already cimported if entry.type.module_name == self.module.module_name.value:
# cimported with absolute name
continue
try:
# cimported with relative name
module = env.find_module(self.module.module_name.value,
pos=None)
if entry.type.module_name == module.qualified_name:
continue
except AttributeError:
pass
target.analyse_target_expression(env, None) target.analyse_target_expression(env, None)
if target.type is py_object_type: if target.type is py_object_type:
coerced_item = None coerced_item = None
else: else:
coerced_item = self.item.coerce_to(target.type, env) coerced_item = self.item.coerce_to(target.type, env)
self.interned_items.append( self.interned_items.append((name, target, coerced_item))
(name, target, coerced_item))
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.module.generate_evaluation_code(code) self.module.generate_evaluation_code(code)
...@@ -6159,10 +6168,10 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ ...@@ -6159,10 +6168,10 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
""", """,
impl = """ impl = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable) { static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
#if PY_VERSION_HEX < 0x03010000 #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#else
PyObject *ob = PyCapsule_New(vtable, 0, 0); PyObject *ob = PyCapsule_New(vtable, 0, 0);
#else
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#endif #endif
if (!ob) if (!ob)
goto bad; goto bad;
...@@ -6187,10 +6196,10 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) { ...@@ -6187,10 +6196,10 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__"); PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob) if (!ob)
goto bad; goto bad;
#if PY_VERSION_HEX < 0x03010000 #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#else
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0); *(void **)vtabptr = PyCapsule_GetPointer(ob, 0);
#else
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#endif #endif
if (!*(void **)vtabptr) if (!*(void **)vtabptr)
goto bad; goto bad;
......
...@@ -600,6 +600,12 @@ class SwitchTransform(Visitor.VisitorTransform): ...@@ -600,6 +600,12 @@ class SwitchTransform(Visitor.VisitorTransform):
not_in = cond.operator == 'not_in' not_in = cond.operator == 'not_in'
if not_in and not allow_not_in: if not_in and not allow_not_in:
return self.NO_MATCH return self.NO_MATCH
if isinstance(cond.operand2, ExprNodes.UnicodeNode) and \
cond.operand2.contains_surrogates():
# dealing with surrogates leads to different
# behaviour on wide and narrow Unicode
# platforms => refuse to optimise this case
return self.NO_MATCH
# this looks somewhat silly, but it does the right # this looks somewhat silly, but it does the right
# checks for NameNode and AttributeNode # checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1): if is_common_value(cond.operand1, cond.operand1):
...@@ -1649,8 +1655,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1649,8 +1655,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
elif len(pos_args) != 1: elif len(pos_args) != 1:
self._error_wrong_arg_count('bool', node, pos_args, '0 or 1') self._error_wrong_arg_count('bool', node, pos_args, '0 or 1')
return node return node
return pos_args[0].coerce_to_boolean( else:
self.current_env()).coerce_to_pyobject(self.current_env()) return pos_args[0].coerce_to_boolean(
self.current_env()).coerce_to_pyobject(self.current_env())
### builtin functions ### builtin functions
...@@ -2463,6 +2470,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2463,6 +2470,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
encoding = encoding_node.value encoding = encoding_node.value
encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding, encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
type=PyrexTypes.c_char_ptr_type) type=PyrexTypes.c_char_ptr_type)
elif encoding_node.type is Builtin.bytes_type:
encoding = None
encoding_node = encoding_node.coerce_to(
PyrexTypes.c_char_ptr_type, self.current_env())
elif encoding_node.type.is_string: elif encoding_node.type.is_string:
encoding = None encoding = None
else: else:
...@@ -2485,6 +2496,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2485,6 +2496,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
error_handling_node = ExprNodes.BytesNode( error_handling_node = ExprNodes.BytesNode(
error_handling_node.pos, value=error_handling, error_handling_node.pos, value=error_handling,
type=PyrexTypes.c_char_ptr_type) type=PyrexTypes.c_char_ptr_type)
elif error_handling_node.type is Builtin.bytes_type:
error_handling = None
error_handling_node = error_handling_node.coerce_to(
PyrexTypes.c_char_ptr_type, self.current_env())
elif error_handling_node.type.is_string: elif error_handling_node.type.is_string:
error_handling = None error_handling = None
else: else:
......
...@@ -972,6 +972,15 @@ property NAME: ...@@ -972,6 +972,15 @@ property NAME:
def __set__(self, value): def __set__(self, value):
ATTR = value ATTR = value
""", level='c_class') """, level='c_class')
basic_pyobject_property = TreeFragment(u"""
property NAME:
def __get__(self):
return ATTR
def __set__(self, value):
ATTR = value
def __del__(self):
ATTR = None
""", level='c_class')
basic_property_ro = TreeFragment(u""" basic_property_ro = TreeFragment(u"""
property NAME: property NAME:
def __get__(self): def __get__(self):
...@@ -1097,7 +1106,10 @@ property NAME: ...@@ -1097,7 +1106,10 @@ property NAME:
def create_Property(self, entry): def create_Property(self, entry):
if entry.visibility == 'public': if entry.visibility == 'public':
template = self.basic_property if entry.type.is_pyobject:
template = self.basic_pyobject_property
else:
template = self.basic_property
elif entry.visibility == 'readonly': elif entry.visibility == 'readonly':
template = self.basic_property_ro template = self.basic_property_ro
property = template.substitute({ property = template.substitute({
......
...@@ -2426,7 +2426,7 @@ def independent_spanning_type(type1, type2): ...@@ -2426,7 +2426,7 @@ def independent_spanning_type(type1, type2):
elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric): elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric):
# special case: if one of the results is a bint and the other # special case: if one of the results is a bint and the other
# is another C integer, we must prevent returning a numeric # is another C integer, we must prevent returning a numeric
# type so that we do not loose the ability to coerce to a # type so that we do not lose the ability to coerce to a
# Python bool if we have to. # Python bool if we have to.
return py_object_type return py_object_type
span_type = _spanning_type(type1, type2) span_type = _spanning_type(type1, type2)
......
...@@ -166,6 +166,7 @@ class FileSourceDescriptor(SourceDescriptor): ...@@ -166,6 +166,7 @@ class FileSourceDescriptor(SourceDescriptor):
the position()-tuple. the position()-tuple.
""" """
def __init__(self, filename): def __init__(self, filename):
filename = Utils.decode_filename(filename)
self.filename = filename self.filename = filename
self.set_file_type_from_name(filename) self.set_file_type_from_name(filename)
self._cmp_name = filename self._cmp_name = filename
......
...@@ -30,8 +30,19 @@ class UnicodeLiteralBuilder(object): ...@@ -30,8 +30,19 @@ class UnicodeLiteralBuilder(object):
assert isinstance(characters, _unicode), str(type(characters)) assert isinstance(characters, _unicode), str(type(characters))
self.chars.append(characters) self.chars.append(characters)
def append_charval(self, char_number): if sys.maxunicode == 65535:
self.chars.append( unichr(char_number) ) def append_charval(self, char_number):
if char_number > 65535:
# wide Unicode character on narrow platform => replace
# by surrogate pair
char_number -= 0x10000
self.chars.append( unichr((char_number // 1024) + 0xD800) )
self.chars.append( unichr((char_number % 1024) + 0xDC00) )
else:
self.chars.append( unichr(char_number) )
else:
def append_charval(self, char_number):
self.chars.append( unichr(char_number) )
def getstring(self): def getstring(self):
return EncodedString(u''.join(self.chars)) return EncodedString(u''.join(self.chars))
......
...@@ -311,7 +311,8 @@ def find_spanning_type(type1, type2): ...@@ -311,7 +311,8 @@ def find_spanning_type(type1, type2):
return py_object_type return py_object_type
else: else:
result_type = PyrexTypes.spanning_type(type1, type2) result_type = PyrexTypes.spanning_type(type1, type2)
if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type, Builtin.float_type): if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type,
Builtin.float_type):
# Python's float type is just a C double, so it's safe to # Python's float type is just a C double, so it's safe to
# use the C type instead # use the C type instead
return PyrexTypes.c_double_type return PyrexTypes.c_double_type
...@@ -328,8 +329,14 @@ def safe_spanning_type(types, might_overflow): ...@@ -328,8 +329,14 @@ def safe_spanning_type(types, might_overflow):
if result_type.is_reference: if result_type.is_reference:
result_type = result_type.ref_base_type result_type = result_type.ref_base_type
if result_type.is_pyobject: if result_type.is_pyobject:
# any specific Python type is always safe to infer # In theory, any specific Python type is always safe to
return result_type # infer. However, inferring str can cause some existing code
# to break, since we are also now much more strict about
# coercion from str to char *. See trac #553.
if result_type.name == 'str':
return py_object_type
else:
return result_type
elif result_type is PyrexTypes.c_double_type: elif result_type is PyrexTypes.c_double_type:
# Python's float type is just a C double, so it's safe to use # Python's float type is just a C double, so it's safe to use
# the C type instead # the C type instead
......
...@@ -143,6 +143,7 @@ from cpython.function cimport * ...@@ -143,6 +143,7 @@ from cpython.function cimport *
from cpython.method cimport * from cpython.method cimport *
from cpython.weakref cimport * from cpython.weakref cimport *
from cpython.getargs cimport * from cpython.getargs cimport *
from cpython.pythread cimport *
# Python <= 2.x # Python <= 2.x
from cpython.cobject cimport * from cpython.cobject cimport *
......
cdef extern from "pythread.h":
ctypedef void *PyThread_type_lock
ctypedef void *PyThread_type_sema
void PyThread_init_thread()
long PyThread_start_new_thread(void (*)(void *), void *)
void PyThread_exit_thread()
long PyThread_get_thread_ident()
PyThread_type_lock PyThread_allocate_lock()
void PyThread_free_lock(PyThread_type_lock)
int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil
void PyThread_release_lock(PyThread_type_lock) nogil
enum: # 'mode' in PyThread_acquire_lock
WAIT_LOCK # 1
NOWAIT_LOCK # 0
size_t PyThread_get_stacksize()
int PyThread_set_stacksize(size_t)
# Thread Local Storage (TLS) API
int PyThread_create_key()
void PyThread_delete_key(int)
int PyThread_set_key_value(int, void *)
void * PyThread_get_key_value(int)
void PyThread_delete_key_value(int key)
# Cleanup after a fork
void PyThread_ReInitTLS()
...@@ -13,11 +13,11 @@ cdef extern from "Python.h": ...@@ -13,11 +13,11 @@ cdef extern from "Python.h":
bint PyTuple_CheckExact(object p) bint PyTuple_CheckExact(object p)
# Return true if p is a tuple object, but not an instance of a subtype of the tuple type. # Return true if p is a tuple object, but not an instance of a subtype of the tuple type.
object PyTuple_New(Py_ssize_t len) tuple PyTuple_New(Py_ssize_t len)
# Return value: New reference. # Return value: New reference.
# Return a new tuple object of size len, or NULL on failure. # Return a new tuple object of size len, or NULL on failure.
object PyTuple_Pack(Py_ssize_t n, ...) tuple PyTuple_Pack(Py_ssize_t n, ...)
# Return value: New reference. # Return value: New reference.
# Return a new tuple object of size n, or NULL on failure. The # Return a new tuple object of size n, or NULL on failure. The
# tuple values are initialized to the subsequent n C arguments # tuple values are initialized to the subsequent n C arguments
...@@ -41,7 +41,7 @@ cdef extern from "Python.h": ...@@ -41,7 +41,7 @@ cdef extern from "Python.h":
# Return value: Borrowed reference. # Return value: Borrowed reference.
# Like PyTuple_GetItem(), but does no checking of its arguments. # Like PyTuple_GetItem(), but does no checking of its arguments.
object PyTuple_GetSlice(object p, Py_ssize_t low, Py_ssize_t high) tuple PyTuple_GetSlice(object p, Py_ssize_t low, Py_ssize_t high)
# Return value: New reference. # Return value: New reference.
# Take a slice of the tuple pointed to by p from low to high and return it as a new tuple. # Take a slice of the tuple pointed to by p from low to high and return it as a new tuple.
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
DEF _buffer_format_string_len = 255 DEF _buffer_format_string_len = 255
cimport cpython.buffer as pybuf cimport cpython.buffer as pybuf
from cpython cimport PyObject, Py_INCREF, Py_XDECREF from cpython.ref cimport Py_INCREF, Py_XDECREF
from libc cimport stdlib from cpython.object cimport PyObject
from libc cimport stdio cimport libc.stdlib as stdlib
cimport libc.stdio as stdio
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef int Py_intptr_t ctypedef int Py_intptr_t
......
...@@ -66,9 +66,9 @@ def path_exists(path): ...@@ -66,9 +66,9 @@ def path_exists(path):
pass pass
return False return False
# support for source file encoding detection # file name encodings
def encode_filename(filename): def decode_filename(filename):
if isinstance(filename, unicode): if isinstance(filename, unicode):
return filename return filename
try: try:
...@@ -80,6 +80,8 @@ def encode_filename(filename): ...@@ -80,6 +80,8 @@ def encode_filename(filename):
pass pass
return filename return filename
# support for source file encoding detection
_match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search _match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search
def detect_file_encoding(source_filename): def detect_file_encoding(source_filename):
......
...@@ -40,7 +40,7 @@ if sys.version_info[0] >= 3: ...@@ -40,7 +40,7 @@ if sys.version_info[0] >= 3:
pxd_include_dirs = [ pxd_include_dirs = [
directory for directory, dirs, files in os.walk('Cython/Includes') directory for directory, dirs, files in os.walk('Cython/Includes')
if '__init__.pyx' in files or '__init__.pxd' in files if '__init__.pyx' in files or '__init__.pxd' in files
or directory == 'Cython/Includes' ] or directory == 'Cython/Includes' or directory == 'Cython/Includes/Deprecated']
pxd_include_patterns = [ pxd_include_patterns = [
p+'/*.pxd' for p in pxd_include_dirs ] + [ p+'/*.pxd' for p in pxd_include_dirs ] + [
...@@ -155,6 +155,12 @@ def compile_cython_modules(profile=False): ...@@ -155,6 +155,12 @@ def compile_cython_modules(profile=False):
result = compile(pyx_source_file) result = compile(pyx_source_file)
c_source_file = result.c_file c_source_file = result.c_file
if c_source_file: if c_source_file:
# Py2 distutils can't handle unicode file paths
if isinstance(c_source_file, unicode):
filename_encoding = sys.getfilesystemencoding()
if filename_encoding is None:
filename_encoding = sys.getdefaultencoding()
c_source_file = c_source_file.encode(filename_encoding)
extensions.append( extensions.append(
Extension(module, sources = [c_source_file]) Extension(module, sources = [c_source_file])
) )
...@@ -164,8 +170,15 @@ def compile_cython_modules(profile=False): ...@@ -164,8 +170,15 @@ def compile_cython_modules(profile=False):
setup_args['ext_modules'] = extensions setup_args['ext_modules'] = extensions
add_command_class("build_ext", build_ext) add_command_class("build_ext", build_ext)
except Exception: except Exception:
print("ERROR: %s" % sys.exc_info()[1]) print('''
print("Extension module compilation failed, using plain Python implementation") ERROR: %s
Extension module compilation failed, looks like Cython cannot run
properly on this system. To work around this, pass the option
"--no-cython-compile". This will install a pure Python version of
Cython without compiling its own sources.
''' % sys.exc_info()[1])
raise
cython_profile = '--cython-profile' in sys.argv cython_profile = '--cython-profile' in sys.argv
if cython_profile: if cython_profile:
......
...@@ -15,6 +15,7 @@ cdef void f(): ...@@ -15,6 +15,7 @@ cdef void f():
_ERRORS = u""" _ERRORS = u"""
5:20: Illegal use of special attribute __weakref__ 5:20: Illegal use of special attribute __weakref__
5:20: Illegal use of special attribute __weakref__ 5:20: Illegal use of special attribute __weakref__
5:20: Illegal use of special attribute __weakref__
5:20: Special attribute __weakref__ cannot be exposed to Python 5:20: Special attribute __weakref__ cannot be exposed to Python
8:22: Illegal use of special attribute __weakref__ 8:22: Illegal use of special attribute __weakref__
8:22: Special attribute __weakref__ cannot be exposed to Python 8:22: Special attribute __weakref__ cannot be exposed to Python
......
def test():
"""
>>> test()
True
"""
cdef int x = 5
print bool(x)
...@@ -45,7 +45,8 @@ class Integral { ...@@ -45,7 +45,8 @@ class Integral {
private: private:
static bool is_le() { static bool is_le() {
int one = 1; int one = 1;
return (int)*(unsigned char *)&one; int b = (int)*(unsigned char *)&one;
return b ? true : false;
} }
static unsigned int lsb() { static unsigned int lsb() {
return is_le() ? 0 : N-1; return is_le() ? 0 : N-1;
......
...@@ -10,7 +10,7 @@ def libc_cimports(): ...@@ -10,7 +10,7 @@ def libc_cimports():
hello hello
""" """
cdef char buf[10] cdef char buf[10]
sprintf(buf, b'hello') sprintf(buf, "%s", b'hello')
print (<object>buf).decode('ASCII') print (<object>buf).decode('ASCII')
def cpython_cimports(): def cpython_cimports():
......
...@@ -15,7 +15,7 @@ def tomato(): ...@@ -15,7 +15,7 @@ def tomato():
>>> lines = __test__.keys() >>> lines = __test__.keys()
>>> len(lines) >>> len(lines)
2 3
>>> 'Spam.eggs.__get__ (line 5)' in lines >>> 'Spam.eggs.__get__ (line 5)' in lines
True True
>>> 'tomato (line 11)' in lines >>> 'tomato (line 11)' in lines
...@@ -26,3 +26,17 @@ def tomato(): ...@@ -26,3 +26,17 @@ def tomato():
spam = Spam() spam = Spam()
lettuce = spam.eggs lettuce = spam.eggs
return lettuce return lettuce
cdef class Bacon(object):
cdef object number_of_slices
cdef public object is_a_vegetable
def breakfast():
"""
>>> breakfast()
"""
cdef Bacon myslices = Bacon()
myslices.is_a_vegetable = True
assert myslices.is_a_vegetable, myslices.is_a_vegetable
del myslices.is_a_vegetable
assert myslices.is_a_vegetable is None, myslices.is_a_vegetable
...@@ -195,6 +195,34 @@ def m_unicode_literal(Py_UNICODE a): ...@@ -195,6 +195,34 @@ def m_unicode_literal(Py_UNICODE a):
cdef int result = a in u'abc\0defg\u1234\uF8D2' cdef int result = a in u'abc\0defg\u1234\uF8D2'
return result return result
cdef unicode wide_unicode_character = u'\U0010FEDC'
py_wide_unicode_character = wide_unicode_character
cdef unicode wide_unicode_character_surrogate1 = u'\uDBFF'
cdef unicode wide_unicode_character_surrogate2 = u'\uDEDC'
py_wide_unicode_character_surrogate1 = wide_unicode_character_surrogate1
py_wide_unicode_character_surrogate2 = wide_unicode_character_surrogate2
@cython.test_fail_if_path_exists("//SwitchStatNode")
@cython.test_assert_path_exists("//PrimaryCmpNode")
def m_wide_unicode_literal(Py_UNICODE a):
"""
>>> m_unicode_literal(ord('f'))
1
>>> m_unicode_literal(ord('X'))
0
>>> import sys
>>> if sys.maxunicode == 65535:
... m_wide_unicode_literal(ord(py_wide_unicode_character_surrogate1))
... m_wide_unicode_literal(ord(py_wide_unicode_character_surrogate2))
... else:
... m_wide_unicode_literal(ord(py_wide_unicode_character))
... 1
1
1
"""
cdef int result = a in u'abc\0defg\u1234\uF8D2\U0010FEDC'
return result
@cython.test_assert_path_exists("//SwitchStatNode") @cython.test_assert_path_exists("//SwitchStatNode")
@cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode") @cython.test_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_int(int a): def conditional_int(int a):
......
...@@ -122,6 +122,27 @@ def arithmetic(): ...@@ -122,6 +122,27 @@ def arithmetic():
d = 1 * 1.5 ** 2 d = 1 * 1.5 ** 2
assert typeof(d) == "double", typeof(d) assert typeof(d) == "double", typeof(d)
cdef class some_class:
pass
def unary_operators():
"""
>>> unary_operators()
"""
cdef int x = 1
assert typeof(~x) == "int", typeof(~x)
cdef some_class obj
assert typeof(~obj) == "Python object", typeof(~obj)
a = int(1)
assert typeof(a) == "Python object", typeof(a)
b = not int(3)
assert typeof(b) == "int", typeof(b)
c = +int(3)
assert typeof(c) == "Python object", typeof(c)
d = -int(5)
assert typeof(d) == "Python object", typeof(d)
def builtin_type_operations(): def builtin_type_operations():
""" """
>>> builtin_type_operations() >>> builtin_type_operations()
...@@ -341,6 +362,13 @@ def safe_only(): ...@@ -341,6 +362,13 @@ def safe_only():
res = ~d res = ~d
assert typeof(d) == "long", typeof(d) assert typeof(d) == "long", typeof(d)
# we special-case inference to type str, see
# trac #553
s = "abc"
assert typeof(s) == "Python object", typeof(s)
cdef str t = "def"
assert typeof(t) == "str object", typeof(t)
# potentially overflowing arithmetic # potentially overflowing arithmetic
e = 1 e = 1
e += 1 e += 1
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
__doc__ = br""" __doc__ = br"""
>>> sa >>> sa
'abc' 'abc'
...@@ -38,6 +40,12 @@ __doc__ = br""" ...@@ -38,6 +40,12 @@ __doc__ = br"""
12 12
>>> len(null) >>> len(null)
1 1
>>> sys.maxunicode >= 65535
True
>>> sys.maxunicode == 65535 and 1 or len(wide_literal) # test for wide build
1
>>> sys.maxunicode > 65535 and 2 or len(wide_literal) # test for narrow build
2
""".decode("ASCII") + u""" """.decode("ASCII") + u"""
>>> ua == u'abc' >>> ua == u'abc'
True True
...@@ -59,9 +67,12 @@ __doc__ = br""" ...@@ -59,9 +67,12 @@ __doc__ = br"""
True True
>>> null == u'\\x00' # unescaped by Python (required by doctest) >>> null == u'\\x00' # unescaped by Python (required by doctest)
True True
>>> wide_literal == u'\U00101234' # unescaped by Cython
True
>>> wide_literal == u'\\U00101234' # unescaped by Python
True
""" """
import sys
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u" u'", u" '") __doc__ = __doc__.replace(u" u'", u" '")
else: else:
...@@ -78,3 +89,5 @@ f = u'\xf8' ...@@ -78,3 +89,5 @@ f = u'\xf8'
add = u'Søk ik' + u'üÖä' + u'abc' add = u'Søk ik' + u'üÖä' + u'abc'
null = u'\x00' null = u'\x00'
wide_literal = u'\U00101234'
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