Skip to content

Commit 91fd216

Browse files
committed
pythongh-149321: Remove lazy_imports=none startup mode
1 parent 8c79678 commit 91fd216

17 files changed

Lines changed: 53 additions & 214 deletions

File tree

Doc/c-api/import.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,11 +393,6 @@ Importing Modules
393393
394394
Make all imports lazy by default.
395395
396-
.. c:enumerator:: PyImport_LAZY_NONE
397-
398-
Disable lazy imports entirely. Even explicit ``lazy`` statements become
399-
eager imports.
400-
401396
.. versionadded:: 3.15
402397
403398
.. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void))

Doc/library/sys.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -919,8 +919,6 @@ always available. Unless explicitly noted otherwise, all variables are read-only
919919
* ``"normal"``: Only imports explicitly marked with the ``lazy`` keyword
920920
are lazy
921921
* ``"all"``: All top-level imports are potentially lazy
922-
* ``"none"``: All lazy imports are suppressed (even explicitly marked
923-
ones)
924922

925923
See also :func:`set_lazy_imports` and :pep:`810`.
926924

@@ -1757,8 +1755,6 @@ always available. Unless explicitly noted otherwise, all variables are read-only
17571755
* ``"normal"``: Only imports explicitly marked with the ``lazy`` keyword
17581756
are lazy
17591757
* ``"all"``: All top-level imports become potentially lazy
1760-
* ``"none"``: All lazy imports are suppressed (even explicitly marked
1761-
ones)
17621758

17631759
This function is intended for advanced users who need to control lazy
17641760
imports across their entire application. Library developers should

Doc/reference/simple_stmts.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -965,10 +965,6 @@ Imports inside functions, class bodies, or
965965
:keyword:`try`/:keyword:`except`/:keyword:`finally` blocks are always eager,
966966
regardless of :attr:`!__lazy_modules__`.
967967

968-
Setting ``-X lazy_imports=none`` (or the :envvar:`PYTHON_LAZY_IMPORTS`
969-
environment variable to ``none``) overrides :attr:`!__lazy_modules__` and
970-
forces all imports to be eager.
971-
972968
.. versionadded:: 3.15
973969

974970
.. _future:

Doc/using/cmdline.rst

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,9 @@ Miscellaneous options
705705

706706
.. versionadded:: 3.14
707707

708-
* :samp:`-X lazy_imports={all,none,normal}` controls lazy import behavior.
709-
``all`` makes all imports lazy by default, ``none`` disables lazy imports
710-
entirely (even explicit ``lazy`` statements become eager), and ``normal``
711-
(the default) respects the ``lazy`` keyword in source code.
708+
* :samp:`-X lazy_imports={all,normal}` controls lazy import behavior.
709+
``all`` makes all imports lazy by default, and ``normal`` (the default)
710+
respects the ``lazy`` keyword in source code.
712711
See also :envvar:`PYTHON_LAZY_IMPORTS`.
713712

714713
.. versionadded:: 3.15
@@ -1416,10 +1415,9 @@ conflict.
14161415

14171416
.. envvar:: PYTHON_LAZY_IMPORTS
14181417

1419-
Controls lazy import behavior. Accepts three values: ``all`` makes all
1420-
imports lazy by default, ``none`` disables lazy imports entirely (even
1421-
explicit ``lazy`` statements become eager), and ``normal`` (the default)
1422-
respects the ``lazy`` keyword in source code.
1418+
Controls lazy import behavior. Accepts two values: ``all`` makes all
1419+
imports lazy by default, and ``normal`` (the default) respects the
1420+
``lazy`` keyword in source code.
14231421

