You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
_localemodule.c: str2uni() with different LC_NUMERIC and LC_CTYPE #51691
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2014-10-14.19:30:57.384>created_at=<Date2009-12-05.10:44:18.463>labels= ['type-bug']
title='_localemodule.c: str2uni() with different LC_NUMERIC and LC_CTYPE'updated_at=<Date2018-01-10.15:46:42.607>user='https://github.com/skrah'
>>> import locale
>>> from decimal import*
>>> locale.setlocale(locale.LC_NUMERIC, 'fi_FI')
'fi_FI'
>>> format(Decimal('1000'), 'n')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.2/decimal.py", line 3632, in __format__
spec = _parse_format_specifier(specifier, _localeconv=_localeconv)
File "/usr/lib/python3.2/decimal.py", line 5628, in
_parse_format_specifier
_localeconv = _locale.localeconv()
File "/usr/lib/python3.2/locale.py", line 111, in localeconv
d = _localeconv()
ValueError: Cannot convert byte to string
skrah commented on Dec 5, 2009
skrahmannequin
MannequinAuthor
More actions
This fails in _localemodule.c: str2uni(). mbstowcs(NULL, s, 0) is
LC_CTYPE sensitive, but LC_CTYPE is UTF-8 in my terminal.
If I set LC_CTYPE and LC_NUMERIC together, things work.
This raises the question: If LC_CTYPE and LC_NUMERIC differ (and
since they are separate entities I assume they may differ), what
is the correct way to convert the separator and the decimal point?
a) call setlocale(LC_CTYPE, setlocale(LC_NUMERIC, NULL)) before
mbstowcs. This is not really an option.
I'm failing to reproduce this (with py3k) on OS X:
Python 3.2a0 (py3k:76866:76867, Dec 17 2009, 09:19:26)
[GCC 4.2.1 (Apple Inc. build 5646) (dot 1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> from decimal import*
>>> locale.setlocale(locale.LC_NUMERIC, 'fi_FI')
'fi_FI'
>>> format(Decimal('1000'), 'n')
'1.000'
The locale command, from the same Terminal prompt, gives me:
What are the multibyte strings that mbstowcs is failing to convert?
On my machine, the separators come out as plain ASCII '.' (for thousands)
and ',' (for the decimal point).
The problem is thousands_sep:
(gdb) p l->thousands_sep
$2 = 0xb7b54022 " "
(gdb) p (unsigned char)l->thousands_sep[0]
$3 = 160 ' '
skrah commented on Dec 18, 2009
skrahmannequin
MannequinAuthor
More actions
Yes, it's a problem in _localemodule.c. This situation always
occurs when LC_NUMERIC is something like ISO8859-15, LC_CTYPE
is UTF-8 AND the decimal point or separator are in the range
128-255. Then mbstowcs tries to decode the character according
to LC_CTYPE and finds that the character is not valid UTF-8:
I don't think this issue is important enough to do that. What
I do in cdecimal is raise an error "Invalid separator or
unsupported combination of LC_NUMERIC and LC_CTYPE".
skrah commented on Dec 18, 2009
skrahmannequin
MannequinAuthor
More actions
Changed title (was: decimal.py: format failure with locale specifier)
changed the title [-]decimal.py: format failure with locale specifier[/-][+]_localemodule.c: str2uni() with different LC_NUMERIC and LC_CTYPE[/+]on Dec 18, 2009
Traceback (most recent call last):
File "/home/matej/build/Extras/python3/Python-3.3.2/Lib/test/test_format.py", line 295, in test_locale
localeconv = locale.localeconv()
File "/home/matej/build/Extras/python3/Python-3.3.2/Lib/locale.py", line 111, in localeconv
d = _localeconv()
UnicodeDecodeError: 'locale' codec can't decode byte 0xe2 in position 0: Invalid or incomplete multibyte or wide character
(or any other explicit locale, I have tried also en_IE) test doesn't fail.
Using Python-3.3.2 on RHEL-6 (kernel 2.6.32-358.23.2.el6.i686).
mcepl commented on Oct 22, 2013
mceplmannequin
Mannequin
More actions
To bpo-200912: now, system locale is UTF-8 all the way:
santiago:python3 (el6) $ locale
LANG=en_US.utf8
LC_CTYPE="en_US.utf8"
LC_NUMERIC=en_IE.utf8
LC_TIME=en_IE.utf8
LC_COLLATE="en_US.utf8"
LC_MONETARY=en_IE.utf8
LC_MESSAGES="en_US.utf8"
LC_PAPER=en_IE.utf8
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT=en_IE.utf8
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=
santiago:python3 (el6) $
9 remaining items
skrah commented on Oct 22, 2013
skrahmannequin
MannequinAuthor
More actions
Victor, thanks for the comments. I also think we should set LC_CTYPE closer
to the actual call to mbstowcs(), otherwise there are many API calls in
between.
So it should happen somewhere in PyUnicode_DecodeLocaleAndSize(). Perhaps
we can create _PyUnicode_DecodeLocaleAndSize() which would take an LC_CTYPE
parameter?
santiago:optimized (el6) $ ./python -m test test_format
[1/1] test_format
1 test OK.
It looks like some other test in the test suite did not restore a changed
locale. If you're motivated enough, you could try if it still happens in
3.4 and open a new issue (it's unrelated to this one).
"So it should happen somewhere in PyUnicode_DecodeLocaleAndSize(). Perhaps we can create _PyUnicode_DecodeLocaleAndSize() which would take an LC_CTYPE parameter?"
For this issue, it means that Python localeconv() will have to change the LC_CTYPE locale many time, for each monetary and each number value. I prefer your patch :-)
mcepl commented on Oct 22, 2013
mceplmannequin
Mannequin
More actions
On 22/10/13 17:32, Stefan Krah wrote:
It looks like some other test in the test suite did not restore a changed
locale. If you're motivated enough, you could try if it still happens in
3.4 and open a new issue (it's unrelated to this one).
Very plain checkout of git and ./configure && make && make test leads to
another failed test, but not this one (issue bpo-19353). So either we do
something wrong in all those Fedora patches, or this has been fixed
since 3.3.2.
"So it should happen somewhere in PyUnicode_DecodeLocaleAndSize(). Perhaps we can create _PyUnicode_DecodeLocaleAndSize() which would take an LC_CTYPE parameter?"
For this issue, it means that Python localeconv() will have to change the LC_CTYPE locale many time, for each monetary and each number value. I prefer your patch :-)
Windows and OS X have mbstowcs_l(), which takes a locale arg. Linux doesn't
(as far as I can see). I agree this solution is ugly, but it probably won't
have an impact on benchmarks (naively assuming that setlocale() is fast).
skrah commented on Oct 22, 2013
skrahmannequin
MannequinAuthor
More actions
Here's a quick-and-dirty version of mbstowcs_l(). The difference in the
benchmark to the plain mbstowcs() is 0.82s vs 0.55s. In the context of
a Python function this is unlikely to be measurable.
The issue has a workaround: use LC_NUMERIC and LC_CTYPE locales which use the same encoding. To avoid issues, it's probably safer to only use UTF-8 locales, which are now available on modern Linux distro.
I don't like the idea of calling setlocale() just for this corner case, because it changes the locale for all threads. Even if Python is protected by the GIL, Python can be embedded or modules written in C may spawn threads which don't care of the GIL. Usually, if it can fail, it will fail :-)
I see that various people contributed to the issue, but it looks like the only user asking for the request is Stefan Krah. I prefer to close the issue and wait until more users ask for it before considering again the patch, or find a different way to implement the feature (support LC_NUMERIC and LC_CTYPE locales using a different encoding).
I prefer to close the issue and wait until more users ask for it before considering again the patch, or find a different way to implement the feature (support LC_NUMERIC and LC_CTYPE locales using a different encoding).
Activity
skrah commentedon Dec 5, 2009
Hi, the following works in 2.7 but not in 3.x:
skrah commentedon Dec 5, 2009
This fails in _localemodule.c: str2uni(). mbstowcs(NULL, s, 0) is
LC_CTYPE sensitive, but LC_CTYPE is UTF-8 in my terminal.
If I set LC_CTYPE and LC_NUMERIC together, things work.
This raises the question: If LC_CTYPE and LC_NUMERIC differ (and
since they are separate entities I assume they may differ), what
is the correct way to convert the separator and the decimal point?
a) call setlocale(LC_CTYPE, setlocale(LC_NUMERIC, NULL)) before
mbstowcs. This is not really an option.
b) use some kind of _mbstowcs_l
(http://msdn.microsoft.com/en-us/library/k1f9b8cy(VS.80).aspx), which
takes a locale parameter. But I don't
find such a thing on Linux.
mdickinson commentedon Dec 17, 2009
I'm failing to reproduce this (with py3k) on OS X:
The locale command, from the same Terminal prompt, gives me:
Just to be clear, is is true that you still get the same result without
involving Decimal at all? That is, am I correct in assuming that:
also gives you that ValueError?
mdickinson commentedon Dec 17, 2009
What are the multibyte strings that mbstowcs is failing to convert?
On my machine, the separators come out as plain ASCII '.' (for thousands)
and ',' (for the decimal point).
ericvsmith commentedon Dec 18, 2009
I can reproduce it on a Fedora (fc6) Linux box. It's not a decimal
problem, but a plain locale problem:
Here's the contents of the struct lconv as returned by localeconv():
((gdb) p *l
$1 = {decimal_point = 0xb7b54020 ",", thousands_sep = 0xb7b54022 " ",
grouping = 0xb7b54024 "\003\003",
int_curr_symbol = 0x998858 "", currency_symbol = 0x998858 "",
mon_decimal_point = 0x998858 "", mon_thousands_sep = 0x998858 "",
mon_grouping = 0x998858 "", positive_sign = 0x998858 "", negative_sign
= 0x998858 "", int_frac_digits = 127 '\177',
frac_digits = 127 '\177', p_cs_precedes = 127 '\177', p_sep_by_space =
127 '\177', n_cs_precedes = 127 '\177',
n_sep_by_space = 127 '\177', p_sign_posn = 127 '\177', n_sign_posn =
127 '\177', int_p_cs_precedes = 127 '\177',
int_p_sep_by_space = 127 '\177', int_n_cs_precedes = 127 '\177',
int_n_sep_by_space = 127 '\177', int_p_sign_posn = 127 '\177',
int_n_sign_posn = 127 '\177'}
The problem is thousands_sep:
(gdb) p l->thousands_sep
$2 = 0xb7b54022 " "
(gdb) p (unsigned char)l->thousands_sep[0]
$3 = 160 ' '
skrah commentedon Dec 18, 2009
Yes, it's a problem in _localemodule.c. This situation always
occurs when LC_NUMERIC is something like ISO8859-15, LC_CTYPE
is UTF-8 AND the decimal point or separator are in the range
128-255. Then mbstowcs tries to decode the character according
to LC_CTYPE and finds that the character is not valid UTF-8:
I can't see a portable way to fix this except:
block threads
set temporary LC_CTYPE
call mbstowcs
restore LC_CTYPE
unblock threads
I don't think this issue is important enough to do that. What
I do in cdecimal is raise an error "Invalid separator or
unsupported combination of LC_NUMERIC and LC_CTYPE".
skrah commentedon Dec 18, 2009
Changed title (was: decimal.py: format failure with locale specifier)
[-]decimal.py: format failure with locale specifier[/-][+]_localemodule.c: str2uni() with different LC_NUMERIC and LC_CTYPE[/+]skrah commentedon Feb 13, 2010
I have a patch that fixes this specific issue. Probably there are similar
issues in other places, e.g. when LC_TIME and LC_CTYPE differ.
I suspect that this is related:
http://bugs.python.org/issue5905
BreamoreBoy commentedon May 26, 2013
Could we have a patch review please. Also note that bpo-5905 has been closed.
mcepl commentedon Oct 22, 2013
Is this the same as when tests with python-3.3.2 fails on me with RHEL-6?
test_locale (test.test_format.FormatTest) ... ERROR
test_non_ascii (test.test_format.FormatTest) ... test test_format failed
'\u20ac=%f' % (1.0,) =? '\u20ac=1.000000' ... yes
ok
======================================================================
ERROR: test_locale (test.test_format.FormatTest)
----------------------------------------------------------------------
skrah commentedon Oct 22, 2013
Matej Cepl <report@bugs.python.org> wrote:
If LC_CTYPE is UTF-8 and LC_NUMERIC something like ISO-8859-2 then it's
the same issue.
mcepl commentedon Oct 22, 2013
Hmm, so with this patch
(or any other explicit locale, I have tried also en_IE) test doesn't fail.
Using Python-3.3.2 on RHEL-6 (kernel 2.6.32-358.23.2.el6.i686).
mcepl commentedon Oct 22, 2013
To bpo-200912: now, system locale is UTF-8 all the way:
santiago:python3 (el6) $ locale
LANG=en_US.utf8
LC_CTYPE="en_US.utf8"
LC_NUMERIC=en_IE.utf8
LC_TIME=en_IE.utf8
LC_COLLATE="en_US.utf8"
LC_MONETARY=en_IE.utf8
LC_MESSAGES="en_US.utf8"
LC_PAPER=en_IE.utf8
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT=en_IE.utf8
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=
santiago:python3 (el6) $
9 remaining items
skrah commentedon Oct 22, 2013
Victor, thanks for the comments. I also think we should set LC_CTYPE closer
to the actual call to mbstowcs(), otherwise there are many API calls in
between.
So it should happen somewhere in PyUnicode_DecodeLocaleAndSize(). Perhaps
we can create _PyUnicode_DecodeLocaleAndSize() which would take an LC_CTYPE
parameter?
skrah commentedon Oct 22, 2013
Matej Cepl <report@bugs.python.org> wrote:
It looks like some other test in the test suite did not restore a changed
locale. If you're motivated enough, you could try if it still happens in
3.4 and open a new issue (it's unrelated to this one).
vstinner commentedon Oct 22, 2013
"So it should happen somewhere in PyUnicode_DecodeLocaleAndSize(). Perhaps we can create _PyUnicode_DecodeLocaleAndSize() which would take an LC_CTYPE parameter?"
For this issue, it means that Python localeconv() will have to change the LC_CTYPE locale many time, for each monetary and each number value. I prefer your patch :-)
mcepl commentedon Oct 22, 2013
On 22/10/13 17:32, Stefan Krah wrote:
Very plain checkout of git and ./configure && make && make test leads to
another failed test, but not this one (issue bpo-19353). So either we do
something wrong in all those Fedora patches, or this has been fixed
since 3.3.2.
Curiouser and curiouser.
skrah commentedon Oct 22, 2013
STINNER Victor <report@bugs.python.org> wrote:
Windows and OS X have mbstowcs_l(), which takes a locale arg. Linux doesn't
(as far as I can see). I agree this solution is ugly, but it probably won't
have an impact on benchmarks (naively assuming that setlocale() is fast).
skrah commentedon Oct 22, 2013
Here's a quick-and-dirty version of mbstowcs_l(). The difference in the
benchmark to the plain mbstowcs() is 0.82s vs 0.55s. In the context of
a Python function this is unlikely to be measurable.
vstinner commentedon Nov 4, 2013
@Stefan: Did you my comments on Rietveld?
http://bugs.python.org/review/7442/#ps1473
skrah commentedon Nov 4, 2013
Yes, I saw the comments. I'm still wondering if we should just write an
mbstowcs_l() function instead.
Even then, there would still be a small chance that a C extension that
creates its own thread picks up the wrong LC_CTYPE.
vstinner commentedon Nov 4, 2013
What is this locale_t type used for the locale parameter of mbstowcs_l()? Are you sure that it is a string? According to this patch, it looks like a structure:
http://www.winehq.org/pipermail/wine-cvs/2010-May/067264.html
skrah commentedon Nov 4, 2013
STINNER Victor <report@bugs.python.org> wrote:
Yes, the string was mainly for benchmarking. FreeBSD seems to have thread safe
versions (xlocale.h), that take a locale_t as the extra parameter.
skrah commentedon Oct 14, 2014
Well, I originally opened this issue but personally I'm not that
bothered by it any more.
Victor, do you want to keep it open?
vstinner commentedon Oct 14, 2014
The issue has a workaround: use LC_NUMERIC and LC_CTYPE locales which use the same encoding. To avoid issues, it's probably safer to only use UTF-8 locales, which are now available on modern Linux distro.
I don't like the idea of calling setlocale() just for this corner case, because it changes the locale for all threads. Even if Python is protected by the GIL, Python can be embedded or modules written in C may spawn threads which don't care of the GIL. Usually, if it can fail, it will fail :-)
I see that various people contributed to the issue, but it looks like the only user asking for the request is Stefan Krah. I prefer to close the issue and wait until more users ask for it before considering again the patch, or find a different way to implement the feature (support LC_NUMERIC and LC_CTYPE locales using a different encoding).
To be clear, I'm closing the issue right now.
vstinner commentedon Jan 10, 2018
Here we are: https://bugs.python.org/issue31900