diff -r d37f963394aa Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst Mon Mar 03 21:16:27 2014 +0200 +++ b/Doc/c-api/arg.rst Tue Mar 04 16:24:03 2014 +0200 @@ -201,9 +201,10 @@ .. versionadded:: 2.5 -``c`` (string of length 1) [char] - Convert a Python character, represented as a string of length 1, to a C - :c:type:`char`. +``c`` (string or Unicode of length 1) [char] + Convert a Python character, represented as a string or Unicode object of + length 1, to a C :c:type:`char`. Unicode object must contain ASCII + character (with code less 128). ``f`` (float) [float] Convert a Python floating point number to a C :c:type:`float`. diff -r d37f963394aa Lib/test/string_tests.py --- a/Lib/test/string_tests.py Mon Mar 03 21:16:27 2014 +0200 +++ b/Lib/test/string_tests.py Tue Mar 04 16:24:03 2014 +0200 @@ -546,6 +546,9 @@ self.checkequal('abc', 'abc', 'ljust', 2) self.checkequal('abc*******', 'abc', 'ljust', 10, '*') self.checkraises(TypeError, 'abc', 'ljust') + if test_support.have_unicode and self.type2test is not unicode: + self.checkequal('abc*******', 'abc', 'ljust', 10, unicode('*')) + self.checkraises(TypeError, 'abc', 'ljust', 10, unichr(0xb7)) def test_rjust(self): self.checkequal(' abc', 'abc', 'rjust', 10) @@ -554,6 +557,9 @@ self.checkequal('abc', 'abc', 'rjust', 2) self.checkequal('*******abc', 'abc', 'rjust', 10, '*') self.checkraises(TypeError, 'abc', 'rjust') + if test_support.have_unicode and self.type2test is not unicode: + self.checkequal('*******abc', 'abc', 'rjust', 10, unicode('*')) + self.checkraises(TypeError, 'abc', 'rjust', 10, unichr(0xb7)) def test_center(self): self.checkequal(' abc ', 'abc', 'center', 10) @@ -562,6 +568,9 @@ self.checkequal('abc', 'abc', 'center', 2) self.checkequal('***abc****', 'abc', 'center', 10, '*') self.checkraises(TypeError, 'abc', 'center') + if test_support.have_unicode and self.type2test is not unicode: + self.checkequal('***abc****', 'abc', 'center', 10, unicode('*')) + self.checkraises(TypeError, 'abc', 'center', 10, unichr(0xb7)) def test_swapcase(self): self.checkequal('hEllO CoMPuTErS', 'HeLLo cOmpUteRs', 'swapcase') @@ -1078,6 +1087,9 @@ self.checkequal('$', "%c", '__mod__', 36) self.checkequal('10', "%d", '__mod__', 10) self.checkequal('\x7f', "%c", '__mod__', 0x7f) + if test_support.have_unicode and self.type2test is not unicode: + self.checkequal('a', '%c', '__mod__', unicode('a')) + self.checkequal(unichr(0xb5), '%c', '__mod__', unichr(0xb5)) for ordinal in (-100, 0x200000): # unicode raises ValueError, str raises OverflowError diff -r d37f963394aa Lib/test/test_array.py --- a/Lib/test/test_array.py Mon Mar 03 21:16:27 2014 +0200 +++ b/Lib/test/test_array.py Tue Mar 04 16:24:03 2014 +0200 @@ -20,15 +20,20 @@ tests = [] # list to accumulate all tests typecodes = "cubBhHiIlLfd" -class BadConstructorTest(unittest.TestCase): +class ConstructorTest(unittest.TestCase): - def test_constructor(self): + def test_bad_constructor(self): self.assertRaises(TypeError, array.array) self.assertRaises(TypeError, array.array, spam=42) self.assertRaises(TypeError, array.array, 'xx') self.assertRaises(ValueError, array.array, 'x') -tests.append(BadConstructorTest) + @unittest.skipUnless(test_support.have_unicode, 'requires Unicode') + def test_constructor_unicode(self): + array.array(unicode('c')) + self.assertRaises(TypeError, array.array, unichr(0xb5)) + +tests.append(ConstructorTest) class BaseTest(unittest.TestCase): # Required class attributes (provided by subclasses @@ -832,6 +837,15 @@ self.assertRaises(ValueError, a.fromunicode, unicode('')) self.assertRaises(ValueError, a.tounicode) + def test_setitem(self): + super(CharacterTest, self).test_setitem() + + a = array.array(self.typecode, self.example) + a[0] = unicode('a') + self.assertEntryEqual(a[0], 'a') + with self.assertRaises(TypeError): + a[0] = unichr(0xb5) + tests.append(CharacterTest) if test_support.have_unicode: diff -r d37f963394aa Lib/test/test_datetime.py --- a/Lib/test/test_datetime.py Mon Mar 03 21:16:27 2014 +0200 +++ b/Lib/test/test_datetime.py Tue Mar 04 16:24:03 2014 +0200 @@ -1194,6 +1194,9 @@ self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123") self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123") self.assertEqual(t.isoformat('\x00'), "0002-03-02\x0004:05:01.000123") + if test_support.have_unicode: + self.assertEqual(t.isoformat(unicode('x')), "0002-03-02x04:05:01.000123") + self.assertRaises(TypeError, t.isoformat, unichr(0xb5)) # str is ISO format with the separator forced to a blank. self.assertEqual(str(t), "0002-03-02 04:05:01.000123") diff -r d37f963394aa Lib/test/test_getargs2.py --- a/Lib/test/test_getargs2.py Mon Mar 03 21:16:27 2014 +0200 +++ b/Lib/test/test_getargs2.py Tue Mar 04 16:24:03 2014 +0200 @@ -331,9 +331,21 @@ else: self.fail('TypeError should have been raised') +class Bytes_TestCase(unittest.TestCase): + def test_c(self): + from _testcapi import getargs_c + self.assertRaises(TypeError, getargs_c, 'abc') # len > 1 + self.assertEqual(getargs_c('a'), 'a') + self.assertRaises(TypeError, getargs_c, bytearray('a')) + self.assertRaises(TypeError, getargs_c, memoryview('a')) + if test_support.have_unicode: + self.assertEqual(getargs_c(unicode('s')), 's') + self.assertRaises(TypeError, getargs_c, unichr(0xb5)) + self.assertRaises(TypeError, getargs_c, None) + def test_main(): tests = [Signed_TestCase, Unsigned_TestCase, LongLong_TestCase, - Tuple_TestCase, Keywords_TestCase] + Tuple_TestCase, Keywords_TestCase, Bytes_TestCase] test_support.run_unittest(*tests) if __name__ == "__main__": diff -r d37f963394aa Lib/test/test_mmap.py --- a/Lib/test/test_mmap.py Mon Mar 03 21:16:27 2014 +0200 +++ b/Lib/test/test_mmap.py Tue Mar 04 16:24:03 2014 +0200 @@ -1,5 +1,5 @@ from test.test_support import (TESTFN, run_unittest, import_module, unlink, - requires, _2G, _4G) + requires, have_unicode, _2G, _4G) import unittest import os, re, itertools, socket, sys @@ -580,6 +580,27 @@ m.seek(8) self.assertRaises(ValueError, m.write, "bar") + @unittest.skipUnless(have_unicode, 'requires Unicode') + def test_write_unicode(self): + data = unicode("0123456789") + with open(TESTFN, "wb") as f: + f.write("x"*len(data)) + with open(TESTFN, "r+b") as f: + m = mmap.mmap(f.fileno(), len(data)) + # Test write_byte() + for i in xrange(len(data)): + self.assertEqual(m.tell(), i) + m.write_byte(data[i]) + self.assertEqual(m.tell(), i+1) + self.assertEqual(m[:], data) + # Test write() + m.seek(3) + m.write(unicode("bar")) + self.assertEqual(m.tell(), 6) + self.assertEqual(m[:], "012bar6789") + self.assertRaises(TypeError, m.write_byte, unichr(0xb5)) + self.assertRaises(ValueError, m.write, unichr(0xb5)) + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_tagname(self): data1 = "0123456789" diff -r d37f963394aa Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Mon Mar 03 21:16:27 2014 +0200 +++ b/Modules/_testcapimodule.c Tue Mar 04 16:24:03 2014 +0200 @@ -1015,6 +1015,15 @@ return Py_None; } +static PyObject * +getargs_c(PyObject *self, PyObject *args) +{ + char c; + if (!PyArg_ParseTuple(args, "c", &c)) + return NULL; + return PyBytes_FromStringAndSize(&c, 1); +} + #ifdef Py_USING_UNICODE static volatile int x; @@ -1820,6 +1829,7 @@ {"codec_incrementaldecoder", (PyCFunction)codec_incrementaldecoder, METH_VARARGS}, #endif + {"getargs_c", getargs_c, METH_VARARGS}, #ifdef Py_USING_UNICODE {"test_u_code", (PyCFunction)test_u_code, METH_NOARGS}, {"test_widechar", (PyCFunction)test_widechar, METH_NOARGS}, diff -r d37f963394aa Python/getargs.c --- a/Python/getargs.c Mon Mar 03 21:16:27 2014 +0200 +++ b/Python/getargs.c Tue Mar 04 16:24:03 2014 +0200 @@ -824,6 +824,13 @@ char *p = va_arg(*p_va, char *); if (PyString_Check(arg) && PyString_Size(arg) == 1) *p = PyString_AS_STRING(arg)[0]; + else if (PyUnicode_Check(arg) && PyUnicode_GET_SIZE(arg) == 1) { + Py_UNICODE ch = PyUnicode_AS_UNICODE(arg)[0]; + if (ch < 128) + *p = (char)ch; + else + return converterr("char", arg, msgbuf, bufsize); + } else return converterr("char", arg, msgbuf, bufsize); break;