14241422
See also the :option:`-X lazy_imports <-X>` command-line option.
14251423

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,10 @@ making it straightforward to diagnose and debug the failure.
151151
For cases where you want to enable lazy loading globally without modifying
152152
source code, Python provides the :option:`-X lazy_imports <-X>` command-line
153153
option and the :envvar:`PYTHON_LAZY_IMPORTS` environment variable. Both
154-
accept three values: ``all`` makes all imports lazy by default, ``none``
155-
disables lazy imports entirely (even explicit ``lazy`` statements become
156-
eager), and ``normal`` (the default) respects the ``lazy`` keyword in source
157-
code. The :func:`sys.set_lazy_imports` and :func:`sys.get_lazy_imports`
158-
functions allow changing and querying this mode at runtime.
154+
accept two values: ``all`` makes all imports lazy by default, and ``normal``
155+
(the default) respects the ``lazy`` keyword in source code. The
156+
:func:`sys.set_lazy_imports` and :func:`sys.get_lazy_imports` functions allow
157+
changing and querying this mode at runtime.
159158

160159
For more selective control, :func:`sys.set_lazy_imports_filter` accepts a
161160
callable that determines whether a specific module should be loaded lazily.

Include/import.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ PyAPI_FUNC(int) PyImport_AppendInittab(
9090

9191
typedef enum {
9292
PyImport_LAZY_NORMAL,
93-
PyImport_LAZY_ALL,
94-
PyImport_LAZY_NONE
93+
PyImport_LAZY_ALL
9594
} PyImport_LazyImportsMode;
9695

9796
#ifndef Py_LIMITED_API

Lib/test/test_lazy_import/__init__.py

Lines changed: 24 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ def tearDown(self):
100100
sys.set_lazy_imports_filter(None)
101101
sys.set_lazy_imports("normal")
102102

103-
def test_global_off(self):
104-
"""Mode 'none' should disable lazy imports entirely."""
105-
import test.test_lazy_import.data.global_off
106-
self.assertIn("test.test_lazy_import.data.basic2", sys.modules)
103+
def test_global_off_rejected(self):
104+
"""Mode 'none' is not supported."""
105+
with self.assertRaises(ValueError):
106+
sys.set_lazy_imports("none")
107107

108108
def test_global_on(self):
109109
"""Mode 'all' should make regular imports lazy."""
@@ -468,9 +468,6 @@ def test_get_lazy_imports_returns_string(self):
468468
sys.set_lazy_imports("all")
469469
self.assertEqual(sys.get_lazy_imports(), "all")
470470

471-
sys.set_lazy_imports("none")
472-
self.assertEqual(sys.get_lazy_imports(), "none")
473-
474471
def test_get_lazy_imports_filter_default(self):
475472
"""get_lazy_imports_filter should return None by default."""
476473
sys.set_lazy_imports_filter(None)
@@ -1015,68 +1012,16 @@ def test_cli_lazy_imports_all_makes_regular_imports_lazy(self):
10151012
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
10161013
self.assertIn("LAZY", result.stdout)
10171014

1018-
def test_cli_lazy_imports_none_forces_all_imports_eager(self):
1019-
"""-X lazy_imports=none should force all imports to be eager."""
1020-
code = textwrap.dedent("""
1021-
import sys
1022-
# Even explicit lazy imports should be eager in 'none' mode
1023-
lazy import json
1024-
if 'json' in sys.modules:
1025-
print("EAGER")
1026-
else:
1027-
print("LAZY")
1028-
""")
1015+
def test_cli_lazy_imports_none_is_rejected(self):
1016+
"""-X lazy_imports=none should be rejected."""
10291017
result = subprocess.run(
1030-
[sys.executable, "-X", "lazy_imports=none", "-c", code],
1018+
[sys.executable, "-X", "lazy_imports=none", "-c", "pass"],
10311019
capture_output=True,
10321020
text=True
10331021
)
1034-
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
1035-
self.assertIn("EAGER", result.stdout)
1036-
1037-
@support.requires_resource("cpu")
1038-
def test_cli_lazy_imports_modes_import_stdlib_modules(self):
1039-
"""-X lazy_imports modes should import available stdlib modules."""
1040-
# Do not smoke-test modules with intentional import-time effects.
1041-
import_side_effect_modules = {"antigravity", "this"}
1042-
importable = []
1043-
1044-
for module in sorted(sys.stdlib_module_names):
1045-
if module in import_side_effect_modules:
1046-
continue
1047-
1048-
with self.subTest(module=module):
1049-
code = f"import {module}; print({module})"
1050-
baseline = subprocess.run(
1051-
[sys.executable, "-I", "-c", code],
1052-
capture_output=True,
1053-
text=True,
1054-
timeout=60,
1055-
)
1056-
if baseline.returncode:
1057-
# sys.stdlib_module_names includes modules for other
1058-
# platforms and optional extension modules not built here.
1059-
continue
1060-
importable.append(module)
1061-
1062-
for mode in ("normal", "none"):
1063-
with self.subTest(module=module, mode=mode):
1064-
result = subprocess.run(
1065-
[
1066-
sys.executable,
1067-
"-I",
1068-
"-X",
1069-
f"lazy_imports={mode}",
1070-
"-c",
1071-
code,
1072-
],
1073-
capture_output=True,
1074-
text=True,
1075-
timeout=60,
1076-
)
1077-
self.assertEqual(result.returncode, 0, result.stderr)
1078-
1079-
self.assertGreater(len(importable), 100)
1022+
self.assertNotEqual(result.returncode, 0)
1023+
self.assertIn("-X lazy_imports: invalid value", result.stderr)
1024+
self.assertIn("expected 'all' or 'normal'", result.stderr)
10801025

10811026
def test_cli_lazy_imports_normal_respects_lazy_keyword_only(self):
10821027
"""-X lazy_imports=normal should respect lazy keyword only."""
@@ -1125,101 +1070,51 @@ def test_env_var_lazy_imports_all_enables_global_lazy(self):
11251070
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
11261071
self.assertIn("LAZY", result.stdout)
11271072

1128-
def test_env_var_lazy_imports_none_disables_all_lazy(self):
1129-
"""PYTHON_LAZY_IMPORTS=none should disable all lazy imports."""
1130-
code = textwrap.dedent("""
1131-
import sys
1132-
lazy import json
1133-
if 'json' in sys.modules:
1134-
print("EAGER")
1135-
else:
1136-
print("LAZY")
1137-
""")
1073+
def test_env_var_lazy_imports_none_is_rejected(self):
1074+
"""PYTHON_LAZY_IMPORTS=none should be rejected."""
11381075
import os
11391076
env = os.environ.copy()
11401077
env["PYTHON_LAZY_IMPORTS"] = "none"
11411078
result = subprocess.run(
1142-
[sys.executable, "-c", code],
1079+
[sys.executable, "-c", "pass"],
11431080
capture_output=True,
11441081
text=True,
11451082
env=env
11461083
)
1147-
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
1148-
self.assertIn("EAGER", result.stdout)
1149-
1150-
def test_cli_lazy_imports_none_disables_dunder_lazy_modules(self):
1151-
"""-X lazy_imports=none should override __lazy_modules__."""
1152-
code = textwrap.dedent("""
1153-
import sys
1154-
__lazy_modules__ = ["json"]
1155-
import json
1156-
if 'json' in sys.modules:
1157-
print("EAGER")
1158-
else:
1159-
print("LAZY")
1160-
""")
1161-
result = subprocess.run(
1162-
[sys.executable, "-X", "lazy_imports=none", "-c", code],
1163-
capture_output=True,
1164-
text=True,
1165-
)
1166-
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
1167-
self.assertIn("EAGER", result.stdout)
1168-
1169-
def test_env_var_lazy_imports_none_disables_dunder_lazy_modules(self):
1170-
"""PYTHON_LAZY_IMPORTS=none should override __lazy_modules__."""
1171-
code = textwrap.dedent("""
1172-
import sys
1173-
__lazy_modules__ = ["json"]
1174-
import json
1175-
if 'json' in sys.modules:
1176-
print("EAGER")
1177-
else:
1178-
print("LAZY")
1179-
""")
1180-
import os
1181-
1182-
env = os.environ.copy()
1183-
env["PYTHON_LAZY_IMPORTS"] = "none"
1184-
result = subprocess.run(
1185-
[sys.executable, "-c", code],
1186-
capture_output=True,
1187-
text=True,
1188-
env=env,
1189-
)
1190-
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
1191-
self.assertIn("EAGER", result.stdout)
1084+
self.assertNotEqual(result.returncode, 0)
1085+
self.assertIn("PYTHON_LAZY_IMPORTS: invalid value", result.stderr)
1086+
self.assertIn("expected 'all' or 'normal'", result.stderr)
11921087

11931088
def test_cli_overrides_env_var(self):
11941089
"""Command-line option should take precedence over environment variable."""
11951090
# PEP 810: -X lazy_imports takes precedence over PYTHON_LAZY_IMPORTS
11961091
code = textwrap.dedent("""
11971092
import sys
1198-
lazy import json
1093+
import json
11991094
if 'json' in sys.modules:
12001095
print("EAGER")
12011096
else:
12021097
print("LAZY")
12031098
""")
12041099
import os
12051100
env = os.environ.copy()
1206-
env["PYTHON_LAZY_IMPORTS"] = "all" # env says all
1101+
env["PYTHON_LAZY_IMPORTS"] = "all" # env says all imports are lazy
12071102
result = subprocess.run(
1208-
[sys.executable, "-X", "lazy_imports=none", "-c", code], # CLI says none
1103+
[sys.executable, "-X", "lazy_imports=normal", "-c", code],
12091104
capture_output=True,
12101105
text=True,
12111106
env=env
12121107
)
12131108
self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}")
1214-
# CLI should win - imports should be eager
1109+
# CLI should win, so a regular import should stay eager.
12151110
self.assertIn("EAGER", result.stdout)
12161111

