Merge 3.3.
This commit is contained in:
commit
8d90e383a3
|
@ -6138,7 +6138,7 @@ _parse_format_specifier_regex = re.compile(r"""\A
|
||||||
(?:\.(?P<precision>0|(?!0)\d+))?
|
(?:\.(?P<precision>0|(?!0)\d+))?
|
||||||
(?P<type>[eEfFgGn%])?
|
(?P<type>[eEfFgGn%])?
|
||||||
\Z
|
\Z
|
||||||
""", re.VERBOSE)
|
""", re.VERBOSE|re.DOTALL)
|
||||||
|
|
||||||
del re
|
del re
|
||||||
|
|
||||||
|
|
|
@ -1020,6 +1020,10 @@ class FormatTest(unittest.TestCase):
|
||||||
('/=10', '-45.6', '-/////45.6'),
|
('/=10', '-45.6', '-/////45.6'),
|
||||||
('/=+10', '45.6', '+/////45.6'),
|
('/=+10', '45.6', '+/////45.6'),
|
||||||
('/= 10', '45.6', ' /////45.6'),
|
('/= 10', '45.6', ' /////45.6'),
|
||||||
|
('\x00=10', '-inf', '-\x00Infinity'),
|
||||||
|
('\x00^16', '-inf', '\x00\x00\x00-Infinity\x00\x00\x00\x00'),
|
||||||
|
('\x00>10', '1.2345', '\x00\x00\x00\x001.2345'),
|
||||||
|
('\x00<10', '1.2345', '1.2345\x00\x00\x00\x00'),
|
||||||
|
|
||||||
# thousands separator
|
# thousands separator
|
||||||
(',', '1234567', '1,234,567'),
|
(',', '1234567', '1,234,567'),
|
||||||
|
|
|
@ -3096,6 +3096,29 @@ dec_repr(PyObject *dec)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a duplicate of src, copy embedded null characters. */
|
||||||
|
static char *
|
||||||
|
dec_strdup(const char *src, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
char *dest = PyMem_Malloc(size+1);
|
||||||
|
if (dest == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dest, src, size);
|
||||||
|
dest[size] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dec_replace_fillchar(char *dest)
|
||||||
|
{
|
||||||
|
while (*dest != '\0') {
|
||||||
|
if (*dest == '\xff') *dest = '\0';
|
||||||
|
dest++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert decimal_point or thousands_sep, which may be multibyte or in
|
/* Convert decimal_point or thousands_sep, which may be multibyte or in
|
||||||
the range [128, 255], to a UTF8 string. */
|
the range [128, 255], to a UTF8 string. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -3131,13 +3154,14 @@ dec_format(PyObject *dec, PyObject *args)
|
||||||
PyObject *dot = NULL;
|
PyObject *dot = NULL;
|
||||||
PyObject *sep = NULL;
|
PyObject *sep = NULL;
|
||||||
PyObject *grouping = NULL;
|
PyObject *grouping = NULL;
|
||||||
PyObject *fmt = NULL;
|
|
||||||
PyObject *fmtarg;
|
PyObject *fmtarg;
|
||||||
PyObject *context;
|
PyObject *context;
|
||||||
mpd_spec_t spec;
|
mpd_spec_t spec;
|
||||||
|
char *fmt;
|
||||||
char *decstring = NULL;
|
char *decstring = NULL;
|
||||||
uint32_t status = 0;
|
uint32_t status = 0;
|
||||||
size_t n;
|
int replace_fillchar = 0;
|
||||||
|
Py_ssize_t size;
|
||||||
|
|
||||||
|
|
||||||
CURRENT_CONTEXT(context);
|
CURRENT_CONTEXT(context);
|
||||||
|
@ -3146,10 +3170,20 @@ dec_format(PyObject *dec, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyUnicode_Check(fmtarg)) {
|
if (PyUnicode_Check(fmtarg)) {
|
||||||
fmt = PyUnicode_AsUTF8String(fmtarg);
|
fmt = PyUnicode_AsUTF8AndSize(fmtarg, &size);
|
||||||
if (fmt == NULL) {
|
if (fmt == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (size > 0 && fmt[0] == '\0') {
|
||||||
|
/* NUL fill character: must be replaced with a valid UTF-8 char
|
||||||
|
before calling mpd_parse_fmt_str(). */
|
||||||
|
replace_fillchar = 1;
|
||||||
|
fmt = dec_strdup(fmt, size);
|
||||||
|
if (fmt == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fmt[0] = '_';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
@ -3157,12 +3191,19 @@ dec_format(PyObject *dec, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt),
|
if (!mpd_parse_fmt_str(&spec, fmt, CtxCaps(context))) {
|
||||||
CtxCaps(context))) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
if (replace_fillchar) {
|
||||||
|
/* In order to avoid clobbering parts of UTF-8 thousands separators or
|
||||||
|
decimal points when the substitution is reversed later, the actual
|
||||||
|
placeholder must be an invalid UTF-8 byte. */
|
||||||
|
spec.fill[0] = '\xff';
|
||||||
|
spec.fill[1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
if (override) {
|
if (override) {
|
||||||
/* Values for decimal_point, thousands_sep and grouping can
|
/* Values for decimal_point, thousands_sep and grouping can
|
||||||
be explicitly specified in the override dict. These values
|
be explicitly specified in the override dict. These values
|
||||||
|
@ -3199,7 +3240,7 @@ dec_format(PyObject *dec, PyObject *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
n = strlen(spec.dot);
|
size_t n = strlen(spec.dot);
|
||||||
if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) {
|
if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) {
|
||||||
/* fix locale dependent non-ascii characters */
|
/* fix locale dependent non-ascii characters */
|
||||||
dot = dotsep_as_utf8(spec.dot);
|
dot = dotsep_as_utf8(spec.dot);
|
||||||
|
@ -3231,14 +3272,19 @@ dec_format(PyObject *dec, PyObject *args)
|
||||||
}
|
}
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL);
|
size = strlen(decstring);
|
||||||
|
if (replace_fillchar) {
|
||||||
|
dec_replace_fillchar(decstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = PyUnicode_DecodeUTF8(decstring, size, NULL);
|
||||||
|
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
Py_XDECREF(grouping);
|
Py_XDECREF(grouping);
|
||||||
Py_XDECREF(sep);
|
Py_XDECREF(sep);
|
||||||
Py_XDECREF(dot);
|
Py_XDECREF(dot);
|
||||||
Py_XDECREF(fmt);
|
if (replace_fillchar) PyMem_Free(fmt);
|
||||||
if (decstring) mpd_free(decstring);
|
if (decstring) mpd_free(decstring);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -891,7 +891,7 @@ def test_ternary(method, prec, exp_range, restricted_range, itr, stat):
|
||||||
def test_format(method, prec, exp_range, restricted_range, itr, stat):
|
def test_format(method, prec, exp_range, restricted_range, itr, stat):
|
||||||
"""Iterate the __format__ method through many test cases."""
|
"""Iterate the __format__ method through many test cases."""
|
||||||
for op in all_unary(prec, exp_range, itr):
|
for op in all_unary(prec, exp_range, itr):
|
||||||
fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn')
|
fmt1 = rand_format(chr(random.randrange(0, 128)), 'EeGgn')
|
||||||
fmt2 = rand_locale()
|
fmt2 = rand_locale()
|
||||||
for fmt in (fmt1, fmt2):
|
for fmt in (fmt1, fmt2):
|
||||||
fmtop = (op[0], fmt)
|
fmtop = (op[0], fmt)
|
||||||
|
@ -904,7 +904,7 @@ def test_format(method, prec, exp_range, restricted_range, itr, stat):
|
||||||
except VerifyError as err:
|
except VerifyError as err:
|
||||||
log(err)
|
log(err)
|
||||||
for op in all_unary(prec, 9999, itr):
|
for op in all_unary(prec, 9999, itr):
|
||||||
fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%')
|
fmt1 = rand_format(chr(random.randrange(0, 128)), 'Ff%')
|
||||||
fmt2 = rand_locale()
|
fmt2 = rand_locale()
|
||||||
for fmt in (fmt1, fmt2):
|
for fmt in (fmt1, fmt2):
|
||||||
fmtop = (op[0], fmt)
|
fmtop = (op[0], fmt)
|
||||||
|
|
|
@ -215,8 +215,6 @@ def check_fillchar(i):
|
||||||
c = chr(i)
|
c = chr(i)
|
||||||
c.encode('utf-8').decode()
|
c.encode('utf-8').decode()
|
||||||
format(P.Decimal(0), c + '<19g')
|
format(P.Decimal(0), c + '<19g')
|
||||||
if c in ("'", '"', '\\'):
|
|
||||||
return None
|
|
||||||
return c
|
return c
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
@ -224,14 +222,14 @@ def check_fillchar(i):
|
||||||
# Generate all unicode characters that are accepted as
|
# Generate all unicode characters that are accepted as
|
||||||
# fill characters by decimal.py.
|
# fill characters by decimal.py.
|
||||||
def all_fillchars():
|
def all_fillchars():
|
||||||
for i in range(32, 0x110002):
|
for i in range(0, 0x110002):
|
||||||
c = check_fillchar(i)
|
c = check_fillchar(i)
|
||||||
if c: yield c
|
if c: yield c
|
||||||
|
|
||||||
# Return random fill character.
|
# Return random fill character.
|
||||||
def rand_fillchar():
|
def rand_fillchar():
|
||||||
while 1:
|
while 1:
|
||||||
i = random.randrange(32, 0x110002)
|
i = random.randrange(0, 0x110002)
|
||||||
c = check_fillchar(i)
|
c = check_fillchar(i)
|
||||||
if c: return c
|
if c: return c
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue