Skip to content

Commit c5c556c

Browse files
committed
Add sys.warn_default_encoding
1 parent 4016278 commit c5c556c

File tree

11 files changed

+57
-25
lines changed

11 files changed

+57
-25
lines changed

Include/cpython/initconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ typedef struct PyConfig {
134134
int isolated;
135135
int use_environment;
136136
int dev_mode;
137+
int warn_default_encoding;
137138
int install_signal_handlers;
138139
int use_hash_seed;
139140
unsigned long hash_seed;

Include/internal/pycore_initconfig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,15 @@ typedef struct {
102102
int isolated; /* -I option */
103103
int use_environment; /* -E option */
104104
int dev_mode; /* -X dev and PYTHONDEVMODE */
105+
int warn_default_encoding; /* -X warndefaultencoding and PYTHONWARNDEFAULTENCODING */
105106
} _PyPreCmdline;
106107

107108
#define _PyPreCmdline_INIT \
108109
(_PyPreCmdline){ \
109110
.use_environment = -1, \
110111
.isolated = -1, \
111-
.dev_mode = -1}
112+
.dev_mode = -1, \
113+
.warn_default_encoding = -1}
112114
/* Note: _PyPreCmdline_INIT sets other fields to 0/NULL */
113115

114116
extern void _PyPreCmdline_Clear(_PyPreCmdline *cmdline);

