GeezerVison is showing github.com — Deprecation of locale.getdefaultlocale breaks POSIX compatibility on Windows platform · Issue #130796 · python/cpython
Deprecation of locale.getdefaultlocale breaks POSIX compatibility on Windows platform #130796DescriptionBug report
Bug description:
Follow-up to #90817.
In summary, without getdetfaultlocale, tools that rely on POSIX locales cannot reliably get the same information from getlocale or setlocale on Windows.
For example, Linux will return something like 'en_AU'. But on Windows, getlocale will return something like 'English_Australia'.
CPython versions tested on:
3.12, 3.13
Operating systems tested on:
Windows, Linux
Linked PRs
Reacted by Andrew Shteren, 星途, Jesse205, Gregory P. Smith and Brénainn Woodsend Activitypicnixz commented on Mar 3, 2025 I'm afraid that this issue is too late because the ship has already sailed. I don't remember well which alternatives there are for that kind of issue so I'll tag @vstinner who was responsible for the original patch. However, I doubt that we would reinstate locale.getdefaultlocale (or we would do something else).
EDIT: Actually it seems to only be deprecated and planned for removal in 3.15: #111187. Wedge009 commented on Mar 3, 2025 I don't think I - or others - was asking for a reinstatement, just a viable alternative for the cases where POSIX locales are expected for use with other tools such as gettext.
And yes, removal is planned for 3.15, hence the discussion now. As noted in wesnoth/wesnoth#9972 (comment), it's difficult to know how to work around the removal of getdefaultlocale when we don't know what future plans are - if any - for any replacement functionality. vstinner commented on Mar 3, 2025 On my Windows 11 VM, getlocale() returns a "POSIX" locale as expected:
vstinner@WIN C:\victor\python\main>python
Python 3.14.0a5+ (heads/pr/130452-dirty:6a5dc1a8ba6, Feb 26 2025, 17:30:51) [MSC v.1943 32 bit (Intel)] on win32
>>> import locale
>>> locale.getlocale()
('fr_FR', 'cp1252')
>>> locale.setlocale(locale.LC_CTYPE, None)
'French_France.1252'
Can you please elaborate your issue? What are the results of locale.getlocale() and locale.setlocale(locale.LC_CTYPE, None)? Wedge009 commented on Mar 3, 2025 It's as I described above and in #90817 (comment).
Python 3.13.2 (tags/v3.13.2:4f8bb39, Feb 4 2025, 15:23:48) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
import locale
locale.getlocale()
('English_Australia', '1252')
locale.setlocale(locale.LC_CTYPE)
'English_Australia.1252'
locale.getdefaultlocale()
Warning (from warnings module):
File "<pyshell#3>", line 1
DeprecationWarning: 'locale.getdefaultlocale' is deprecated and slated for removal in Python 3.15. Use setlocale(), getencoding() and getlocale() instead.
('en_AU', 'cp1252')
@shineworld reported something similar in #90817 (comment)
@Elvish-Hunter reports the same in wesnoth/wesnoth#9972 (comment) Reacted by Andrew Shteren and 星途 2trvl commented on Mar 6, 2025 The reason why POSIX compatibility breaks is this:
The windows_locale dictionary is only used by the locale.getdefaultlocale() function and this function is deprecated: it will be removed in Python 3.15.
Windows 22H2, Python 3.13.1:
>>> locale.setlocale(locale.LC_CTYPE)
'English_United States.1252'
>>> locale.getlocale()
('English_United States', '1252')
>>> locale.getdefaultlocale()
('en_US', 'cp1252')2trvl commented on Mar 7, 2025 I would like to know how can I find out the system locale for LC_TIME without using defaultlocale?
>>> locale.getdefaultlocale(["LC_TIME"])
('ru_RU', 'UTF-8')
>>> locale.setlocale(locale.LC_TIME)
'C'
>>> locale.getlocale(locale.LC_TIME)
(None, None)
Apparently I have no other option than to change the interpreter locale:
>>> locale.setlocale(locale.LC_TIME, "")
'ru_RU.UTF-8'
>>> locale.getlocale(locale.LC_TIME)
('ru_RU', 'UTF-8')
It is generally a bad idea to call setlocale() in some library routine, since as a side effect it affects the entire program. Saving and restoring it is almost as bad: it is expensive and affects other threads that happen to run before the settings have been restored.
I see that the original reason for removal is the use of non-ASCII characters in locale. Do you think this is a common case?
If fixing the problem is difficult or impossible, perhaps it is worth introducing a similar function called getpreferredlocale? StanFromIreland commented on May 17, 2025 The windows_locale dictionary is well out of date anyway (and is no longer updated from what I can tell), so keeping the function is not great either. The dictionary itself is not deprecated, and so you should be able to use it. If we do want to provide this functionality on windows, it should be better though out.
I was unable to find any windows API that returns the POSIX format. gpshead commented on Dec 20, 2025 I added the 3.15 release blocker labels as if we don't solve this for 3.15 we should stop the deprecation. Reacted by Hugo van Kemenade and 星途 chris-eibl commented on Dec 22, 2025 vstinner commented on Dec 22, 2025 I wasn't aware that locale.getdefaultlocale() is the only way to get a POSIX-like locale name on Windows when I deprecated the function. I didn't know neither that there are users of the "read the locale from environment variables" feature. There is no good replacement for these features, so I wrote #143069 to undeprecate locale.getdefaultlocale(). vstinner commented on Dec 22, 2025 FYI getdefaultlocale() was not removed yet because we are aware of these issues. Reacted by Andrew Shteren malemburg commented on Dec 22, 2025
Whereas locale.getlocale() internally calls C setlocale(LC_CTYPE, NULL) which returns German_Austria for me.
This is then further processed via locale.normalize() which does a lookup in locale_alias
cpython/Lib/locale.py
Line 763 in 786f464
The locale_alias table maps lowercase alias names to C locale names
which fails for German_Austria and all the other examples given in this issue, but succeeds for e.g.
'french_france': 'fr_FR.ISO8859-1',
'german_germany': 'de_DE.ISO8859-1',
Thus, @vstinner gets fr_FR above and @malemburg gets de_DE in #90817 (comment).
I suppose we could make locale.getlocale() work for this use case by adding the Windows locale names to the locale_alias table.
Apparently I have no other option than to change the interpreter locale:
locale.setlocale(locale.LC_TIME, "")
'ru_RU.UTF-8'
locale.getlocale(locale.LC_TIME)
('ru_RU', 'UTF-8')
This is why I had added locale.getdefaultlocale() a long while ago: I did not want to break libraries which rely on other custom local settings by calling setlocale(LC_ALL, ""), since this then applies to the whole process. Doing so at random times can be especially problematic for embedded Python interpreters.
Nowadays, CPython does call setlocale(LC_CTYPE, NULL); during startup and that was what triggered the deprecation of locale.setdefaultlocale(). However, you are right in that the call only configures the LC_CTYPE part of the locale settings, not the other ones, such as LC_TIME. We should probably change the startup code to call setlocale(LC_ALL, "") instead - as recommended by the C lib docs.
So I guess two changes would be necessary to fix this situation:
or we leave locale.getdefaultlocale() around, but given that it's purpose has been superseded, I don't think that's a good idea. vstinner commented on Dec 23, 2025 setlocale(LC_CTYPE, "") is called by Python during startup: in _Py_SetLocaleFromEnv(LC_CTYPE) which is called by _PyPreConfig_Write().
vstinner commented on Dec 23, 2025 I close the issue. The function is no longer deprecated in Python 3.15.
MetadataMetadataStatusShow more project fields StatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|