From 8fc16bb9aee5f60387d9f5b5fddf2f2873eb5bc7 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Sat, 17 May 2025 09:21:44 +0100 Subject: [PATCH] Add --- Doc/deprecations/pending-removal-in-3.15.rst | 2 +- Doc/library/locale.rst | 25 ------- Doc/using/cmdline.rst | 3 +- Doc/whatsnew/3.11.rst | 4 +- Doc/whatsnew/3.15.rst | 8 ++ Lib/locale.py | 74 ++----------------- Lib/test/test_locale.py | 24 ------ ...5-05-17-09-09-00.gh-issue-134086.asfhs.rst | 1 + Modules/_localemodule.c | 47 ------------ Modules/clinic/_localemodule.c.h | 27 +------ 10 files changed, 19 insertions(+), 196 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-05-17-09-09-00.gh-issue-134086.asfhs.rst diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index 707253a91ecd40..8cc7d25fd821d3 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -35,7 +35,7 @@ Pending removal in Python 3.15 * :class:`locale`: - * The :func:`~locale.getdefaultlocale` function + * The :func:`!~locale.getdefaultlocale` function has been deprecated since Python 3.11. Its removal was originally planned for Python 3.13 (:gh:`90817`), but has been postponed to Python 3.15. diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 426e3a06e1ef11..8351689e25dff1 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -327,31 +327,6 @@ The :mod:`locale` module defines the following exception and functions: The function now temporarily sets the ``LC_CTYPE`` locale in some cases. -.. function:: getdefaultlocale([envvars]) - - Tries to determine the default locale settings and returns them as a tuple of - the form ``(language code, encoding)``. - - According to POSIX, a program which has not called ``setlocale(LC_ALL, '')`` - runs using the portable ``'C'`` locale. Calling ``setlocale(LC_ALL, '')`` lets - it use the default locale as defined by the :envvar:`LANG` variable. Since we - do not want to interfere with the current locale setting we thus emulate the - behavior in the way described above. - - To maintain compatibility with other platforms, not only the :envvar:`LANG` - variable is tested, but a list of variables given as envvars parameter. The - first found to be defined will be used. *envvars* defaults to the search - path used in GNU gettext; it must always contain the variable name - ``'LANG'``. The GNU gettext search path contains ``'LC_ALL'``, - ``'LC_CTYPE'``, ``'LANG'`` and ``'LANGUAGE'``, in that order. - - Except for the code ``'C'``, the language code corresponds to :rfc:`1766`. - *language code* and *encoding* may be ``None`` if their values cannot be - determined. - - .. deprecated-removed:: 3.11 3.15 - - .. function:: getlocale(category=LC_CTYPE) Returns the current setting for the given locale category as sequence containing diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 40a46a62031ef7..b5b1aa79530fb2 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -1113,8 +1113,7 @@ conflict. components running in the same process (such as the GNU ``readline`` library), the updated setting is also seen in subprocesses (regardless of whether or not those processes are running a Python interpreter), as well as - in operations that query the environment rather than the current C locale - (such as Python's own :func:`locale.getdefaultlocale`). + in operations that query the environment rather than the current C locale. Configuring one of these locales (either explicitly or via the above implicit locale coercion) automatically enables the ``surrogateescape`` diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 2dd205dd2b8831..a3467e5285cd08 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1811,7 +1811,7 @@ Standard Library * :func:`!importlib.resources.read_text` * :func:`!importlib.resources.path` -* The :func:`locale.getdefaultlocale` function is deprecated and will be +* The :func:`!locale.getdefaultlocale` function is deprecated and will be removed in Python 3.15. Use :func:`locale.setlocale`, :func:`locale.getpreferredencoding(False) ` and :func:`locale.getlocale` functions instead. @@ -2080,7 +2080,7 @@ Porting notes for the C API are * :mod:`calendar`: The :class:`calendar.LocaleTextCalendar` and :class:`calendar.LocaleHTMLCalendar` classes now use - :func:`locale.getlocale`, instead of using :func:`locale.getdefaultlocale`, + :func:`locale.getlocale`, instead of using :func:`!locale.getdefaultlocale`, if no locale is specified. (Contributed by Victor Stinner in :issue:`46659`.) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 9e9a168db0e725..aec5c546c78127 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -121,6 +121,14 @@ Deprecated Removed ======= + +locale +------ +* Remove the :func:`!locale.getdefaultlocale` function, + which was deprecated since Python 3.13. + (Contributed by Stan Ulbrych in :gh:`XXXXXX`.) + + platform -------- diff --git a/Lib/locale.py b/Lib/locale.py index 2feb10e59c96a3..5cc88d650cf8a1 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -23,7 +23,7 @@ # Yuck: LC_MESSAGES is non-standard: can't tell whether it exists before # trying the import. So __all__ is also fiddled at the end of the file. -__all__ = ["getlocale", "getdefaultlocale", "getpreferredencoding", "Error", +__all__ = ["getlocale", "getpreferredencoding", "Error", "setlocale", "localeconv", "strcoll", "strxfrm", "str", "atof", "atoi", "format_string", "currency", "normalize", "LC_CTYPE", "LC_COLLATE", "LC_TIME", "LC_MONETARY", @@ -521,69 +521,6 @@ def _build_localename(localetuple): raise TypeError('Locale must be None, a string, or an iterable of ' 'two strings -- language code, encoding.') from None -def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): - - """ Tries to determine the default locale settings and returns - them as tuple (language code, encoding). - - According to POSIX, a program which has not called - setlocale(LC_ALL, "") runs using the portable 'C' locale. - Calling setlocale(LC_ALL, "") lets it use the default locale as - defined by the LANG variable. Since we don't want to interfere - with the current locale setting we thus emulate the behavior - in the way described above. - - To maintain compatibility with other platforms, not only the - LANG variable is tested, but a list of variables given as - envvars parameter. The first found to be defined will be - used. envvars defaults to the search path used in GNU gettext; - it must always contain the variable name 'LANG'. - - Except for the code 'C', the language code corresponds to RFC - 1766. code and encoding can be None in case the values cannot - be determined. - - """ - - import warnings - warnings._deprecated( - "locale.getdefaultlocale", - "{name!r} is deprecated and slated for removal in Python {remove}. " - "Use setlocale(), getencoding() and getlocale() instead.", - remove=(3, 15)) - return _getdefaultlocale(envvars) - - -def _getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): - try: - # check if it's supported by the _locale module - import _locale - code, encoding = _locale._getdefaultlocale() - except (ImportError, AttributeError): - pass - else: - # make sure the code/encoding values are valid - if sys.platform == "win32" and code and code[:2] == "0x": - # map windows language identifier to language name - code = windows_locale.get(int(code, 0)) - # ...add other platform-specific processing here, if - # necessary... - return code, encoding - - # fall back on POSIX behaviour - import os - lookup = os.environ.get - for variable in envvars: - localename = lookup(variable,None) - if localename: - if variable == 'LANGUAGE': - localename = localename.split(':')[0] - break - else: - localename = 'C' - return _parse_localename(localename) - - def getlocale(category=LC_CTYPE): """ Returns the current setting for the given locale category as @@ -1728,12 +1665,11 @@ def _init_categories(categories=categories): _init_categories() del categories['LC_ALL'] - print('Locale defaults as determined by getdefaultlocale():') + print('Locale defaults as determined by locale.getlocale() and locale.getpreferredencoding():') print('-'*72) - lang, enc = getdefaultlocale() - print('Language: ', lang or '(undefined)') - print('Encoding: ', enc or '(undefined)') - print() + lang, enc = getlocale() + print(f'Language: {lang or "(undefined)"}') + print(f'Encoding: {enc or getpreferredencoding(False) or "(undefined)"}\n') print('Locale settings on startup:') print('-'*72) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index 455d2af37efdc8..e40de15ca9cda3 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -483,30 +483,6 @@ def test_japanese(self): class TestMiscellaneous(unittest.TestCase): - def test_defaults_UTF8(self): - # Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is - # valid. Furthermore LC_CTYPE=UTF is used by the UTF-8 locale coercing - # during interpreter startup (on macOS). - import _locale - - self.assertEqual(locale._parse_localename('UTF-8'), (None, 'UTF-8')) - - if hasattr(_locale, '_getdefaultlocale'): - orig_getlocale = _locale._getdefaultlocale - del _locale._getdefaultlocale - else: - orig_getlocale = None - - try: - with os_helper.EnvironmentVarGuard() as env: - env.unset('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE') - env.set('LC_CTYPE', 'UTF-8') - - with check_warnings(('', DeprecationWarning)): - self.assertEqual(locale.getdefaultlocale(), (None, 'UTF-8')) - finally: - if orig_getlocale is not None: - _locale._getdefaultlocale = orig_getlocale def test_getencoding(self): # Invoke getencoding to make sure it does not cause exceptions. diff --git a/Misc/NEWS.d/next/Library/2025-05-17-09-09-00.gh-issue-134086.asfhs.rst b/Misc/NEWS.d/next/Library/2025-05-17-09-09-00.gh-issue-134086.asfhs.rst new file mode 100644 index 00000000000000..55d93d47ce0bb9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-17-09-09-00.gh-issue-134086.asfhs.rst @@ -0,0 +1 @@ +Remove deprecated :func:`!locale.getdefaultlocale`. diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index ad618398d5b824..70e24f7f245402 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -444,50 +444,6 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str) } #endif -#if defined(MS_WINDOWS) - -/*[clinic input] -_locale._getdefaultlocale - -[clinic start generated code]*/ - -static PyObject * -_locale__getdefaultlocale_impl(PyObject *module) -/*[clinic end generated code: output=e6254088579534c2 input=003ea41acd17f7c7]*/ -{ - char encoding[20]; - char locale[100]; - - PyOS_snprintf(encoding, sizeof(encoding), "cp%u", GetACP()); - - if (GetLocaleInfoA(LOCALE_USER_DEFAULT, - LOCALE_SISO639LANGNAME, - locale, sizeof(locale))) { - Py_ssize_t i = strlen(locale); - locale[i++] = '_'; - if (GetLocaleInfoA(LOCALE_USER_DEFAULT, - LOCALE_SISO3166CTRYNAME, - locale+i, (int)(sizeof(locale)-i))) - return Py_BuildValue("ss", locale, encoding); - } - - /* If we end up here, this windows version didn't know about - ISO639/ISO3166 names (it's probably Windows 95). Return the - Windows language identifier instead (a hexadecimal number) */ - - locale[0] = '0'; - locale[1] = 'x'; - if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, - locale+2, sizeof(locale)-2)) { - return Py_BuildValue("ss", locale, encoding); - } - - /* cannot determine the language code (very unlikely) */ - Py_INCREF(Py_None); - return Py_BuildValue("Os", Py_None, encoding); -} -#endif - #ifdef HAVE_LANGINFO_H #define LANGINFO(X, Y) {#X, X, Y} static struct langinfo_constant{ @@ -899,9 +855,6 @@ static struct PyMethodDef PyLocale_Methods[] = { #ifdef HAVE_WCSXFRM _LOCALE_STRXFRM_METHODDEF #endif -#if defined(MS_WINDOWS) - _LOCALE__GETDEFAULTLOCALE_METHODDEF -#endif #ifdef HAVE_LANGINFO_H _LOCALE_NL_LANGINFO_METHODDEF #endif diff --git a/Modules/clinic/_localemodule.c.h b/Modules/clinic/_localemodule.c.h index 5e0880b0d0bb4c..52ea5e35e2c1bb 100644 --- a/Modules/clinic/_localemodule.c.h +++ b/Modules/clinic/_localemodule.c.h @@ -151,27 +151,6 @@ _locale_strxfrm(PyObject *module, PyObject *arg) #endif /* defined(HAVE_WCSXFRM) */ -#if defined(MS_WINDOWS) - -PyDoc_STRVAR(_locale__getdefaultlocale__doc__, -"_getdefaultlocale($module, /)\n" -"--\n" -"\n"); - -#define _LOCALE__GETDEFAULTLOCALE_METHODDEF \ - {"_getdefaultlocale", (PyCFunction)_locale__getdefaultlocale, METH_NOARGS, _locale__getdefaultlocale__doc__}, - -static PyObject * -_locale__getdefaultlocale_impl(PyObject *module); - -static PyObject * -_locale__getdefaultlocale(PyObject *module, PyObject *Py_UNUSED(ignored)) -{ - return _locale__getdefaultlocale_impl(module); -} - -#endif /* defined(MS_WINDOWS) */ - #if defined(HAVE_LANGINFO_H) PyDoc_STRVAR(_locale_nl_langinfo__doc__, @@ -564,10 +543,6 @@ _locale_getencoding(PyObject *module, PyObject *Py_UNUSED(ignored)) #define _LOCALE_STRXFRM_METHODDEF #endif /* !defined(_LOCALE_STRXFRM_METHODDEF) */ -#ifndef _LOCALE__GETDEFAULTLOCALE_METHODDEF - #define _LOCALE__GETDEFAULTLOCALE_METHODDEF -#endif /* !defined(_LOCALE__GETDEFAULTLOCALE_METHODDEF) */ - #ifndef _LOCALE_NL_LANGINFO_METHODDEF #define _LOCALE_NL_LANGINFO_METHODDEF #endif /* !defined(_LOCALE_NL_LANGINFO_METHODDEF) */ @@ -595,4 +570,4 @@ _locale_getencoding(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _LOCALE_BIND_TEXTDOMAIN_CODESET_METHODDEF #define _LOCALE_BIND_TEXTDOMAIN_CODESET_METHODDEF #endif /* !defined(_LOCALE_BIND_TEXTDOMAIN_CODESET_METHODDEF) */ -/*[clinic end generated code: output=034a3c219466d207 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d33720466578590f input=a9049054013a1b77]*/