if dst_type.is_pyobject:
if not src.type.is_pyobject:
- src = CoerceToPyTypeNode(src, env)
+ if dst_type is bytes_type and src.type.is_int:
+ src = CoerceIntToBytesNode(src, env)
+ else:
+ src = CoerceToPyTypeNode(src, env)
if not src.type.subtype_of(dst_type):
if not isinstance(src, NoneNode):
src = PyTypeTestNode(src, dst_type, env)
if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
if to_py and not from_py:
- if self.operand.type.can_coerce_to_pyobject(env):
+ if self.type is bytes_type and self.operand.type.is_int:
+ # FIXME: the type cast node isn't needed in this case
+ # and can be dropped once analyse_types() can return a
+ # different node
+ self.operand = CoerceIntToBytesNode(self.operand, env)
+ elif self.operand.type.can_coerce_to_pyobject(env):
self.result_ctype = py_object_type
self.operand = self.operand.coerce_to_pyobject(env)
else:
def is_c_string_contains(self):
return self.operator in ('in', 'not_in') and \
- ((self.operand1.type in (PyrexTypes.c_char_type, PyrexTypes.c_uchar_type)
- and self.operand2.type in (PyrexTypes.c_char_ptr_type,
- PyrexTypes.c_uchar_ptr_type,
- bytes_type)) or
+ ((self.operand1.type.is_int
+ and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or
(self.operand1.type is PyrexTypes.c_py_unicode_type
and self.operand2.type is unicode_type))
CoercionNode.__init__(self, arg)
if not arg.type.create_to_py_utility_code(env):
error(arg.pos,
- "Cannot convert '%s' to Python object" % arg.type)
+ "Cannot convert '%s' to Python object" % arg.type)
if type is not py_object_type:
self.type = py_object_type
elif arg.type.is_string:
code.put_gotref(self.py_result())
+class CoerceIntToBytesNode(CoerceToPyTypeNode):
+ # This node is used to convert a C int type to a Python bytes
+ # object.
+
+ is_temp = 1
+
+ def __init__(self, arg, env):
+ arg = arg.coerce_to_simple(env)
+ CoercionNode.__init__(self, arg)
+ self.type = Builtin.bytes_type
+
+ def generate_result_code(self, code):
+ arg = self.arg
+ arg_result = arg.result()
+ if arg.type not in (PyrexTypes.c_char_type,
+ PyrexTypes.c_uchar_type,
+ PyrexTypes.c_schar_type):
+ if arg.type.signed:
+ code.putln("if ((%s < 0) || (%s > 255)) {" % (
+ arg_result, arg_result))
+ else:
+ code.putln("if (%s > 255) {" % arg_result)
+ code.putln('PyErr_Format(PyExc_OverflowError, '
+ '"value too large to pack into a byte"); %s' % (
+ code.error_goto(self.pos)))
+ code.putln('}')
+ temp = None
+ if arg.type is not PyrexTypes.c_char_type:
+ temp = code.funcstate.allocate_temp(PyrexTypes.c_char_type, manage_ref=False)
+ code.putln("%s = (char)%s;" % (temp, arg_result))
+ arg_result = temp
+ code.putln('%s = PyBytes_FromStringAndSize(&%s, 1); %s' % (
+ self.result(),
+ arg_result,
+ code.error_goto_if_null(self.result(), self.pos)))
+ if temp is not None:
+ code.funcstate.release_temp(temp)
+ code.put_gotref(self.py_result())
+
+
class CoerceFromPyTypeNode(CoercionNode):
# This node is used to convert a Python object
# to a C data type.
--- /dev/null
+
+cimport cython
+
+def coerce_char_default(char c):
+ """
+ Default char -> int coercion
+
+ >>> coerce_char_default(ord('A')) == ord('A')
+ True
+ """
+ return c
+
+
+def coerce_uchar_default(unsigned char c):
+ """
+ Default char -> int coercion
+
+ >>> coerce_uchar_default(ord('A')) == ord('A')
+ True
+ """
+ return c
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_char_bytes_cast(char c):
+ """
+ Explicit char -> bytes coercion
+
+ >>> coerce_char_bytes_cast(ord('A')) == 'A'.encode('ASCII')
+ True
+ """
+ return <bytes>c
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_uchar_bytes_cast(unsigned char c):
+ """
+ Explicit uchar -> bytes coercion
+
+ >>> coerce_uchar_bytes_cast(ord('A')) == 'A'.encode('ASCII')
+ True
+ >>> b = coerce_uchar_bytes_cast(ord('\\xff'))
+ >>> b == '\\xff' or b == '\\xff'.encode('ISO-8859-1') # Py2 or Py3
+ True
+ """
+ return <bytes>c
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_int_bytes_cast(int c):
+ """
+ Explicit int -> bytes coercion
+
+ >>> coerce_int_bytes_cast(ord('A')) == 'A'.encode('ASCII')
+ True
+ >>> coerce_int_bytes_cast(ord('A') + 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ >>> coerce_int_bytes_cast(ord('A') - 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ """
+ return <bytes>c
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_uint_bytes_cast(unsigned int c):
+ """
+ Explicit uint -> bytes coercion
+
+ >>> coerce_uint_bytes_cast(ord('A')) == 'A'.encode('ASCII')
+ True
+ >>> b = coerce_uint_bytes_cast(ord('\\xff'))
+ >>> b == '\\xff' or b == '\\xff'.encode('ISO-8859-1') # Py2 or Py3
+ True
+
+ >>> coerce_uint_bytes_cast(ord('A') + 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ """
+ return <bytes>c
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_char_bytes_assign(char c):
+ """
+ Implicit char -> bytes coercion in assignments
+
+ >>> coerce_char_bytes_assign(ord('A')) == 'A'.encode('ASCII')
+ True
+ """
+ cdef bytes s = c
+ return s
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_uchar_bytes_assign(unsigned char c):
+ """
+ Implicit uchar -> bytes coercion in assignments
+
+ >>> coerce_uchar_bytes_assign(ord('A')) == 'A'.encode('ASCII')
+ True
+ >>> b = coerce_uchar_bytes_assign(ord('\\xff'))
+ >>> b == '\\xff' or b == '\\xff'.encode('ISO-8859-1') # Py2 or Py3
+ True
+ """
+ cdef bytes s = c
+ return s
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_int_bytes_assign(int c):
+ """
+ Implicit int -> bytes coercion in assignments
+
+ >>> coerce_int_bytes_assign(ord('A')) == 'A'.encode('ASCII')
+ True
+
+ >>> coerce_int_bytes_assign(ord('A') + 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ >>> coerce_int_bytes_assign(ord('A') - 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ """
+ cdef bytes s = c
+ return s
+
+
+@cython.test_assert_path_exists("//CoerceIntToBytesNode")
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def coerce_uint_bytes_assign(unsigned int c):
+ """
+ Implicit uint -> bytes coercion in assignments
+
+ >>> coerce_uint_bytes_assign(ord('A')) == 'A'.encode('ASCII')
+ True
+ >>> b = coerce_uint_bytes_assign(ord('\\xff'))
+ >>> b == '\\xff' or b == '\\xff'.encode('ISO-8859-1') # Py2 or Py3
+ True
+
+ >>> coerce_uint_bytes_assign(ord('A') + 0x100)
+ Traceback (most recent call last):
+ OverflowError: value too large to pack into a byte
+ """
+ cdef bytes s = c
+ return s