Skip to content

Commit feb5e53

Browse files
authored
Merge branch 'main' into ascii-lower-upper-word
2 parents 9d2c049 + 9c37326 commit feb5e53

3 files changed

Lines changed: 43 additions & 37 deletions

File tree

‎.github/CODEOWNERS‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,13 @@ Doc/library/importlib.resources.rst @jaraco @warsaw @FFY00
510510
Lib/importlib/resources/ @jaraco @warsaw @FFY00
511511
Lib/test/test_importlib/resources/ @jaraco @warsaw @FFY00
512512

513+
# IO
514+
Doc/library/io.rst @cmaloney
515+
Lib/_pyio.py @cmaloney
516+
Lib/io.py @cmaloney
517+
Lib/test/test_io/ @cmaloney
518+
Modules/_io/ @cmaloney
519+
513520
# Itertools
514521
Doc/library/itertools.rst @rhettinger
515522
Lib/test/test_itertools.py @rhettinger

‎Lib/test/test_embed.py‎

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
INIT_LOOPS = 4
4949
MAX_HASH_SEED = 4294967295
5050

51+
# Environment variables that change runtime but should not break embedding.
52+
RUNTIME_ENVVARS = ('PYTHON_GIL', 'PYTHON_JIT_STRESS', 'PYTHON_UOPS_OPTIMIZE')
53+
5154
ABI_THREAD = 't' if support.Py_GIL_DISABLED else ''
5255
# PLATSTDLIB_LANDMARK copied from Modules/getpath.py
5356
if os.name == 'nt':
@@ -133,21 +136,24 @@ def tearDown(self):
133136

134137
def run_embedded_interpreter(self, *args, env=None,
135138
timeout=None, returncode=0, input=None,
136-
cwd=None):
139+
cwd=None, runtime_envvars=True):
137140
"""Runs a test in the embedded interpreter"""
138141
cmd = [self.test_exe]
139142
cmd.extend(args)
140-
if env is not None and MS_WINDOWS:
141-
# Windows requires at least the SYSTEMROOT environment variable to
142-
# start Python.
143-
env = env.copy()
144-
env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
143+
safe_env = remove_python_envvars()
144+
# Copy across runtime-modifying variables.
145+
if runtime_envvars:
146+
for name in RUNTIME_ENVVARS:
147+
if name in os.environ:
148+
safe_env[name] = os.environ[name]
149+
if env:
150+
safe_env.update(env)
145151

146152
kwargs = dict(
147153
stdout=subprocess.PIPE,
148154
stderr=subprocess.PIPE,
149155
universal_newlines=True,
150-
env=env,
156+
env=safe_env,
151157
cwd=cwd,
152158
)
153159
if input is not None:
@@ -323,7 +329,7 @@ def test_inittab_submodule_singlephase(self):
323329

324330
def test_forced_io_encoding(self):
325331
# Checks forced configuration of embedded interpreter IO streams
326-
env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
332+
env = {'PYTHONIOENCODING': 'utf-8:surrogateescape'}
327333
out, err = self.run_embedded_interpreter("test_forced_io_encoding", env=env)
328334
if support.verbose > 1:
329335
print()
@@ -369,7 +375,7 @@ def test_pre_initialization_api(self):
369375
Checks some key parts of the C-API that need to work before the runtime
370376
is initialized (via Py_Initialize()).
371377
"""
372-
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
378+
env = {'PYTHONPATH': os.pathsep.join(sys.path)}
373379
out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env)
374380
if support.verbose > 1:
375381
print()
@@ -390,8 +396,7 @@ def test_pre_initialization_sys_options(self):
390396
Checks that sys.warnoptions and sys._xoptions can be set before the
391397
runtime is initialized (otherwise they won't be effective).
392398
"""
393-
env = remove_python_envvars()
394-
env['PYTHONPATH'] = os.pathsep.join(sys.path)
399+
env = {'PYTHONPATH': os.pathsep.join(sys.path)}
395400
out, err = self.run_embedded_interpreter(
396401
"test_pre_initialization_sys_options", env=env)
397402
if support.verbose > 1:
@@ -686,10 +691,8 @@ def test_init_run_main_startup_exitcode(self):
686691
with open(filename, 'x') as fp:
687692
fp.write(CODE_EXITCODE_123)
688693

689-
env = dict(os.environ)
690-
env['PYTHONSTARTUP'] = filename
691694
self.check_program_exitcode("test_init_run_main_interactive_exitcode",
692-
env=env,
695+
env={'PYTHONSTARTUP': filename},
693696
check_stderr=False)
694697

