Skip to content

Commit e96a84f

Browse files
authored
Adopt multi-phase initialisation (PEP 489) (#495)
2 parents dec39fe + 643a70a commit e96a84f

File tree

3 files changed

+45
-20
lines changed

3 files changed

+45
-20
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Unreleased
55

66
- ``__version__`` raises ``DeprecationWarning`` instead of ``UserWarning``.
77
:issue:`487`
8+
- Adopt multi-phase initialisation (:pep:`489`) for the C extension.
9+
:issue:`494`
810

911

1012
Version 3.0.2

src/markupsafe/_speedups.c

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -175,30 +175,26 @@ static PyMethodDef module_methods[] = {
175175
{NULL, NULL, 0, NULL} /* Sentinel */
176176
};
177177

178+
static PyModuleDef_Slot module_slots[] = {
179+
#ifdef Py_mod_multiple_interpreters // Python 3.12+
180+
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
181+
#endif
182+
#ifdef Py_mod_gil // Python 3.13+
183+
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
184+
#endif
185+
{0, NULL} /* Sentinel */
186+
};
187+
178188
static struct PyModuleDef module_definition = {
179-
PyModuleDef_HEAD_INIT,
180-
"markupsafe._speedups",
181-
NULL,
182-
-1,
183-
module_methods,
184-
NULL,
185-
NULL,
186-
NULL,
187-
NULL
189+
.m_base = PyModuleDef_HEAD_INIT,
190+
.m_name = "markupsafe._speedups",
191+
.m_size = 0,
192+
.m_methods = module_methods,
193+
.m_slots = module_slots,
188194
};
189195

190196
PyMODINIT_FUNC
191197
PyInit__speedups(void)
192198
{
193-
PyObject *m = PyModule_Create(&module_definition);
194-
195-
if (m == NULL) {
196-
return NULL;
197-
}
198-
199-
#ifdef Py_GIL_DISABLED
200-
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
201-
#endif
202-
203-
return m;
199+
return PyModuleDef_Init(&module_definition);
204200
}

tests/test_ext_init.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import sys
2+
3+
import pytest
4+
5+
import markupsafe
6+
7+
try:
8+
from markupsafe import _speedups
9+
except ImportError:
10+
_speedups = None # type: ignore[assignment]
11+
12+
13+
@pytest.mark.skipif(_speedups is None, reason="speedups unavailable")
14+
def test_ext_init() -> None:
15+
"""Test that the extension module uses multi-phase init by checking that
16+
uncached imports result in different module objects.
17+
"""
18+
if markupsafe._escape_inner is not _speedups._escape_inner: # type: ignore[attr-defined]
19+
pytest.skip("speedups not active")
20+
21+
for k in [k for k in sys.modules if k.startswith("markupsafe")]:
22+
del sys.modules[k]
23+
24+
import markupsafe._speedups as new
25+
26+
assert _speedups.__dict__ != new.__dict__
27+
assert _speedups._escape_inner is not new._escape_inner

0 commit comments

Comments
 (0)