12171112
def test_sys_set_lazy_imports_overrides_cli(self):
12181113
"""sys.set_lazy_imports() should take precedence over CLI option."""
12191114
code = textwrap.dedent("""
12201115
import sys
1221-
sys.set_lazy_imports("none") # Override CLI
1222-
lazy import json
1116+
sys.set_lazy_imports("normal") # Override CLI
1117+
import json
12231118
if 'json' in sys.modules:
12241119
print("EAGER")
12251120
else:
@@ -2001,9 +1896,10 @@ def tearDown(self):
20011896

20021897
def test_set_matches_sys(self):
20031898
self.assertEqual(_testcapi.PyImport_GetLazyImportsMode(), sys.get_lazy_imports())
2004-
for mode in ("normal", "all", "none"):
1899+
for mode in ("normal", "all"):
20051900
_testcapi.PyImport_SetLazyImportsMode(mode)
20061901
self.assertEqual(_testcapi.PyImport_GetLazyImportsMode(), sys.get_lazy_imports())
1902+
self.assertRaises(ValueError, _testcapi.PyImport_SetLazyImportsMode, "none")
20071903

20081904
def test_filter_matches_sys(self):
20091905
self.assertEqual(_testcapi.PyImport_GetLazyImportsFilter(), sys.get_lazy_imports_filter())

Lib/test/test_lazy_import/data/global_off.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

Misc/NEWS.d/3.15.0a8.rst

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,6 @@ dealing with contradictions in ``make_bottom``.
180180

181181
..
182182
183-
.. date: 2026-03-24-13-06-52
184-
.. gh-issue: 146369
185-
.. nonce: 6wDI6S
186-
.. section: Core and Builtins
187-
188-
Ensure ``-X lazy_imports=none`` and ``PYTHON_LAZY_IMPORTS=none`` override
189-
:attr:`~module.__lazy_modules__`. Patch by Hugo van Kemenade.
190-
191-
..
192-
193183
.. date: 2026-03-22-19-30-00
194184
.. gh-issue: 146308
195185
.. nonce: AxnRVA
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Do not support ``none`` as a lazy imports mode.

0 commit comments

Comments
 (0)