@@ -273,7 +273,7 @@ _PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2)
273273return 0 ;
274274 }
275275
276- PyWideStringList copy = PyWideStringList_INIT ;
276+ PyWideStringList copy = _PyWideStringList_INIT ;
277277
278278size_t size = list2 -> length * sizeof (list2 -> items [0 ]);
279279copy .items = PyMem_RawMalloc (size );
@@ -2095,63 +2095,83 @@ config_init_env_warnoptions(PyConfig *config, PyWideStringList *warnoptions)
20952095
20962096
20972097static PyStatus
2098- config_add_warnoption (PyConfig * config ,const wchar_t * option )
2098+ warnoptions_append (PyConfig * config ,PyWideStringList * options ,
2099+ const wchar_t * option )
20992100{
2101+ /* config_init_warnoptions() add existing config warnoptions at the end:
2102+ ensure that the new option is not already present in this list to
2103+ prevent change the options order whne config_init_warnoptions() is
2104+ called twice. */
21002105if (_PyWideStringList_Find (& config -> warnoptions ,option )) {
21012106/* Already present: do nothing */
21022107return _PyStatus_OK ();
21032108 }
2104- return PyWideStringList_Append (& config -> warnoptions ,option );
2109+ if (_PyWideStringList_Find (options ,option )) {
2110+ /* Already present: do nothing */
2111+ return _PyStatus_OK ();
2112+ }
2113+ return PyWideStringList_Append (options ,option );
2114+ }
2115+
2116+
2117+ static PyStatus
2118+ warnoptions_extend (PyConfig * config ,PyWideStringList * options ,
2119+ const PyWideStringList * options2 )
2120+ {
2121+ const Py_ssize_t len = options2 -> length ;
2122+ wchar_t * const * items = options2 -> items ;
2123+
2124+ for (Py_ssize_t i = 0 ;i < len ;i ++ ) {
2125+ PyStatus status = warnoptions_append (config ,options ,items [i ]);
2126+ if (_PyStatus_EXCEPTION (status )) {
2127+ return status ;
2128+ }
2129+ }
2130+ return _PyStatus_OK ();
21052131}
21062132
21072133
21082134static PyStatus
21092135config_init_warnoptions (PyConfig * config ,
21102136const PyWideStringList * cmdline_warnoptions ,
2111- const PyWideStringList * env_warnoptions )
2137+ const PyWideStringList * env_warnoptions ,
2138+ const PyWideStringList * sys_warnoptions )
21122139{
21132140PyStatus status ;
2141+ PyWideStringList options = _PyWideStringList_INIT ;
21142142
2115- /* The priority order for warnings configuration is (highest precedence
2116- * first):
2143+ /* Priority of warnings options, lowest to highest:
21172144 *
2118- * - early PySys_AddWarnOption() calls
2119- * - the BytesWarning filter, if needed ('-b', '-bb')
2120- * - any '-W' command line options; then
2121- * - the 'PYTHONWARNINGS' environment variable; then
2122- * - the dev mode filter ('-X dev', 'PYTHONDEVMODE'); then
21232145 * - any implicit filters added by _warnings.c/warnings.py
2146+ * - PyConfig.dev_mode: "default" filter
2147+ * - PYTHONWARNINGS environment variable
2148+ * - '-W' command line options
2149+ * - PyConfig.bytes_warning ('-b' and '-bb' command line options):
2150+ * "default::BytesWarning" or "error::BytesWarning" filter
2151+ * - early PySys_AddWarnOption() calls
2152+ * - PyConfig.warnoptions
21242153 *
2125- *All settings except the last are passed to the warnings module via
2126- *the `sys.warnoptions` list. Since thewarnings module works on the basis
2127- *of "the most recently added filter will be checked first", we add
2128- *the lowest precedence entries first so that later entries override them.
2154+ *PyConfig.warnoptions is copied to sys.warnoptions. Since the warnings
2155+ *module works on the basis of " themost recently added filter will be
2156+ *checked first", we add the lowest precedence entries first so that later
2157+ * entries override them.
21292158 */
21302159
21312160if (config -> dev_mode ) {
2132- status = config_add_warnoption (config ,L"default" );
2161+ status = warnoptions_append (config , & options ,L"default" );
21332162if (_PyStatus_EXCEPTION (status )) {
2134- return status ;
2163+ goto error ;
21352164 }
21362165 }
21372166
2138- Py_ssize_t i ;
2139- const PyWideStringList * options ;
2140-
2141- options = env_warnoptions ;
2142- for (i = 0 ;i < options -> length ;i ++ ) {
2143- status = config_add_warnoption (config ,options -> items [i ]);
2144- if (_PyStatus_EXCEPTION (status )) {
2145- return status ;
2146- }
2167+ status = warnoptions_extend (config ,& options ,env_warnoptions );
2168+ if (_PyStatus_EXCEPTION (status )) {
2169+ gotoerror ;
21472170 }
21482171
2149- options = cmdline_warnoptions ;
2150- for (i = 0 ;i < options -> length ;i ++ ) {
2151- status = config_add_warnoption (config ,options -> items [i ]);
2152- if (_PyStatus_EXCEPTION (status )) {
2153- return status ;
2154- }
2172+ status = warnoptions_extend (config ,& options ,cmdline_warnoptions );
2173+ if (_PyStatus_EXCEPTION (status )) {
2174+ gotoerror ;
21552175 }
21562176
21572177/* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c
@@ -2166,27 +2186,38 @@ config_init_warnoptions(PyConfig *config,
21662186else {
21672187filter = L"default::BytesWarning" ;
21682188 }
2169- status = config_add_warnoption (config ,filter );
2189+ status = warnoptions_append (config , & options ,filter );
21702190if (_PyStatus_EXCEPTION (status )) {
2171- return status ;
2191+ goto error ;
21722192 }
21732193 }
21742194
2175- /* Handle early PySys_AddWarnOption() calls */
2176- status = _PySys_ReadPreinitWarnOptions (config );
2195+ status = warnoptions_extend (config ,& options ,sys_warnoptions );
21772196if (_PyStatus_EXCEPTION (status )) {
2178- return status ;
2197+ gotoerror ;
2198+ }
2199+
2200+ /* Always add all PyConfig.warnoptions options */
2201+ status = _PyWideStringList_Extend (& options ,& config -> warnoptions );
2202+ if (_PyStatus_EXCEPTION (status )) {
2203+ gotoerror ;
21792204 }
21802205
2206+ _PyWideStringList_Clear (& config -> warnoptions );
2207+ config -> warnoptions = options ;
21812208return _PyStatus_OK ();
2209+
2210+ error :
2211+ _PyWideStringList_Clear (& options );
2212+ return status ;
21822213}
21832214
21842215
21852216static PyStatus
21862217config_update_argv (PyConfig * config ,Py_ssize_t opt_index )
21872218{
21882219const PyWideStringList * cmdline_argv = & config -> argv ;
2189- PyWideStringList config_argv = PyWideStringList_INIT ;
2220+ PyWideStringList config_argv = _PyWideStringList_INIT ;
21902221
21912222/* Copy argv to be able to modify it (to force -c/-m) */
21922223if (cmdline_argv -> length <=opt_index ) {
@@ -2270,8 +2301,9 @@ static PyStatus
22702301config_read_cmdline (PyConfig * config )
22712302{
22722303PyStatus status ;
2273- PyWideStringList cmdline_warnoptions = PyWideStringList_INIT ;
2274- PyWideStringList env_warnoptions = PyWideStringList_INIT ;
2304+ PyWideStringList cmdline_warnoptions = _PyWideStringList_INIT ;
2305+ PyWideStringList env_warnoptions = _PyWideStringList_INIT ;
2306+ PyWideStringList sys_warnoptions = _PyWideStringList_INIT ;
22752307
22762308if (config -> parse_argv < 0 ) {
22772309config -> parse_argv = 1 ;
@@ -2304,9 +2336,16 @@ config_read_cmdline(PyConfig *config)
23042336 }
23052337 }
23062338
2339+ /* Handle early PySys_AddWarnOption() calls */
2340+ status = _PySys_ReadPreinitWarnOptions (& sys_warnoptions );
2341+ if (_PyStatus_EXCEPTION (status )) {
2342+ gotodone ;
2343+ }
2344+
23072345status = config_init_warnoptions (config ,
23082346& cmdline_warnoptions ,
2309- & env_warnoptions );
2347+ & env_warnoptions ,
2348+ & sys_warnoptions );
23102349if (_PyStatus_EXCEPTION (status )) {
23112350 gotodone ;
23122351 }
@@ -2316,6 +2355,7 @@ config_read_cmdline(PyConfig *config)
23162355done :
23172356_PyWideStringList_Clear (& cmdline_warnoptions );
23182357_PyWideStringList_Clear (& env_warnoptions );
2358+ _PyWideStringList_Clear (& sys_warnoptions );
23192359return status ;
23202360}
23212361
@@ -2386,7 +2426,7 @@ PyStatus
23862426PyConfig_Read (PyConfig * config )
23872427{
23882428PyStatus status ;
2389- PyWideStringList orig_argv = PyWideStringList_INIT ;
2429+ PyWideStringList orig_argv = _PyWideStringList_INIT ;
23902430
23912431status = config_check_struct_size (config );
23922432if (_PyStatus_EXCEPTION (status )) {