8000 gh-132952: Speed up startup by importing _io instead of io (#132957) · python/cpython@58567cc · GitHub
[go: up one dir, main page]

Skip to content

Commit 58567cc

Browse files
gh-132952: Speed up startup by importing _io instead of io (#132957)
1 parent 7f16f1b commit 58567cc

11 files changed

+50
-6
lines changed

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ struct _Py_global_strings {
514514
STRUCT_FOR_ID(intern)
515515
STRUCT_FOR_ID(intersection)
516516
STRUCT_FOR_ID(interval)
517+
STRUCT_FOR_ID(io)
517518
STRUCT_FOR_ID(is_running)
518519
STRUCT_FOR_ID(is_struct)
519520
STRUCT_FOR_ID(isatty)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/io.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@
6060
IncrementalNewlineDecoder, text_encoding, TextIOWrapper)
6161

6262

63-
# Pretend this exception was created here.
64-
UnsupportedOperation.__module__ = "io"
65-
6663
# for seek()
6764
SEEK_SET = 0
6865
SEEK_CUR = 1

Lib/site.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
import os
7474
import builtins
7575
import _sitebuiltins
76-
import io
76+
import _io as io
7777
import stat
7878

7979
# Prefixes for site-packages; add additional prefixes like /usr/local here

Lib/test/test_io.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,25 @@ def test_invalid_operations(self):
445445
self.assertRaises(exc, fp.seek, 1, self.SEEK_CUR)
446446
self.assertRaises(exc, fp.seek, -1, self.SEEK_END)
447447

448+
@support.cpython_only
449+
def test_startup_optimization(self):
450+
# gh-132952: Test that `io` is not imported at startup and that the
451+
# __module__ of UnsupportedOperation is set to "io".
452+
assert_python_ok("-S", "-c", textwrap.dedent(
453+
"""
454+
import sys
455+
assert "io" not in sys.modules
456+
try:
457+
sys.stdin.truncate()
458+
except Exception as e:
459+
typ = type(e)
460+
assert typ.__module__ == "io", (typ, typ.__module__)
461+
assert typ.__name__ == "UnsupportedOperation", (typ, typ.__name__)
462+
else:
463+
raise AssertionError("Expected UnsupportedOperation")
464+
"""
465+
))
466+
448467
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
449468
def test_optional_abilities(self):
450469
# Test for OSError when optional APIs are not supported

Lib/test/test_site.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import test.support
99
from test import support
1010
from test.support.script_helper import assert_python_ok
11+
from test.support import import_helper
1112
from test.support import os_helper
1213
from test.support import socket_helper
1314
from test.support import captured_stderr
@@ -574,6 +575,17 @@ def test_license_exists_at_url(self):
574575
code = e.code
575576
self.assertEqual(code, 200, msg="Can't find " + url)
576577

578+
@support.cpython_only
579+
def test_lazy_imports(self):
580+
import_helper.ensure_lazy_imports("site", [
581+
"io",
582+
"locale",
583+
"traceback",
584+
"atexit",
585+
"warnings",
586+
"textwrap",
587+
])
588+
577589

578590
class StartupImportTests(unittest.TestCase):
579591

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Speed up startup with the ``-S`` argument by importing the
2+
private ``_io`` module instead of :mod:`io`. This fixes a performance
3+
regression introduced earlier in Python 3.14 development and restores performance
4+
to the level of Python 3.13.

Modules/_io/_iomodule.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,11 @@ iomodule_exec(PyObject *m)
661661
"UnsupportedOperation", PyExc_OSError, PyExc_ValueError);
662662
if (state->unsupported_operation == NULL)
663663
return -1;
664+
if (PyObject_SetAttrString(state->unsupported_operation,
665+
"__module__", &_Py_ID(io)) < 0)
666+
{
667+
return -1;
668+
}
664669
if (PyModule_AddObjectRef(m, "UnsupportedOperation",
665670
state->unsupported_operation) < 0)
666671
{

Python/pylifecycle.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,7 +2755,7 @@ init_set_builtins_open(void)
27552755
goto error;
27562756
}
27572757

2758-
if (!(wrapper = PyImport_ImportModuleAttrString("io", "open"))) {
2758+
if (!(wrapper = PyImport_ImportModuleAttrString("_io", "open"))) {
27592759
goto error;
27602760
}
27612761

@@ -2800,7 +2800,7 @@ init_sys_streams(PyThreadState *tstate)
28002800
}
28012801
#endif
28022802

2803-
if (!(iomod = PyImport_ImportModule("io"))) {
2803+
if (!(iomod = PyImport_ImportModule("_io"))) {
28042804
goto error;
28052805
}
28062806

0 commit comments

Comments
 (0)
0