Commit de519dc7 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents 0ce99d24 c3fdb80e
......@@ -127,7 +127,7 @@ function toggleDiv(id) {
""")
f.write(u'<body>\n')
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))
k = 0
......
......@@ -981,6 +981,23 @@ class UnicodeNode(PyConstNode):
def can_coerce_to_char_literal(self):
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):
self.result_code = code.get_py_string_const(self.value)
......@@ -3423,7 +3440,8 @@ class AttributeNode(ExprNode):
def generate_deletion_code(self, code):
interned_attr_cname = code.intern_identifier(self.attribute)
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,
'PyObject_DelAttr(%s, %s)' % (
self.obj.py_result(),
......@@ -4569,7 +4587,11 @@ class UnopNode(ExprNode):
self.compile_time_value_error(e)
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):
self.operand.analyse_types(env)
......@@ -5563,13 +5585,12 @@ class PowNode(NumBinopNode):
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.
#
# More sophisticated temp reuse was going on before,
# one could have a look at adding this again after /all/ classes
# are converted to the new temp scheme. (The temp juggling cannot work
# otherwise).
# More sophisticated temp reuse was going on before, one could have a
# look at adding this again after /all/ classes are converted to the
# new temp scheme. (The temp juggling cannot work otherwise).
class BoolBinopNode(ExprNode):
# Short-circuiting boolean operation.
#
......@@ -6494,7 +6515,12 @@ class CoerceToPyTypeNode(CoercionNode):
return False
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):
# If not already some C integer type, coerce to longint.
......
......@@ -481,7 +481,7 @@ class Context(object):
def parse(self, source_desc, scope, pxd, full_module_name):
if not isinstance(source_desc, FileSourceDescriptor):
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
# Parse the given source file and return a parse tree.
try:
......
......@@ -2243,10 +2243,10 @@ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *s
goto bad;
}
tmp.fp = f;
#if PY_VERSION_HEX < 0x03010000
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#else
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
cobj = PyCapsule_New(tmp.p, sig, 0);
#else
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#endif
if (!cobj)
goto bad;
......@@ -2277,9 +2277,6 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
void (*fp)(void);
void *p;
} tmp;
#if PY_VERSION_HEX < 0x03010000
const char *desc, *s1, *s2;
#endif
d = PyObject_GetAttrString(module, (char *)"%(API)s");
if (!d)
......@@ -2291,7 +2288,16 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
PyModule_GetName(module), funcname);
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);
if (!desc)
goto bad;
......@@ -2303,15 +2309,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
PyModule_GetName(module), funcname, sig, desc);
goto bad;
}
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);
tmp.p = PyCObject_AsVoidPtr(cobj);}
#endif
*f = tmp.fp;
if (!(*f))
......
......@@ -5216,17 +5216,26 @@ class FromImportStatNode(StatNode):
break
else:
entry = env.lookup(target.name)
if (entry.is_type and
entry.type.name == name and
entry.type.module_name == self.module.module_name.value):
continue # already cimported
# check whether or not entry is already cimported
if (entry.is_type and entry.type.name == name
and hasattr(entry.type, 'module_name')):
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)
if target.type is py_object_type:
coerced_item = None
else:
coerced_item = self.item.coerce_to(target.type, env)
self.interned_items.append(
(name, target, coerced_item))
self.interned_items.append((name, target, coerced_item))
def generate_execution_code(self, code):
self.module.generate_evaluation_code(code)
......@@ -6159,10 +6168,10 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
""",
impl = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
#if PY_VERSION_HEX < 0x03010000
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#else
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
PyObject *ob = PyCapsule_New(vtable, 0, 0);
#else
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#endif
if (!ob)
goto bad;
......@@ -6187,10 +6196,10 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob)
goto bad;
#if PY_VERSION_HEX < 0x03010000
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#else
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0);
#else
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#endif
if (!*(void **)vtabptr)
goto bad;
......
......@@ -600,6 +600,12 @@ class SwitchTransform(Visitor.VisitorTransform):
not_in = cond.operator == 'not_in'
if not_in and not allow_not_in:
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
# checks for NameNode and AttributeNode
if is_common_value(cond.operand1, cond.operand1):
......@@ -1649,8 +1655,9 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
elif len(pos_args) != 1:
self._error_wrong_arg_count('bool', node, pos_args, '0 or 1')
return node
return pos_args[0].coerce_to_boolean(
self.current_env()).coerce_to_pyobject(self.current_env())
else:
return pos_args[0].coerce_to_boolean(
self.current_env()).coerce_to_pyobject(self.current_env())
### builtin functions
......@@ -2463,6 +2470,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
encoding = encoding_node.value
encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
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:
encoding = None
else:
......@@ -2485,6 +2496,10 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
error_handling_node = ExprNodes.BytesNode(
error_handling_node.pos, value=error_handling,
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:
error_handling = None
else:
......
......@@ -972,6 +972,15 @@ property NAME:
def __set__(self, value):
ATTR = value
""", 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"""
property NAME:
def __get__(self):
......@@ -1097,7 +1106,10 @@ property NAME:
def create_Property(self, entry):
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':
template = self.basic_property_ro
property = template.substitute({
......
......@@ -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):
# special case: if one of the results is a bint and the other
# 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.
return py_object_type
span_type = _spanning_type(type1, type2)
......
......@@ -166,6 +166,7 @@ class FileSourceDescriptor(SourceDescriptor):
the position()-tuple.
"""
def __init__(self, filename):
filename = Utils.decode_filename(filename)
self.filename = filename
self.set_file_type_from_name(filename)
self._cmp_name = filename
......
......@@ -30,8 +30,19 @@ class UnicodeLiteralBuilder(object):
assert isinstance(characters, _unicode), str(type(characters))
self.chars.append(characters)
def append_charval(self, char_number):
self.chars.append( unichr(char_number) )
if sys.maxunicode == 65535:
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):
return EncodedString(u''.join(self.chars))
......
......@@ -311,7 +311,8 @@ def find_spanning_type(type1, type2):
return py_object_type
else:
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
# use the C type instead
return PyrexTypes.c_double_type
......@@ -328,8 +329,14 @@ def safe_spanning_type(types, might_overflow):
if result_type.is_reference:
result_type = result_type.ref_base_type
if result_type.is_pyobject:
# any specific Python type is always safe to infer
return result_type
# In theory, any specific Python type is always safe to
# 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:
# Python's float type is just a C double, so it's safe to use
# the C type instead
......
......@@ -143,6 +143,7 @@ from cpython.function cimport *
from cpython.method cimport *
from cpython.weakref cimport *
from cpython.getargs cimport *
from cpython.pythread cimport *
# Python <= 2.x
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":
bint PyTuple_CheckExact(object p)
# 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 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 a new tuple object of size n, or NULL on failure. The
# tuple values are initialized to the subsequent n C arguments
......@@ -41,7 +41,7 @@ cdef extern from "Python.h":
# Return value: Borrowed reference.
# 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.
# 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 @@
DEF _buffer_format_string_len = 255
cimport cpython.buffer as pybuf
from cpython cimport PyObject, Py_INCREF, Py_XDECREF
from libc cimport stdlib
from libc cimport stdio
from cpython.ref cimport Py_INCREF, Py_XDECREF
from cpython.object cimport PyObject
cimport libc.stdlib as stdlib
cimport libc.stdio as stdio
cdef extern from "Python.h":
ctypedef int Py_intptr_t
......
......@@ -66,9 +66,9 @@ def path_exists(path):
pass
return False
# support for source file encoding detection
# file name encodings
def encode_filename(filename):
def decode_filename(filename):
if isinstance(filename, unicode):
return filename
try:
......@@ -80,6 +80,8 @@ def encode_filename(filename):
pass
return filename
# support for source file encoding detection
_match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search
def detect_file_encoding(source_filename):
......
......@@ -40,7 +40,7 @@ if sys.version_info[0] >= 3:
pxd_include_dirs = [
directory for directory, dirs, files in os.walk('Cython/Includes')
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 = [
p+'/*.pxd' for p in pxd_include_dirs ] + [
......@@ -155,6 +155,12 @@ def compile_cython_modules(profile=False):
result = compile(pyx_source_file)
c_source_file = result.c_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(
Extension(module, sources = [c_source_file])
)
......@@ -164,8 +170,15 @@ def compile_cython_modules(profile=False):
setup_args['ext_modules'] = extensions
add_command_class("build_ext", build_ext)
except Exception:
print("ERROR: %s" % sys.exc_info()[1])
print("Extension module compilation failed, using plain Python implementation")
print('''
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
if cython_profile:
......
......@@ -15,6 +15,7 @@ cdef void f():
_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: Special attribute __weakref__ cannot be exposed to Python
8:22: Illegal use of special attribute __weakref__
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 {
private:
static bool is_le() {
int one = 1;
return (int)*(unsigned char *)&one;
int b = (int)*(unsigned char *)&one;
return b ? true : false;
}
static unsigned int lsb() {
return is_le() ? 0 : N-1;
......
......@@ -10,7 +10,7 @@ def libc_cimports():
hello
"""
cdef char buf[10]
sprintf(buf, b'hello')
sprintf(buf, "%s", b'hello')
print (<object>buf).decode('ASCII')
def cpython_cimports():
......
......@@ -15,7 +15,7 @@ def tomato():
>>> lines = __test__.keys()
>>> len(lines)
2
3
>>> 'Spam.eggs.__get__ (line 5)' in lines
True
>>> 'tomato (line 11)' in lines
......@@ -26,3 +26,17 @@ def tomato():
spam = Spam()
lettuce = spam.eggs
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):
cdef int result = a in u'abc\0defg\u1234\uF8D2'
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_fail_if_path_exists("//BoolBinopNode", "//PrimaryCmpNode")
def conditional_int(int a):
......
......@@ -122,6 +122,27 @@ def arithmetic():
d = 1 * 1.5 ** 2
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():
"""
>>> builtin_type_operations()
......@@ -341,6 +362,13 @@ def safe_only():
res = ~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
e = 1
e += 1
......
# -*- coding: utf-8 -*-
import sys
__doc__ = br"""
>>> sa
'abc'
......@@ -38,6 +40,12 @@ __doc__ = br"""
12
>>> len(null)
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"""
>>> ua == u'abc'
True
......@@ -59,9 +67,12 @@ __doc__ = br"""
True
>>> null == u'\\x00' # unescaped by Python (required by doctest)
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:
__doc__ = __doc__.replace(u" u'", u" '")
else:
......@@ -78,3 +89,5 @@ f = u'\xf8'
add = u'Søk ik' + u'üÖä' + u'abc'
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