From 6d970f47134ef812774defe3169c95ee6c4c6bff Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 2 Mar 2011 00:04:25 +0000 Subject: [PATCH] Issue #10831: PyUnicode_FromFormat() supports %li, %lli and %zi formats --- Lib/test/test_unicode.py | 35 ++++++++++++++++++++++++++--------- Misc/NEWS | 2 ++ Objects/unicodeobject.c | 14 +++++--------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index c4e54e78356..5fc30db4d37 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1430,7 +1430,9 @@ class UnicodeTest(string_tests.CommonTest, # Test PyUnicode_FromFormat() def test_from_format(self): support.import_module('ctypes') - from ctypes import pythonapi, py_object, c_int + from ctypes import (pythonapi, py_object, + c_int, c_long, c_longlong, c_ssize_t, + c_uint, c_ulong, c_ulonglong, c_size_t) if sys.maxunicode == 65535: name = "PyUnicodeUCS2_FromFormat" else: @@ -1466,21 +1468,29 @@ class UnicodeTest(string_tests.CommonTest, self.assertEqual(PyUnicode_FromFormat(b'[%%]'), '[%]') self.assertEqual(PyUnicode_FromFormat(b'%%%s', b'abc'), '%abc') - # test "%i" + # test integer formats (%i, %d, %u) self.assertEqual(PyUnicode_FromFormat(b'%03i', c_int(10)), '010') self.assertEqual(PyUnicode_FromFormat(b'%0.4i', c_int(10)), '0010') + self.assertEqual(PyUnicode_FromFormat(b'%i', c_int(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%li', c_long(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%lli', c_longlong(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%zi', c_ssize_t(-123)), '-123') - # not supported: copy the raw format string. these tests are just here - # to check for crashs and should not be considered as specifications - self.assertEqual(PyUnicode_FromFormat(b'%1%s', b'abc'), '%s') - self.assertEqual(PyUnicode_FromFormat(b'%1abc'), '%1abc') - self.assertEqual(PyUnicode_FromFormat(b'%+i', c_int(10)), '%+i') - self.assertEqual(PyUnicode_FromFormat(b'%.%s', b'abc'), '%.%s') + self.assertEqual(PyUnicode_FromFormat(b'%d', c_int(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%ld', c_long(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(-123)), '-123') + self.assertEqual(PyUnicode_FromFormat(b'%zd', c_ssize_t(-123)), '-123') - # other tests + self.assertEqual(PyUnicode_FromFormat(b'%u', c_uint(123)), '123') + self.assertEqual(PyUnicode_FromFormat(b'%lu', c_ulong(123)), '123') + self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(123)), '123') + self.assertEqual(PyUnicode_FromFormat(b'%zu', c_size_t(123)), '123') + + # test %A text = PyUnicode_FromFormat(b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') self.assertEqual(text, r"%A:'abc\xe9\uabcd\U0010ffff'") + # test %V text = PyUnicode_FromFormat(b'repr=%V', 'abc', b'xyz') self.assertEqual(text, 'repr=abc') @@ -1494,6 +1504,13 @@ class UnicodeTest(string_tests.CommonTest, text = PyUnicode_FromFormat(b'repr=%V', None, b'abc\xff') self.assertEqual(text, 'repr=abc\ufffd') + # not supported: copy the raw format string. these tests are just here + # to check for crashs and should not be considered as specifications + self.assertEqual(PyUnicode_FromFormat(b'%1%s', b'abc'), '%s') + self.assertEqual(PyUnicode_FromFormat(b'%1abc'), '%1abc') + self.assertEqual(PyUnicode_FromFormat(b'%+i', c_int(10)), '%+i') + self.assertEqual(PyUnicode_FromFormat(b'%.%s', b'abc'), '%.%s') + # Test PyUnicode_AsWideChar() def test_aswidechar(self): from _testcapi import unicode_aswidechar diff --git a/Misc/NEWS b/Misc/NEWS index 47a4825d742..b87fb127a5e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1? Core and Builtins ----------------- +- Issue #10831: PyUnicode_FromFormat() supports %li, %lli and %zi formats. + - Issue #10829: Refactor PyUnicode_FromFormat(), use the same function to parse the format string in the 3 steps, fix crashs on invalid format strings. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7597a46ab6a..cd0fccf4b5d 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -753,20 +753,20 @@ parse_format_flags(const char *f, size_tflag = 0; if (*f == 'l') { - if (f[1] == 'd' || f[1] == 'u') { + if (f[1] == 'd' || f[1] == 'u' || f[1] == 'i') { longflag = 1; ++f; } #ifdef HAVE_LONG_LONG else if (f[1] == 'l' && - (f[2] == 'd' || f[2] == 'u')) { + (f[2] == 'd' || f[2] == 'u' || f[2] == 'i')) { longlongflag = 1; f += 2; } #endif } /* handle the size_t flag. */ - else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) { + else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u' || f[1] == 'i')) { size_tflag = 1; ++f; } @@ -1044,9 +1044,10 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) *s++ = ordinal; break; } + case 'i': case 'd': makefmt(fmt, longflag, longlongflag, size_tflag, zeropad, - width, precision, 'd'); + width, precision, *f); if (longflag) sprintf(realbuffer, fmt, va_arg(vargs, long)); #ifdef HAVE_LONG_LONG @@ -1075,11 +1076,6 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) sprintf(realbuffer, fmt, va_arg(vargs, unsigned int)); appendstring(realbuffer); break; - case 'i': - makefmt(fmt, 0, 0, 0, zeropad, width, precision, 'i'); - sprintf(realbuffer, fmt, va_arg(vargs, int)); - appendstring(realbuffer); - break; case 'x': makefmt(fmt, 0, 0, 0, zeropad, width, precision, 'x'); sprintf(realbuffer, fmt, va_arg(vargs, int));