Skip to content

Commit a158168

Browse files
shihai1991encukou
andauthored
bpo-1635741: Port _locale extension module to multiphase initialization (PEP 489) (GH-18358)
Co-authored-by: Petr Viktorin <[email protected]>
1 parent 704e206 commit a158168

File tree

2 files changed

+84
-34
lines changed

2 files changed

+84
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Port _locale extension module to multiphase initialization (:pep:`489`).

Modules/_localemodule.c

+83-34
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,17 @@ This software comes with no warranty. Use at your own risk.
4141

4242
PyDoc_STRVAR(locale__doc__, "Support for POSIX locales.");
4343

44-
static PyObject *Error;
44+
typedef struct _locale_state {
45+
PyObject *Error;
46+
} _locale_state;
47+
48+
static inline _locale_state*
49+
get_locale_state(PyObject *m)
50+
{
51+
void *state = PyModule_GetState(m);
52+
assert(state != NULL);
53+
return (_locale_state *)state;
54+
}
4555

4656
/* support functions for formatting floating point numbers */
4757

@@ -94,7 +104,8 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
94104
#if defined(MS_WINDOWS)
95105
if (category < LC_MIN || category > LC_MAX)
96106
{
97-
PyErr_SetString(Error, "invalid locale category");
107+
PyErr_SetString(get_locale_state(self)->Error,
108+
"invalid locale category");
98109
return NULL;
99110
}
100111
#endif
@@ -104,7 +115,8 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
104115
result = setlocale(category, locale);
105116
if (!result) {
106117
/* operation failed, no setting was changed */
107-
PyErr_SetString(Error, "unsupported locale setting");
118+
PyErr_SetString(get_locale_state(self)->Error,
119+
"unsupported locale setting");
108120
return NULL;
109121
}
110122
result_object = PyUnicode_DecodeLocale(result, NULL);
@@ -114,7 +126,8 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
114126
/* get locale */
115127
result = setlocale(category, NULL);
116128
if (!result) {
117-
PyErr_SetString(Error, "locale query failed");
129+
PyErr_SetString(get_locale_state(self)->Error,
130+
"locale query failed");
118131
return NULL;
119132
}
120133
result_object = PyUnicode_DecodeLocale(result, NULL);
@@ -622,14 +635,16 @@ PyDoc_STRVAR(bindtextdomain__doc__,
622635
"Bind the C library's domain to dir.");
623636

624637
static PyObject*
625-
PyIntl_bindtextdomain(PyObject* self,PyObject*args)
638+
PyIntl_bindtextdomain(PyObject* self, PyObject*args)
626639
{
627640
char *domain, *dirname, *current_dirname;
628641
PyObject *dirname_obj, *dirname_bytes = NULL, *result;
642+
629643
if (!PyArg_ParseTuple(args, "sO", &domain, &dirname_obj))
630644
return 0;
631645
if (!strlen(domain)) {
632-
PyErr_SetString(Error, "domain must be a non-empty string");
646+
PyErr_SetString(get_locale_state(self)->Error,
647+
"domain must be a non-empty string");
633648
return 0;
634649
}
635650
if (dirname_obj != Py_None) {
@@ -710,31 +725,13 @@ static struct PyMethodDef PyLocale_Methods[] = {
710725
{NULL, NULL}
711726
};
712727

713-
714-
static struct PyModuleDef _localemodule = {
715-
PyModuleDef_HEAD_INIT,
716-
"_locale",
717-
locale__doc__,
718-
-1,
719-
PyLocale_Methods,
720-
NULL,
721-
NULL,
722-
NULL,
723-
NULL
724-
};
725-
726-
PyMODINIT_FUNC
727-
PyInit__locale(void)
728+
static int
729+
_locale_exec(PyObject *m)
728730
{
729-
PyObject *m;
730731
#ifdef HAVE_LANGINFO_H
731732
int i;
732733
#endif
733734

734-
m = PyModule_Create(&_localemodule);
735-
if (m == NULL)
736-
return NULL;
737-
738735
PyModule_AddIntMacro(m, LC_CTYPE);
739736
PyModule_AddIntMacro(m, LC_TIME);
740737
PyModule_AddIntMacro(m, LC_COLLATE);
@@ -748,12 +745,16 @@ PyInit__locale(void)
748745
PyModule_AddIntMacro(m, LC_ALL);
749746
PyModule_AddIntMacro(m, CHAR_MAX);
750747

751-
Error = PyErr_NewException("locale.Error", NULL, NULL);
752-
if (Error == NULL) {
753-
Py_DECREF(m);
754-
return NULL;
748+
_locale_state *state = get_locale_state(m);
749+
state->Error = PyErr_NewException("locale.Error", NULL, NULL);
750+
if (state->Error == NULL) {
751+
return -1;
752+
}
753+
Py_INCREF(get_locale_state(m)->Error);
754+
if (PyModule_AddObject(m, "Error", get_locale_state(m)->Error) < 0) {
755+
Py_DECREF(get_locale_state(m)->Error);
756+
return -1;
755757
}
756-
PyModule_AddObject(m, "Error", Error);
757758

758759
#ifdef HAVE_LANGINFO_H
759760
for (i = 0; langinfo_constants[i].name; i++) {
@@ -763,10 +764,58 @@ PyInit__locale(void)
763764
#endif
764765

765766
if (PyErr_Occurred()) {
766-
Py_DECREF(m);
767-
return NULL;
767+
return -1;
768768
}
769-
return m;
769+
return 0;
770+
}
771+
772+
static struct PyModuleDef_Slot _locale_slots[] = {
773+
{Py_mod_exec, _locale_exec},
774+
{0, NULL}
775+
};
776+
777+
static int
778+
locale_traverse(PyObject *m, visitproc visit, void *arg)
779+
{
780+
_locale_state *state = (_locale_state*)PyModule_GetState(m);
781+
if (state) {
782+
Py_VISIT(state->Error);
783+
}
784+
return 0;
785+
}
786+
787+
static int
788+
locale_clear(PyObject *m)
789+
{
790+
_locale_state *state = (_locale_state*)PyModule_GetState(m);
791+
if (state) {
792+
Py_CLEAR(state->Error);
793+
}
794+
return 0;
795+
}
796+
797+
static void
798+
locale_free(PyObject *m)
799+
{
800+
locale_clear(m);
801+
}
802+
803+
static struct PyModuleDef _localemodule = {
804+
PyModuleDef_HEAD_INIT,
805+
"_locale",
806+
locale__doc__,
807+
sizeof(_locale_state),
808+
PyLocale_Methods,
809+
_locale_slots,
810+
locale_traverse,
811+
locale_clear,
812+
(freefunc)locale_free,
813+
};
814+
815+
PyMODINIT_FUNC
816+
PyInit__locale(void)
817+
{
818+
return PyModuleDef_Init(&_localemodule);
770819
}
771820

772821
/*

0 commit comments

Comments
 (0)