Lib/_pyio.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ def text_encoding(encoding, stacklevel=1):
4545
Helper function to choose the text encoding.
4646
4747
When encoding is not None, just return it.
48-
Otherwise, return the default text encoding ("locale" for now)
49-
and raise a EncodingWarning in dev mode.
48+
Otherwise, return the default text encoding (i.e. "locale").
49+
50+
This function emits EncodingWarning if *encoding* is None and
51+
sys.flags.encoding_warning is true.
5052
5153
This function can be used in APIs having encoding=None option.
5254
But please consider encoding="utf-8" for new APIs.
5355
"""
5456
if encoding is None:
55-
if sys.flags.dev_mode:
57+
if sys.flags.warn_default_encoding:
5658
import warnings
5759
warnings.warn(
5860
"'encoding' option is not specified. The default encoding "

Lib/test/test_io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4242,7 +4242,7 @@ def test_check_encoding_warning(self):
42424242
42434243
pathlib.Path({filename!r}).read_text() # line 8
42444244
''')
4245-
proc = assert_python_ok('-X', 'dev', '-c', code)
4245+
proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code)
42464246
warnings = proc.err.splitlines()
42474247
self.assertEqual(len(warnings), 2)
42484248
self.assertTrue(

Lib/test/test_sys.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,8 @@ def test_sys_flags(self):
591591
"inspect", "interactive", "optimize",
592592
"dont_write_bytecode", "no_user_site", "no_site",
593593
"ignore_environment", "verbose", "bytes_warning", "quiet",
594-
"hash_randomization", "isolated", "dev_mode", "utf8_mode")
594+
"hash_randomization", "isolated", "dev_mode", "utf8_mode",
595+
"warn_default_encoding")
595596
for attr in attrs:
596597
self.assertTrue(hasattr(sys.flags, attr), attr)
597598
attr_type = bool if attr == "dev_mode" else int

Modules/_io/_iomodule.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,10 @@ _io.text_encoding
516516
Helper function to choose the text encoding.
517517
518518
When encoding is not None, just return it.
519-
Otherwise, return the default text encoding ("locale" for now)
520-
and raise a EncodingWarning in dev mode.
519+
Otherwise, return the default text encoding (i.e. "locale").
520+
521+
This function emits EncodingWarning if *encoding* is None and
522+
sys.flags.encoding_warning is true.
521523
522524
This function can be used in APIs having encoding=None option.
523525
But please consider encoding="utf-8" for new APIs.
@@ -529,11 +531,9 @@ _io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel)
529531
{
530532
if (encoding == NULL || encoding == Py_None) {
531533
PyInterpreterState *interp = _PyInterpreterState_GET();
532-
if (!_PyInterpreterState_GetConfig(interp)->dev_mode) {
534+
if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) {
533535
PyErr_WarnEx(PyExc_EncodingWarning,
534-
"'encoding' option is not specified. The default encoding "
535-
"will be changed to 'utf-8' in the future",
536-
stacklevel + 1);
536+
"'encoding' option is omitted", stacklevel + 1);
537537
}
538538
Py_INCREF(_PyIO_str_locale);
539539
return _PyIO_str_locale;

Modules/_io/textio.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,10 +1125,9 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
11251125

11261126
if (encoding == NULL) {
11271127
PyInterpreterState *interp = _PyInterpreterState_GET();
1128-
if (!_PyInterpreterState_GetConfig(interp)->dev_mode) {
1129-
PyErr_WarnEx(PyExc_DeprecationWarning,
1130-
"'encoding' option is not specified. The default encoding "
1131-
"will be changed to 'utf-8' in the future", 1);
1128+
if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) {
1129+
PyErr_WarnEx(PyExc_EncodingWarning,
1130+
"'encoding' option is omitted", 1);
11321131
}
11331132
}
11341133
else if (strcmp(encoding, "locale") == 0) {

Objects/exceptions.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,13 +2406,6 @@ SimpleExtendsException(PyExc_Warning, UserWarning,
24062406
"Base class for warnings generated by user code.");
24072407

24082408

2409-
/*
2410-
* EncodingWarning extends Warning
2411-
*/
2412-
SimpleExtendsException(PyExc_Warning, EncodingWarning,
2413-
"Base class for warnings about encodings.");
2414-
2415-
24162409
/*
24172410
* DeprecationWarning extends Warning
24182411
*/
@@ -2428,6 +2421,13 @@ SimpleExtendsException(PyExc_Warning, PendingDeprecationWarning,
24282421
"in the future.");
24292422

24302423

2424+
/*
2425+
* EncodingWarning extends Warning
2426+
*/
2427+
SimpleExtendsException(PyExc_DeprecationWarning, EncodingWarning,
2428+
"Base class for warnings about encodings.");
2429+
2430+
24312431
/*
24322432
* SyntaxWarning extends Warning
24332433
*/

Python/initconfig.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static const char usage_3[] = "\
9494
otherwise activate automatically)\n\
9595
-X pycache_prefix=PATH: enable writing .pyc files to a parallel tree rooted at the\n\
9696
given directory instead of to the code tree\n\
97+
-X warn_default_encoding: enable opt-in EncodingWarning for 'encoding=None'\n\
9798
\n\
9899
--check-hash-based-pycs always|default|never:\n\
99100
control how Python invalidates hash-based .pyc files\n\
@@ -129,7 +130,8 @@ static const char usage_6[] =
129130
"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
130131
" debugger. It can be set to the callable of your debugger of choice.\n"
131132
"PYTHONDEVMODE: enable the development mode.\n"
132-
"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n";
133+
"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n"
134+
"PYTHONWARNDEFAULTENCODING: enable opt-in EncodingWarning for 'encoding=None'.\n";
133135

134136
#if defined(MS_WINDOWS)
135137
# define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
@@ -589,6 +591,7 @@ config_check_consistency(const PyConfig *config)
589591
assert(config->isolated >= 0);
590592
assert(config->use_environment >= 0);
591593
assert(config->dev_mode >= 0);
594+
assert(config->warn_default_encoding >= 0);
592595
assert(config->install_signal_handlers >= 0);
593596
assert(config->use_hash_seed >= 0);
594597
assert(config->hash_seed <= MAX_HASH_SEED);
@@ -690,6 +693,7 @@ _PyConfig_InitCompatConfig(PyConfig *config)
690693
config->isolated = -1;
691694
config->use_environment = -1;
692695
config->dev_mode = -1;
696+
config->warn_default_encoding = -1;
693697
config->install_signal_handlers = 1;
694698
config->use_hash_seed = -1;
695699
config->faulthandler = -1;
@@ -765,6 +769,7 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
765769
config->use_environment = 0;
766770
config->user_site_directory = 0;
767771
config->dev_mode = 0;
772+
config->warn_default_encoding = 0;
768773
config->install_signal_handlers = 0;
769774
config->use_hash_seed = 0;
770775
config->faulthandler = 0;
@@ -873,6 +878,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
873878
COPY_ATTR(isolated);
874879
COPY_ATTR(use_environment);
875880
COPY_ATTR(dev_mode);
881+
COPY_ATTR(warn_default_encoding);
876882
COPY_ATTR(install_signal_handlers);
877883
COPY_ATTR(use_hash_seed);
878884
COPY_ATTR(hash_seed);
@@ -977,6 +983,7 @@ _PyConfig_AsDict(const PyConfig *config)
977983
SET_ITEM_INT(isolated);
978984
SET_ITEM_INT(use_environment);
979985
SET_ITEM_INT(dev_mode);
986+
SET_ITEM_INT(warn_default_encoding);
980987
SET_ITEM_INT(install_signal_handlers);
981988
SET_ITEM_INT(use_hash_seed);
982989
SET_ITEM_UINT(hash_seed);
@@ -1249,6 +1256,7 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict)
12491256
GET_UINT(isolated);
12501257
GET_UINT(use_environment);
12511258
GET_UINT(dev_mode);
1259+
GET_UINT(warn_default_encoding);
12521260
GET_UINT(install_signal_handlers);
12531261
GET_UINT(use_hash_seed);
12541262
if (config_dict_get_ulong(dict, "hash_seed", &config->hash_seed) < 0) {
@@ -2136,6 +2144,10 @@ config_read(PyConfig *config, int compute_path_config)
21362144
config->parse_argv = 2;
21372145
}
21382146

2147+
if (config->warn_default_encoding < 0) {
2148+
config->warn_default_encoding = 0;
2149+
}
2150+
21392151
return _PyStatus_OK();
21402152
}
21412153

Python/preconfig.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ _PyPreCmdline_SetConfig(const _PyPreCmdline *cmdline, PyConfig *config)
169169
COPY_ATTR(isolated);
170170
COPY_ATTR(use_environment);
171171
COPY_ATTR(dev_mode);
172+
COPY_ATTR(warn_default_encoding);
172173
return _PyStatus_OK();
173174

174175
#undef COPY_ATTR
@@ -257,9 +258,21 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline, const PyPreConfig *preconfig)
257258
cmdline->dev_mode = 0;
258259
}
259260

261+
// warn_default_encoding
262+
if ((cmdline->warn_default_encoding < 0)
263+
&& (_Py_get_xoption(&cmdline->xoptions, L"warn_default_encoding")
264+
|| _Py_GetEnv(cmdline->use_environment, "PYTHONWARNDEFAULTENCODING")))
265+
{
266+
cmdline->warn_default_encoding = 1;
267+
}
268+
if (cmdline->warn_default_encoding < 0) {
269+
cmdline->warn_default_encoding = 0;
270+
}
271+
260272
assert(cmdline->use_environment >= 0);
261273
assert(cmdline->isolated >= 0);
262274
assert(cmdline->dev_mode >= 0);
275+
assert(cmdline->warn_default_encoding >= 0);
263276

264277
return _PyStatus_OK();
265278
}

Python/sysmodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2506,14 +2506,15 @@ static PyStructSequence_Field flags_fields[] = {
25062506
{"isolated", "-I"},
25072507
{"dev_mode", "-X dev"},
25082508
{"utf8_mode", "-X utf8"},
2509+
{"warn_default_encoding", "-X warndefaultencoding"},
25092510
{0}
25102511
};
25112512

25122513
static PyStructSequence_Desc flags_desc = {
25132514
"sys.flags", /* name */
25142515
flags__doc__, /* doc */
25152516
flags_fields, /* fields */
2516-
15
2517+
16
25172518
};
25182519

25192520
static int
@@ -2552,6 +2553,7 @@ set_flags_from_config(PyObject *flags, PyThreadState *tstate)
25522553
SetFlag(config->use_hash_seed == 0 || config->hash_seed != 0);
25532554
SetFlag(config->isolated);
25542555
SetFlagObj(PyBool_FromLong(config->dev_mode));
2556+
SetFlagObj(PyBool_FromLong(config->warn_default_encoding));
25552557
SetFlag(preconfig->utf8_mode);
25562558
#undef SetFlagObj
25572559
#undef SetFlag

0 commit comments

Comments
 (0)