[Python-checkins] bpo-36763: Implement PyWideStringList_Insert() of PEP 587 (GH-15423)

Victor Stinner webhook-mailer at python.org
Fri Aug 23 11:57:58 EDT 2019


https://github.com/python/cpython/commit/3842f2997fbd4dc840986aad2bb94656815e243b
commit: 3842f2997fbd4dc840986aad2bb94656815e243b
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-08-23T16:57:54+01:00
summary:

bpo-36763: Implement PyWideStringList_Insert() of PEP 587 (GH-15423)

files:
M Doc/c-api/init_config.rst
M Include/cpython/initconfig.h
M Lib/test/test_embed.py
M Programs/_testembed.c
M Python/initconfig.c

diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index d2c1f9a2f3e3..5fd836d77b81 100644
--- a/Doc/c-api/init_config.rst
+++ b/Doc/c-api/init_config.rst
@@ -72,8 +72,12 @@ PyWideStringList
 
    .. c:function:: PyStatus PyWideStringList_Insert(PyWideStringList *list, Py_ssize_t index, const wchar_t *item)
 
-      Insert *item* into *list* at *index*. If *index* is greater than *list*
-      length, just append *item* to *list*.
+      Insert *item* into *list* at *index*.
+
+      If *index* is greater than or equal to *list* length, append *item* to
+      *list*.
+
+      *index* must be greater than or equal to 0.
 
       Python must be preinitialized to call this function.
 
diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h
index bd07a4829b47..047f511f3104 100644
--- a/Include/cpython/initconfig.h
+++ b/Include/cpython/initconfig.h
@@ -37,6 +37,9 @@ typedef struct {
 
 PyAPI_FUNC(PyStatus) PyWideStringList_Append(PyWideStringList *list,
     const wchar_t *item);
+PyAPI_FUNC(PyStatus) PyWideStringList_Insert(PyWideStringList *list,
+    Py_ssize_t index,
+    const wchar_t *item);
 
 
 /* --- PyPreConfig ----------------------------------------------- */
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 37f542b29540..6fb401200380 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -500,7 +500,7 @@ def _get_expected_config(self, env):
             self.fail(f"fail to decode stdout: {stdout!r}")
 
     def get_expected_config(self, expected_preconfig, expected, env, api,
-                            add_path=None):
+                            modify_path_cb=None):
         cls = self.__class__
         if cls.EXPECTED_CONFIG is None:
             cls.EXPECTED_CONFIG = self._get_expected_config(env)
@@ -556,8 +556,9 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
         prepend_path = expected['pythonpath_env']
         if prepend_path is not None:
             expected['module_search_paths'] = [prepend_path, *expected['module_search_paths']]
-        if add_path is not None:
-            expected['module_search_paths'] = [*expected['module_search_paths'], add_path]
+        if modify_path_cb is not None:
+            expected['module_search_paths'] = expected['module_search_paths'].copy()
+            modify_path_cb(expected['module_search_paths'])
 
         for key in self.COPY_PRE_CONFIG:
             if key not in expected_preconfig:
@@ -602,7 +603,7 @@ def check_global_config(self, configs):
         self.assertEqual(configs['global_config'], expected)
 
     def check_all_configs(self, testname, expected_config=None,
-                     expected_preconfig=None, add_path=None, stderr=None,
+                     expected_preconfig=None, modify_path_cb=None, stderr=None,
                      *, api):
         env = remove_python_envvars()
 
@@ -628,7 +629,7 @@ def check_all_configs(self, testname, expected_config=None,
 
         self.get_expected_config(expected_preconfig,
                                  expected_config, env,
-                                 api, add_path)
+                                 api, modify_path_cb)
 
         out, err = self.run_embedded_interpreter(testname, env=env)
         if stderr is None and not expected_config['verbose']:
@@ -894,9 +895,12 @@ def test_init_read_set(self):
             'program_name': './init_read_set',
             'executable': 'my_executable',
         }
+        def modify_path(path):
+            path.insert(1, "test_path_insert1")
+            path.append("test_path_append")
         self.check_all_configs("test_init_read_set", config,
                                api=API_PYTHON,
-                               add_path="init_read_set_path")
+                               modify_path_cb=modify_path)
 
     def test_init_run_main(self):
         code = ('import _testinternalcapi, json; '
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 3d27ed2a4003..38730095dab0 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -1350,8 +1350,14 @@ static int test_init_read_set(void)
         goto fail;
     }
 
+    status = PyWideStringList_Insert(&config.module_search_paths,
+                                     1, L"test_path_insert1");
+    if (PyStatus_Exception(status)) {
+        goto fail;
+    }
+
     status = PyWideStringList_Append(&config.module_search_paths,
-                                     L"init_read_set_path");
+                                     L"test_path_append");
     if (PyStatus_Exception(status)) {
         goto fail;
     }
diff --git a/Python/initconfig.c b/Python/initconfig.c
index 5bd7d4fcf889..b706f4cb8512 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -297,32 +297,53 @@ _PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
 
 
 PyStatus
-PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)
+PyWideStringList_Insert(PyWideStringList *list,
+                        Py_ssize_t index, const wchar_t *item)
 {
-    if (list->length == PY_SSIZE_T_MAX) {
+    Py_ssize_t len = list->length;
+    if (len == PY_SSIZE_T_MAX) {
         /* length+1 would overflow */
         return _PyStatus_NO_MEMORY();
     }
+    if (index < 0) {
+        return _PyStatus_ERR("PyWideStringList_Insert index must be >= 0");
+    }
+    if (index > len) {
+        index = len;
+    }
 
     wchar_t *item2 = _PyMem_RawWcsdup(item);
     if (item2 == NULL) {
         return _PyStatus_NO_MEMORY();
     }
 
-    size_t size = (list->length + 1) * sizeof(list->items[0]);
+    size_t size = (len + 1) * sizeof(list->items[0]);
     wchar_t **items2 = (wchar_t **)PyMem_RawRealloc(list->items, size);
     if (items2 == NULL) {
         PyMem_RawFree(item2);
         return _PyStatus_NO_MEMORY();
     }
 
-    items2[list->length] = item2;
+    if (index < len) {
+        memmove(&items2[index + 1],
+                &items2[index],
+                (len - index) * sizeof(items2[0]));
+    }
+
+    items2[index] = item2;
     list->items = items2;
     list->length++;
     return _PyStatus_OK();
 }
 
 
+PyStatus
+PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)
+{
+    return PyWideStringList_Insert(list, list->length, item);
+}
+
+
 PyStatus
 _PyWideStringList_Extend(PyWideStringList *list, const PyWideStringList *list2)
 {



More information about the Python-checkins mailing list