695698
def test_init_run_main_module_exitcode(self):
@@ -699,10 +702,8 @@ def test_init_run_main_module_exitcode(self):
699702
with open(filename, 'x', encoding='utf8') as fp:
700703
fp.write(CODE_EXITCODE_123)
701704

702-
env = dict(os.environ)
703-
env['PYTHONPATH'] = tmpdir
704705
self.check_program_exitcode("test_init_run_main_module_exitcode",
705-
modname, env=env)
706+
modname, env={'PYTHONPATH': tmpdir})
706707

707708

708709
def config_dev_mode(preconfig, config):
@@ -1061,11 +1062,6 @@ def check_all_configs(self, testname, expected_config=None,
10611062
modify_path_cb=None,
10621063
stderr=None, *, api, preconfig_api=None,
10631064
env=None, ignore_stderr=False, cwd=None):
1064-
new_env = remove_python_envvars()
1065-
if env is not None:
1066-
new_env.update(env)
1067-
env = new_env
1068-
10691065
if preconfig_api is None:
10701066
preconfig_api = api
10711067
if preconfig_api == API_ISOLATED:
@@ -1094,8 +1090,9 @@ def check_all_configs(self, testname, expected_config=None,
10941090
env,
10951091
api, modify_path_cb)
10961092

1097-
out, err = self.run_embedded_interpreter(testname,
1098-
env=env, cwd=cwd)
1093+
# Ignore runtime flags like PYTHON_GIL to get the build configuration.
1094+
out, err = self.run_embedded_interpreter(testname, env=env, cwd=cwd,
1095+
runtime_envvars=False)
10991096
if stderr is None and not expected_config['verbose']:
11001097
stderr = ""
11011098
if stderr is not None and not ignore_stderr:
@@ -1871,8 +1868,7 @@ def test_getpath_abspath_win32(self):
18711868
]
18721869
out, err = self.run_embedded_interpreter(
18731870
"test_init_initialize_config",
1874-
env={**remove_python_envvars(),
1875-
"PYTHONPATH": os.path.pathsep.join(c[0] for c in CASES)}
1871+
env={"PYTHONPATH": os.path.pathsep.join(c[0] for c in CASES)}
18761872
)
18771873
self.assertEqual(err, "")
18781874
try:
@@ -2085,7 +2081,7 @@ def test_audit_run_interactivehook(self):
20852081
print("import sys", file=f)
20862082
print("sys.__interactivehook__ = lambda: None", file=f)
20872083
try:
2088-
env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
2084+
env = {"PYTHONSTARTUP": startup}
20892085
self.run_embedded_interpreter("test_audit_run_interactivehook",
20902086
timeout=support.SHORT_TIMEOUT,
20912087
returncode=10, env=env)
@@ -2097,7 +2093,7 @@ def test_audit_run_startup(self):
20972093
with open(startup, "w", encoding="utf-8") as f:
20982094
print("pass", file=f)
20992095
try:
2100-
env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
2096+
env = {"PYTHONSTARTUP": startup}
21012097
self.run_embedded_interpreter("test_audit_run_startup",
21022098
timeout=support.SHORT_TIMEOUT,
21032099
returncode=10, env=env)
@@ -2143,8 +2139,7 @@ def test_unicode_id_init(self):
21432139
'Py_FrozenMain is not exported on Windows')
21442140
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
21452141
def test_frozenmain(self):
2146-
env = dict(os.environ)
2147-
env['PYTHONUNBUFFERED'] = '1'
2142+
env = {'PYTHONUNBUFFERED': '1'}
21482143
out, err = self.run_embedded_interpreter("test_frozenmain", env=env)
21492144
executable = os.path.realpath('./argv0')
21502145
expected = textwrap.dedent(f"""

‎Modules/_io/fileio.c‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Author: Daniel Stutzbach */
22

33
#include "Python.h"
4+
#include "pycore_abstract.h" // _PyIndex_Check()
45
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
56
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
67
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
@@ -300,14 +301,17 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
300301
return -1;
301302
}
302303
}
303-
fd = PyLong_AsInt(nameobj);
304-
if (fd < 0) {
305-
if (!PyErr_Occurred()) {
306-
PyErr_SetString(PyExc_ValueError,
307-
"negative file descriptor");
308-
return -1;
304+
if (_PyIndex_Check(nameobj)) {
305+
fd = PyLong_AsInt(nameobj);
306+
if (fd < 0) {
307+
if (!PyErr_Occurred()) {
308+
PyErr_SetString(PyExc_ValueError,
309+
"negative file descriptor");
310+
return -1;
311+
}
312+
/* Failed to convert; try other paths. */
313+
PyErr_Clear();
309314
}
310-
PyErr_Clear();
311315
}
312316

313317
if (fd < 0) {

0 commit comments

Comments
 (0)