bpo-41842: Add codecs.unregister() function (GH-22360)

Add codecs.unregister() and PyCodec_Unregister() functions
to unregister a codec search function.
This commit is contained in:
Hai Shi 2020-09-29 05:41:11 +08:00 committed by GitHub
parent 24ba3b0df5
commit d332e7b816
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 108 additions and 5 deletions

View file

@ -10,6 +10,14 @@ Codec registry and support functions
As side effect, this tries to load the :mod:`encodings` package, if not yet
done, to make sure that it is always first in the list of search functions.
.. c:function:: int PyCodec_Unregister(PyObject *search_function)
Unregister a codec search function and clear the registry's cache.
If the search function is not registered, do nothing.
Return 0 on success. Raise an exception and return -1 on error.
.. versionadded:: 3.10
.. c:function:: int PyCodec_KnownEncoding(const char *encoding)
Return ``1`` or ``0`` depending on whether there is a registered codec for

View file

@ -163,11 +163,14 @@ function:
:class:`CodecInfo` object. In case a search function cannot find
a given encoding, it should return ``None``.
.. note::
Search function registration is not currently reversible,
which may cause problems in some cases, such as unit testing or
module reloading.
.. function:: unregister(search_function)
Unregister a codec search function and clear the registry's cache.
If the search function is not registered, do nothing.
.. versionadded:: 3.10
While the builtin :func:`open` and the associated :mod:`io` module are the
recommended approach for working with encoded text files, this module

View file

@ -109,6 +109,12 @@ base64
Add :func:`base64.b32hexencode` and :func:`base64.b32hexdecode` to support the
Base32 Encoding with Extended Hex Alphabet.
codecs
------
Add a :func:`codecs.unregister` function to unregister a codec search function.
(Contributed by Hai Shi in :issue:`41842`.)
curses
------
@ -237,6 +243,10 @@ New Features
:class:`datetime.time` objects.
(Contributed by Zackery Spytz in :issue:`30155`.)
* Add a :c:func:`PyCodec_Unregister` function to unregister a codec
search function.
(Contributed by Hai Shi in :issue:`41842`.)
Porting to Python 3.10
----------------------

View file

@ -27,6 +27,14 @@ PyAPI_FUNC(int) PyCodec_Register(
PyObject *search_function
);
/* Unregister a codec search function and clear the registry's cache.
If the search function is not registered, do nothing.
Return 0 on success. Raise an exception and return -1 on error. */
PyAPI_FUNC(int) PyCodec_Unregister(
PyObject *search_function
);
/* Codec registry lookup API.
Looks up the given encoding and returns a CodecInfo object with

View file

@ -1641,6 +1641,18 @@ def test_register(self):
self.assertRaises(TypeError, codecs.register)
self.assertRaises(TypeError, codecs.register, 42)
def test_unregister(self):
name = "nonexistent_codec_name"
search_function = mock.Mock()
codecs.register(search_function)
self.assertRaises(TypeError, codecs.lookup, name)
search_function.assert_called_with(name)
search_function.reset_mock()
codecs.unregister(search_function)
self.assertRaises(LookupError, codecs.lookup, name)
search_function.assert_not_called()
def test_lookup(self):
self.assertRaises(TypeError, codecs.lookup)
self.assertRaises(LookupError, codecs.lookup, "__spam__")

View file

@ -1575,6 +1575,7 @@ Akash Shende
Charlie Shepherd
Bruce Sherwood
Gregory Shevchenko
Hai Shi
Alexander Shigin
Pete Shinners
Michael Shiplett

View file

@ -0,0 +1,2 @@
Add :c:func:`PyCodec_Unregister` function to unregister a codec search
function.

View file

@ -0,0 +1 @@
Add :func:`codecs.unregister` function to unregister a codec search function.

View file

@ -68,6 +68,27 @@ _codecs_register(PyObject *module, PyObject *search_function)
Py_RETURN_NONE;
}
/*[clinic input]
_codecs.unregister
search_function: object
/
Unregister a codec search function and clear the registry's cache.
If the search function is not registered, do nothing.
[clinic start generated code]*/
static PyObject *
_codecs_unregister(PyObject *module, PyObject *search_function)
/*[clinic end generated code: output=1f0edee9cf246399 input=dd7c004c652d345e]*/
{
if (PyCodec_Unregister(search_function) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
/*[clinic input]
_codecs.lookup
encoding: str
@ -992,6 +1013,7 @@ _codecs_lookup_error_impl(PyObject *module, const char *name)
static PyMethodDef _codecs_functions[] = {
_CODECS_REGISTER_METHODDEF
_CODECS_UNREGISTER_METHODDEF
_CODECS_LOOKUP_METHODDEF
_CODECS_ENCODE_METHODDEF
_CODECS_DECODE_METHODDEF

View file

@ -15,6 +15,17 @@ PyDoc_STRVAR(_codecs_register__doc__,
#define _CODECS_REGISTER_METHODDEF \
{"register", (PyCFunction)_codecs_register, METH_O, _codecs_register__doc__},
PyDoc_STRVAR(_codecs_unregister__doc__,
"unregister($module, search_function, /)\n"
"--\n"
"\n"
"Unregister a codec search function and clear the registry\'s cache.\n"
"\n"
"If the search function is not registered, do nothing.");
#define _CODECS_UNREGISTER_METHODDEF \
{"unregister", (PyCFunction)_codecs_unregister, METH_O, _codecs_unregister__doc__},
PyDoc_STRVAR(_codecs_lookup__doc__,
"lookup($module, encoding, /)\n"
"--\n"
@ -2827,4 +2838,4 @@ exit:
#ifndef _CODECS_CODE_PAGE_ENCODE_METHODDEF
#define _CODECS_CODE_PAGE_ENCODE_METHODDEF
#endif /* !defined(_CODECS_CODE_PAGE_ENCODE_METHODDEF) */
/*[clinic end generated code: output=eeead01414be6e42 input=a9049054013a1b77]*/
/*[clinic end generated code: output=9a97e2ddf3e69072 input=a9049054013a1b77]*/

View file

@ -50,6 +50,31 @@ int PyCodec_Register(PyObject *search_function)
return -1;
}
int
PyCodec_Unregister(PyObject *search_function)
{
PyInterpreterState *interp = PyInterpreterState_Get();
PyObject *codec_search_path = interp->codec_search_path;
/* Do nothing if codec_search_path is not created yet or was cleared. */
if (codec_search_path == NULL) {
return 0;
}
assert(PyList_CheckExact(codec_search_path));
Py_ssize_t n = PyList_GET_SIZE(codec_search_path);
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *item = PyList_GET_ITEM(codec_search_path, i);
if (item == search_function) {
if (interp->codec_search_cache != NULL) {
assert(PyDict_CheckExact(interp->codec_search_cache));
PyDict_Clear(interp->codec_search_cache);
}
return PyList_SetSlice(codec_search_path, i, i+1, NULL);
}
}
return 0;
}
extern int _Py_normalize_encoding(const char *, char *, size_t);
/* Convert a string to a normalized Python string(decoded from UTF-8): all characters are