diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index 49433e346..9d4636a29 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -35,6 +35,7 @@ _dummy_threading: 2.7-3.8 _heapq: 2.7- _imp: 3.0- _json: 2.7- +_locale: 2.7- _markupbase: 2.7- _msi: 2.7- _operator: 3.4- diff --git a/stdlib/_locale.pyi b/stdlib/_locale.pyi new file mode 100644 index 000000000..2b2fe03e4 --- /dev/null +++ b/stdlib/_locale.pyi @@ -0,0 +1,100 @@ +import sys +from _typeshed import StrPath +from collections.abc import Iterable, Mapping + +LC_CTYPE: int +LC_COLLATE: int +LC_TIME: int +LC_MONETARY: int +LC_NUMERIC: int +LC_ALL: int +CHAR_MAX: int + +def setlocale(category: int, locale: str | Iterable[str | None] | None = None) -> str: ... +def localeconv() -> Mapping[str, int | str | list[int]]: ... + +if sys.version_info >= (3, 11): + def getencoding() -> str: ... + +def strcoll(__os1: str, __os2: str) -> int: ... +def strxfrm(__string: str) -> str: ... + +# native gettext functions +# https://docs.python.org/3/library/locale.html#access-to-message-catalogs +# https://github.com/python/cpython/blob/f4c03484da59049eb62a9bf7777b963e2267d187/Modules/_localemodule.c#L626 +if sys.platform != "win32": + LC_MESSAGES: int + + ABDAY_1: int + ABDAY_2: int + ABDAY_3: int + ABDAY_4: int + ABDAY_5: int + ABDAY_6: int + ABDAY_7: int + + ABMON_1: int + ABMON_2: int + ABMON_3: int + ABMON_4: int + ABMON_5: int + ABMON_6: int + ABMON_7: int + ABMON_8: int + ABMON_9: int + ABMON_10: int + ABMON_11: int + ABMON_12: int + + DAY_1: int + DAY_2: int + DAY_3: int + DAY_4: int + DAY_5: int + DAY_6: int + DAY_7: int + + ERA: int + ERA_D_T_FMT: int + ERA_D_FMT: int + ERA_T_FMT: int + + MON_1: int + MON_2: int + MON_3: int + MON_4: int + MON_5: int + MON_6: int + MON_7: int + MON_8: int + MON_9: int + MON_10: int + MON_11: int + MON_12: int + + CODESET: int + D_T_FMT: int + D_FMT: int + T_FMT: int + T_FMT_AMPM: int + AM_STR: int + PM_STR: int + + RADIXCHAR: int + THOUSEP: int + YESEXPR: int + NOEXPR: int + CRNCYSTR: int + ALT_DIGITS: int + + def nl_langinfo(__key: int) -> str: ... + + # This is dependent on `libintl.h` which is a part of `gettext` + # system dependency. These functions might be missing. + # But, we always say that they are present. + def gettext(__msg: str) -> str: ... + def dgettext(__domain: str | None, __msg: str) -> str: ... + def dcgettext(__domain: str | None, __msg: str, __category: int) -> str: ... + def textdomain(__domain: str | None) -> str: ... + def bindtextdomain(__domain: str, __dir: StrPath | None) -> str: ... + def bind_textdomain_codeset(__domain: str, __codeset: str | None) -> str | None: ... diff --git a/stdlib/locale.pyi b/stdlib/locale.pyi index 3753700ea..7dcb0cfa7 100644 --- a/stdlib/locale.pyi +++ b/stdlib/locale.pyi @@ -1,6 +1,5 @@ import sys -from _typeshed import StrPath -from collections.abc import Callable, Iterable, Mapping +from collections.abc import Callable __all__ = [ "getlocale", @@ -20,7 +19,6 @@ __all__ = [ "normalize", "LC_CTYPE", "LC_COLLATE", - "LC_MESSAGES", "LC_TIME", "LC_MONETARY", "LC_NUMERIC", @@ -34,88 +32,102 @@ if sys.version_info >= (3, 11): if sys.version_info < (3, 12): __all__ += ["format"] +if sys.platform != "win32": + __all__ += ["LC_MESSAGES"] + +from _locale import ( + CHAR_MAX as CHAR_MAX, + LC_ALL as LC_ALL, + LC_COLLATE as LC_COLLATE, + LC_CTYPE as LC_CTYPE, + LC_MONETARY as LC_MONETARY, + LC_NUMERIC as LC_NUMERIC, + LC_TIME as LC_TIME, + localeconv as localeconv, + setlocale as setlocale, + strcoll as strcoll, + strxfrm as strxfrm, +) + +if sys.version_info >= (3, 11): + from _locale import getencoding as getencoding + +# Some parts of the `_locale` module are platform-specific: +if sys.platform != "win32": + from _locale import ( + ABDAY_1 as ABDAY_1, + ABDAY_2 as ABDAY_2, + ABDAY_3 as ABDAY_3, + ABDAY_4 as ABDAY_4, + ABDAY_5 as ABDAY_5, + ABDAY_6 as ABDAY_6, + ABDAY_7 as ABDAY_7, + ABMON_1 as ABMON_1, + ABMON_2 as ABMON_2, + ABMON_3 as ABMON_3, + ABMON_4 as ABMON_4, + ABMON_5 as ABMON_5, + ABMON_6 as ABMON_6, + ABMON_7 as ABMON_7, + ABMON_8 as ABMON_8, + ABMON_9 as ABMON_9, + ABMON_10 as ABMON_10, + ABMON_11 as ABMON_11, + ABMON_12 as ABMON_12, + ALT_DIGITS as ALT_DIGITS, + AM_STR as AM_STR, + CODESET as CODESET, + CRNCYSTR as CRNCYSTR, + D_FMT as D_FMT, + D_T_FMT as D_T_FMT, + DAY_1 as DAY_1, + DAY_2 as DAY_2, + DAY_3 as DAY_3, + DAY_4 as DAY_4, + DAY_5 as DAY_5, + DAY_6 as DAY_6, + DAY_7 as DAY_7, + ERA as ERA, + ERA_D_FMT as ERA_D_FMT, + ERA_D_T_FMT as ERA_D_T_FMT, + ERA_T_FMT as ERA_T_FMT, + LC_MESSAGES as LC_MESSAGES, + MON_1 as MON_1, + MON_2 as MON_2, + MON_3 as MON_3, + MON_4 as MON_4, + MON_5 as MON_5, + MON_6 as MON_6, + MON_7 as MON_7, + MON_8 as MON_8, + MON_9 as MON_9, + MON_10 as MON_10, + MON_11 as MON_11, + MON_12 as MON_12, + NOEXPR as NOEXPR, + PM_STR as PM_STR, + RADIXCHAR as RADIXCHAR, + T_FMT as T_FMT, + T_FMT_AMPM as T_FMT_AMPM, + THOUSEP as THOUSEP, + YESEXPR as YESEXPR, + bind_textdomain_codeset as bind_textdomain_codeset, + bindtextdomain as bindtextdomain, + dcgettext as dcgettext, + dgettext as dgettext, + gettext as gettext, + nl_langinfo as nl_langinfo, + textdomain as textdomain, + ) + # This module defines a function "str()", which is why "str" can't be used # as a type annotation or type alias. from builtins import str as _str from decimal import Decimal from typing import Any -CODESET: int -D_T_FMT: int -D_FMT: int -T_FMT: int -T_FMT_AMPM: int -AM_STR: int -PM_STR: int - -DAY_1: int -DAY_2: int -DAY_3: int -DAY_4: int -DAY_5: int -DAY_6: int -DAY_7: int -ABDAY_1: int -ABDAY_2: int -ABDAY_3: int -ABDAY_4: int -ABDAY_5: int -ABDAY_6: int -ABDAY_7: int - -MON_1: int -MON_2: int -MON_3: int -MON_4: int -MON_5: int -MON_6: int -MON_7: int -MON_8: int -MON_9: int -MON_10: int -MON_11: int -MON_12: int -ABMON_1: int -ABMON_2: int -ABMON_3: int -ABMON_4: int -ABMON_5: int -ABMON_6: int -ABMON_7: int -ABMON_8: int -ABMON_9: int -ABMON_10: int -ABMON_11: int -ABMON_12: int - -RADIXCHAR: int -THOUSEP: int -YESEXPR: int -NOEXPR: int -CRNCYSTR: int - -ERA: int -ERA_D_T_FMT: int -ERA_D_FMT: int -ERA_T_FMT: int - -ALT_DIGITS: int - -LC_CTYPE: int -LC_COLLATE: int -LC_TIME: int -LC_MONETARY: int -LC_MESSAGES: int -LC_NUMERIC: int -LC_ALL: int - -CHAR_MAX: int - class Error(Exception): ... -def setlocale(category: int, locale: _str | Iterable[_str | None] | None = None) -> _str: ... -def localeconv() -> Mapping[_str, int | _str | list[int]]: ... -def nl_langinfo(__key: int) -> _str: ... def getdefaultlocale( envvars: tuple[_str, ...] = ("LC_ALL", "LC_CTYPE", "LANG", "LANGUAGE") ) -> tuple[_str | None, _str | None]: ... @@ -123,8 +135,6 @@ def getlocale(category: int = ...) -> tuple[_str | None, _str | None]: ... def getpreferredencoding(do_setlocale: bool = True) -> _str: ... def normalize(localename: _str) -> _str: ... def resetlocale(category: int = ...) -> None: ... -def strcoll(__os1: _str, __os2: _str) -> int: ... -def strxfrm(__string: _str) -> _str: ... if sys.version_info < (3, 12): def format( @@ -138,20 +148,6 @@ def atof(string: _str, func: Callable[[_str], float] = ...) -> float: ... def atoi(string: _str) -> int: ... def str(val: float) -> _str: ... -# native gettext functions -# https://docs.python.org/3/library/locale.html#access-to-message-catalogs -# https://github.com/python/cpython/blob/f4c03484da59049eb62a9bf7777b963e2267d187/Modules/_localemodule.c#L626 -if sys.platform == "linux" or sys.platform == "darwin": - def gettext(__msg: _str) -> _str: ... - def dgettext(__domain: _str | None, __msg: _str) -> _str: ... - def dcgettext(__domain: _str | None, __msg: _str, __category: int) -> _str: ... - def textdomain(__domain: _str | None) -> _str: ... - def bindtextdomain(__domain: _str, __dir: StrPath | None) -> _str: ... - def bind_textdomain_codeset(__domain: _str, __codeset: _str | None) -> _str | None: ... - -if sys.version_info >= (3, 11): - def getencoding() -> _str: ... - locale_alias: dict[_str, _str] # undocumented locale_encoding_alias: dict[_str, _str] # undocumented windows_locale: dict[int, _str] # undocumented diff --git a/tests/stubtest_allowlists/darwin-py311.txt b/tests/stubtest_allowlists/darwin-py311.txt index d20383941..f31fcfe80 100644 --- a/tests/stubtest_allowlists/darwin-py311.txt +++ b/tests/stubtest_allowlists/darwin-py311.txt @@ -1,7 +1,8 @@ +# These entries looks like a `setup-python` bug: (dbm.gnu)? -(locale.bind_textdomain_codeset)? -(locale.bindtextdomain)? -(locale.dcgettext)? -(locale.dgettext)? -(locale.gettext)? -(locale.textdomain)? +(_?locale.bind_textdomain_codeset)? +(_?locale.bindtextdomain)? +(_?locale.dcgettext)? +(_?locale.dgettext)? +(_?locale.gettext)? +(_?locale.textdomain)? diff --git a/tests/stubtest_allowlists/darwin-py312.txt b/tests/stubtest_allowlists/darwin-py312.txt index d20383941..f31fcfe80 100644 --- a/tests/stubtest_allowlists/darwin-py312.txt +++ b/tests/stubtest_allowlists/darwin-py312.txt @@ -1,7 +1,8 @@ +# These entries looks like a `setup-python` bug: (dbm.gnu)? -(locale.bind_textdomain_codeset)? -(locale.bindtextdomain)? -(locale.dcgettext)? -(locale.dgettext)? -(locale.gettext)? -(locale.textdomain)? +(_?locale.bind_textdomain_codeset)? +(_?locale.bindtextdomain)? +(_?locale.dcgettext)? +(_?locale.dgettext)? +(_?locale.gettext)? +(_?locale.textdomain)? diff --git a/tests/stubtest_allowlists/win32.txt b/tests/stubtest_allowlists/win32.txt index ef4755017..8577e1613 100644 --- a/tests/stubtest_allowlists/win32.txt +++ b/tests/stubtest_allowlists/win32.txt @@ -1,6 +1,4 @@ ctypes.GetLastError # Is actually a pointer -locale.[A-Z0-9_]+ # Constants that should be moved to _locale and re-exported conditionally -locale.nl_langinfo # Function that should be moved to _locale and re-exported conditionally # alias for a class defined elsewhere, # mypy infers the variable has type `(*args) -> DupHandle` but stubtest infers the runtime type as multiprocessing.reduction.AbstractReducer.DupHandle