8000 bpo-41842: Add codecs.unregister() function (GH-22360) · python/cpython@d332e7b · GitHub
[go: up one dir, main page]

Skip to content

Commit d332e7b

Browse files
authored
bpo-41842: Add codecs.unregister() function (GH-22360)
Add codecs.unregister() and PyCodec_Unregister() functions to unregister a codec search function.
1 parent 24ba3b0 commit d332e7b

File tree

11 files changed

+108
-5
lines changed

11 files changed

+108
-5
lines changed

Doc/c-api/codec.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Codec registry and support functions
1010
As side effect, this tries to load the :mod:`encodings` package, if not yet
1111
done, to make sure that it is always first in the list of search functions.
1212
13+
.. c:function:: int PyCodec_Unregister(PyObject *search_function)
14+
15+
Unregister a codec search function and clear the registry's cache.
16+
If the search function is not registered, do nothing.
17+
Return 0 on success. Raise an exception and return -1 on error.
18+
19+
.. versionadded:: 3.10
20+
1321
.. c:function:: int PyCodec_KnownEncoding(const char *encoding)
1422
1523
Return ``1`` or ``0`` depending on whether there is a registered codec for

Doc/library/codecs.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
163163
:class:`CodecInfo` object. In case a search function cannot find
164164
a given encoding, it should return ``None``.
165165

166-
.. note::
167166

168-
Search function registration is not currently reversible,
169-
which may cause problems in some cases, such as unit testing or
170-
module reloading.
167+
.. function:: unregister(search_function)
168+
169+
Unregister a codec search function and clear the registry's cache.
170+
If the search function is not registered, do nothing.
171+
172+
.. versionadded:: 3.10
173+
171174

172175
While the builtin :func:`open` and the associated :mod:`io` module are the
173176
recommended approach for working with encoded text files, this module

Doc/whatsnew/3.10.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ base64
109109
Add :func:`base64.b32hexencode` and :func:`base64.b32hexdecode` to support the
110110
Base32 Encoding with Extended Hex Alphabet.
111111

112+
codecs
113+
------
114+
115+
Add a :func:`codecs.unregister` function to unregister a codec search function.
116+
(Contributed by Hai Shi in :issue:`41842`.)
117+
112118
curses
113119
------
114120

@@ -237,6 +243,10 @@ New Features
237243
:class:`datetime.time` objects.
238244
(Contributed by Zackery Spytz in :issue:`30155`.)
239245

246+
* Add a :c:func:`PyCodec_Unregister` function to unregister a codec
247+
search function.
248+
(Contributed by Hai Shi in :issue:`41842`.)
249+
240250
Porting to Python 3.10
241251
----------------------
242252

Include/codecs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ PyAPI_FUNC(int) PyCodec_Register(
2727
PyObject *search_function
2828
);
2929

30+
/* Unregister a codec search function and clear the registry's cache.
31+
If the search function is not registered, do nothing.
32+
Return 0 on success. Raise an exception and return -1 on error. */
33+
34+
PyAPI_FUNC(int) PyCodec_Unregister(
35+
PyObject *search_function
36+
);
37+
3038
/* Codec registry lookup API.
3139
3240
Looks up the given encoding and returns a CodecInfo object with

Lib/test/test_codecs.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,18 @@ def test_register(self):
16411641
self.assertRaises(TypeError, codecs.register)
16421642
self.assertRaises(TypeError, codecs.register, 42)
16431643

1644+
def test_unregister(self):
1645+
name = "nonexistent_codec_name"
1646+
search_function = mock.Mock()
1647+
codecs.register(search_function)
1648+
self.assertRaises(TypeError, codecs.lookup, name)
1649+
search_function.assert_called_with(name)
1650+
search_function.reset_mock()
1651+
1652+
codecs.unregister(search_function)
1653+
self.assertRaises(LookupError, codecs.lookup, name)
1654+
search_function.assert_not_called()
1655+
16441656
def test_lookup(self):
16451657
self.assertRaises(TypeError, codecs.lookup)
16461658
self.assertRaises(LookupError, codecs.lookup, "__spam__")

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,7 @@ Akash Shende
15751575
Charlie Shepherd
15761576
Bruce Sherwood
15771577
Gregory Shevchenko
1578+
Hai Shi
15781579
Alexander Shigin
15791580
Pete Shinners
15801581
Michael Shiplett
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :c:func:`PyCodec_Unregister` function to unregister a codec search
2+
function.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :func:`codecs.unregister` function to unregister a codec search function.

Modules/_codecsmodule.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ _codecs_register(PyObject *module, PyObject *search_function)
6868
Py_RETURN_NONE;
6969
}
7070

71+
/*[clinic input]
72+
_codecs.unregister
73+
search_function: object
74+
/
75+
76+
Unregister a codec search function and clear the registry's cache.
77+
78+
If the search function is not registered, do nothing.
79+
[clinic start generated code]*/
80+
81+
static PyObject *
82+
_codecs_unregister(PyObject *module, PyObject *search_function)
83+
/*[clinic end generated code: output=1f0edee9cf246399 input=dd7c004c652d345e]*/
84+
{
85+
if (PyCodec_Unregister(search_function) < 0) {
86+
return NULL;
87+
}
88+
89+
Py_RETURN_NONE;
90+
}
91+
7192
/*[clinic input]
7293
_codecs.lookup
7394
encoding: str
@@ -992,6 +1013,7 @@ _codecs_lookup_error_impl(PyObject *module, const char *name)
9921013

9931014
static PyMethodDef _codecs_functions[] = {
9941015
_CODECS_REGISTER_METHODDEF
1016+
_CODECS_UNREGISTER_METHODDEF
9951017
_CODECS_LOOKUP_METHODDEF
9961018
_CODECS_ENCODE_METHODDEF
9971019
_CODECS_DECODE_METHODDEF

Modules/clinic/_codecsmodule.c.h

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/codecs.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,31 @@ int PyCodec_Register(PyObject *search_function)
5050
return -1;
5151
}
5252

53+
int
54+
PyCodec_Unregister(PyObject *search_function)
55+
{
56+
PyInterpreterState *interp = PyInterpreterState_Get();
57+
PyObject *codec_search_path = interp->codec_search_path;
58+
/* Do nothing if codec_search_path is not created yet or was cleared. */
59+
if (codec_search_path == NULL) {
60+
return 0;
61+
}
62+
63+
assert(PyList_CheckExact(codec_search_path));
64+
Py_ssize_t n = PyList_GET_SIZE(codec_search_path);
65+
for (Py_ssize_t i = 0; i < n; i++) {
66+
PyObject *item = PyList_GET_ITEM(codec_search_path, i);
67+
if (item == search_function) {
68+
if (interp->codec_search_cache != NULL) {
69+
assert(PyDict_CheckExact(interp->codec_search_cache));
70+
PyDict_Clear(interp->codec_search_cache);
71+
}
72+
return PyList_SetSlice(codec_search_path, i, i+1, NULL);
73+
}
74+
}
75+
return 0;
76+
}
77+
5378
extern int _Py_normalize_encoding(const char *, char *, size_t);
5479

5580
/* Convert a string to a normalized Python string(decoded from UTF-8): all characters are

0 commit comments

Comments
 (0)
0