Update sys module to conform with the PEP, add matching C API

This commit is contained in:
Dino Viehland 2025-10-09 13:27:14 -07:00
parent fe526b4e54
commit 06b9110569
18 changed files with 260 additions and 177 deletions

View file

@ -333,3 +333,40 @@ Importing Modules
strings instead of Python :class:`str` objects. strings instead of Python :class:`str` objects.
.. versionadded:: 3.14 .. versionadded:: 3.14
.. c:function:: PyImport_LazyImportsMode PyImport_GetLazyImportsMode()
Gets the current lazy imports mode.
.. versionadded:: 3.15
.. c:function:: PyObject* PyImport_GetLazyImportsFilter()
Gets the current lazy imports filter. Returns a new reference.
.. versionadded:: 3.15
.. c:function:: PyObject* PyImport_SetLazyImportsMode(PyImport_LazyImportsMode mode)
Similar to :c:func:`PyImport_ImportModuleAttr`, but names are UTF-8 encoded
strings instead of Python :class:`str` objects.
.. versionadded:: 3.15
.. c:function:: PyObject* PyImport_SetLazyImportsFilter(PyObject *filter)
Sets the current lazy imports filter. The function should be a callable that
will receive (importing_module_name, imported_module_name, [fromlist]) when
an import can potentially be lazy. Returns True if the import should be lazy
or False otherwise.
.. versionadded:: 3.15
.. c:type:: PyImport_LazyImportsMode
Enumeration of possible lazy import modes:
- ``PyImport_LAZY_NORMAL``
- ``PyImport_LAZY_ALL``
- ``PyImport_LAZY_NONE``
.. versionadded:: 3.12

View file

@ -89,14 +89,16 @@ PyAPI_FUNC(int) PyImport_AppendInittab(
); );
typedef enum { typedef enum {
PyLazyImportsMode_Default, PyImport_LAZY_NORMAL,
PyLazyImportsMode_ForcedOff, PyImport_LAZY_ALL,
PyLazyImportsMode_ForcedOn, PyImport_LAZY_NONE,
} PyImport_LazyImportsMode; } PyImport_LazyImportsMode;
PyAPI_FUNC(int) PyImport_SetLazyImports(PyImport_LazyImportsMode mode, PyObject *filter); PyAPI_FUNC(int) PyImport_SetLazyImportsMode(PyImport_LazyImportsMode mode);
PyAPI_FUNC(int) PyImport_SetLazyImportsFilter(PyObject *filter);
PyAPI_FUNC(PyImport_LazyImportsMode) PyImport_LazyImportsEnabled(void); PyAPI_FUNC(PyImport_LazyImportsMode) PyImport_GetLazyImportsMode(void);
PyAPI_FUNC(PyObject *) PyImport_GetLazyImportsFilter(void);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
# define Py_CPYTHON_IMPORT_H # define Py_CPYTHON_IMPORT_H

View file

@ -1704,6 +1704,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(effective_ids)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(effective_ids));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(element_factory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(element_factory));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(emptyerror)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(emptyerror));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(enabled));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encode));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encoding)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encoding));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end));

View file

@ -427,6 +427,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(effective_ids) STRUCT_FOR_ID(effective_ids)
STRUCT_FOR_ID(element_factory) STRUCT_FOR_ID(element_factory)
STRUCT_FOR_ID(emptyerror) STRUCT_FOR_ID(emptyerror)
STRUCT_FOR_ID(enabled)
STRUCT_FOR_ID(encode) STRUCT_FOR_ID(encode)
STRUCT_FOR_ID(encoding) STRUCT_FOR_ID(encoding)
STRUCT_FOR_ID(end) STRUCT_FOR_ID(end)

View file

@ -1702,6 +1702,7 @@ extern "C" {
INIT_ID(effective_ids), \ INIT_ID(effective_ids), \
INIT_ID(element_factory), \ INIT_ID(element_factory), \
INIT_ID(emptyerror), \ INIT_ID(emptyerror), \
INIT_ID(enabled), \
INIT_ID(encode), \ INIT_ID(encode), \
INIT_ID(encoding), \ INIT_ID(encoding), \
INIT_ID(end), \ INIT_ID(end), \

View file

@ -1496,6 +1496,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(enabled);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(encode); string = &_Py_ID(encode);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));

View file

@ -59,8 +59,6 @@
from ._bootstrap import __import__ from ._bootstrap import __import__
from _imp import set_lazy_imports
def invalidate_caches(): def invalidate_caches():
"""Call the invalidate_caches() method on all meta path finders stored in """Call the invalidate_caches() method on all meta path finders stored in

View file

@ -2548,7 +2548,8 @@ def tearDown(self):
if key.startswith('test.test_import.data.lazy_imports'): if key.startswith('test.test_import.data.lazy_imports'):
del sys.modules[key] del sys.modules[key]
importlib.set_lazy_imports(None, None) sys.set_lazy_imports_filter(None)
sys.set_lazy_imports(None)
def test_basic_unused(self): def test_basic_unused(self):
try: try:
@ -2738,7 +2739,7 @@ def test_lazy_try_except_from_star(self):
import test.test_import.data.lazy_imports.lazy_try_except_from_star import test.test_import.data.lazy_imports.lazy_try_except_from_star
def test_try_except_eager(self): def test_try_except_eager(self):
importlib.set_lazy_imports(True) sys.set_lazy_imports(True)
try: try:
import test.test_import.data.lazy_imports.try_except_eager import test.test_import.data.lazy_imports.try_except_eager
except ImportError as e: except ImportError as e:
@ -2747,7 +2748,7 @@ def test_try_except_eager(self):
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules) self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
def test_try_except_eager_from(self): def test_try_except_eager_from(self):
importlib.set_lazy_imports(True) sys.set_lazy_imports(True)
try: try:
import test.test_import.data.lazy_imports.try_except_eager_from import test.test_import.data.lazy_imports.try_except_eager_from
except ImportError as e: except ImportError as e:
@ -2759,8 +2760,8 @@ def test_lazy_import_func(self):
with self.assertRaises(SyntaxError): with self.assertRaises(SyntaxError):
import test.test_import.data.lazy_imports.lazy_import_func import test.test_import.data.lazy_imports.lazy_import_func
def test_eager_import_func(self): def test_eager_import_func(self):
importlib.set_lazy_imports(True) sys.set_lazy_imports(True)
try: try:
import test.test_import.data.lazy_imports.eager_import_func import test.test_import.data.lazy_imports.eager_import_func
except ImportError as e: except ImportError as e:

View file

@ -1,10 +1,10 @@
import importlib import sys
def filter(module_name, imported_name, from_list): def filter(module_name, imported_name, from_list):
assert module_name == __name__ assert module_name == __name__
assert imported_name == "test.test_import.data.lazy_imports.basic2" assert imported_name == "test.test_import.data.lazy_imports.basic2"
return False return False
importlib.set_lazy_imports(None, filter) sys.set_lazy_imports_filter(filter)
lazy import test.test_import.data.lazy_imports.basic2 as basic2 lazy import test.test_import.data.lazy_imports.basic2 as basic2

View file

@ -1,10 +1,11 @@
import importlib import sys
def filter(module_name, imported_name, from_list): def filter(module_name, imported_name, from_list):
assert module_name == __name__ assert module_name == __name__
assert imported_name == "test.test_import.data.lazy_imports.basic2" assert imported_name == "test.test_import.data.lazy_imports.basic2"
return True return True
importlib.set_lazy_imports(None, filter) sys.set_lazy_imports(None)
sys.set_lazy_imports_filter(filter)
lazy import test.test_import.data.lazy_imports.basic2 as basic2 lazy import test.test_import.data.lazy_imports.basic2 as basic2

View file

@ -1,5 +1,5 @@
import importlib import sys
importlib.set_lazy_imports(False) sys.set_lazy_imports(False)
lazy import test.test_import.data.lazy_imports.basic2 as basic2 lazy import test.test_import.data.lazy_imports.basic2 as basic2

View file

@ -1,5 +1,5 @@
import importlib import sys
importlib.set_lazy_imports(True) sys.set_lazy_imports(True)
import test.test_import.data.lazy_imports.basic2 as basic2 import test.test_import.data.lazy_imports.basic2 as basic2

View file

@ -3072,14 +3072,14 @@ _PyEval_LazyImportName(PyThreadState *tstate, PyObject *builtins, PyObject *glob
{ {
PyObject *res = NULL; PyObject *res = NULL;
// Check if global policy overrides the local syntax // Check if global policy overrides the local syntax
switch (PyImport_LazyImportsEnabled()) { switch (PyImport_GetLazyImportsMode()) {
case PyLazyImportsMode_ForcedOff: case PyImport_LAZY_NONE:
lazy = 0; lazy = 0;
break; break;
case PyLazyImportsMode_ForcedOn: case PyImport_LAZY_ALL:
lazy = 1; lazy = 1;
break; break;
case PyLazyImportsMode_Default: case PyImport_LAZY_NORMAL:
break; break;
} }

View file

@ -622,88 +622,6 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(_imp_set_lazy_imports__doc__,
"set_lazy_imports($module, enabled=None, /, filter=<unrepresentable>)\n"
"--\n"
"\n"
"Programmatic API for enabling lazy imports at runtime.\n"
"\n"
"enabled can be:\n"
" None (lazy imports always respect keyword)\n"
" False (forced lazy imports off)\n"
" True (forced lazy imports on)\n"
"\n"
"filter is an optional callable which further disables lazy imports when they\n"
"would otherwise be enabled. Returns True if the the import is still enabled\n"
"or False to disable it. The callable is called with:\n"
"\n"
"(importing_module_name, imported_module_name, [fromlist])");
#define _IMP_SET_LAZY_IMPORTS_METHODDEF \
{"set_lazy_imports", _PyCFunction_CAST(_imp_set_lazy_imports), METH_FASTCALL|METH_KEYWORDS, _imp_set_lazy_imports__doc__},
static PyObject *
_imp_set_lazy_imports_impl(PyObject *module, PyObject *enabled,
PyObject *filter);
static PyObject *
_imp_set_lazy_imports(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
Py_hash_t ob_hash;
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(filter), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "filter", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_lazy_imports",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
PyObject *enabled = Py_None;
PyObject *filter = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
if (nargs < 1) {
goto skip_optional_posonly;
}
noptargs--;
enabled = args[0];
skip_optional_posonly:
if (!noptargs) {
goto skip_optional_pos;
}
filter = args[1];
skip_optional_pos:
return_value = _imp_set_lazy_imports_impl(module, enabled, filter);
exit:
return return_value;
}
PyDoc_STRVAR(_imp__set_lazy_attributes__doc__, PyDoc_STRVAR(_imp__set_lazy_attributes__doc__,
"_set_lazy_attributes($module, child_module, name, /)\n" "_set_lazy_attributes($module, child_module, name, /)\n"
"--\n" "--\n"
@ -746,4 +664,4 @@ exit:
#ifndef _IMP_EXEC_DYNAMIC_METHODDEF #ifndef _IMP_EXEC_DYNAMIC_METHODDEF
#define _IMP_EXEC_DYNAMIC_METHODDEF #define _IMP_EXEC_DYNAMIC_METHODDEF
#endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */ #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */
/*[clinic end generated code: output=0b2b116cf3e431ca input=a9049054013a1b77]*/ /*[clinic end generated code: output=0fe31ade5e29e8d6 input=a9049054013a1b77]*/

View file

@ -1907,6 +1907,93 @@ sys_get_lazy_imports_filter(PyObject *module, PyObject *Py_UNUSED(ignored))
return sys_get_lazy_imports_filter_impl(module); return sys_get_lazy_imports_filter_impl(module);
} }
PyDoc_STRVAR(sys_set_lazy_imports__doc__,
"set_lazy_imports($module, /, enabled)\n"
"--\n"
"\n"
"Sets the global lazy imports flag.\n"
"\n"
"True sets all imports at the top level as potentially lazy.\n"
"False disables lazy imports for any explicitly marked imports.\n"
"None causes only explicitly marked imports as lazy.\n"
"\n"
"In addition to the mode lazy imports can be controlled via the filter\n"
"provided to sys.set_lazy_imports_filter");
#define SYS_SET_LAZY_IMPORTS_METHODDEF \
{"set_lazy_imports", _PyCFunction_CAST(sys_set_lazy_imports), METH_FASTCALL|METH_KEYWORDS, sys_set_lazy_imports__doc__},
static PyObject *
sys_set_lazy_imports_impl(PyObject *module, PyObject *enabled);
static PyObject *
sys_set_lazy_imports(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
Py_hash_t ob_hash;
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(enabled), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"enabled", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "set_lazy_imports",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[1];
PyObject *enabled;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
enabled = args[0];
return_value = sys_set_lazy_imports_impl(module, enabled);
exit:
return return_value;
}
PyDoc_STRVAR(sys_get_lazy_imports__doc__,
"get_lazy_imports($module, /)\n"
"--\n"
"\n"
"Gets the global lazy imports flag.\n"
"\n"
"Returns True if all top level imports are potentially lazy.\n"
"Returns False if all explicilty marked lazy imports are suppressed.\n"
"Returns None if only explicitly marked imports are lazy.");
#define SYS_GET_LAZY_IMPORTS_METHODDEF \
{"get_lazy_imports", (PyCFunction)sys_get_lazy_imports, METH_NOARGS, sys_get_lazy_imports__doc__},
static PyObject *
sys_get_lazy_imports_impl(PyObject *module);
static PyObject *
sys_get_lazy_imports(PyObject *module, PyObject *Py_UNUSED(ignored))
{
return sys_get_lazy_imports_impl(module);
}
PyDoc_STRVAR(_jit_is_available__doc__, PyDoc_STRVAR(_jit_is_available__doc__,
"is_available($module, /)\n" "is_available($module, /)\n"
"--\n" "--\n"
@ -2034,4 +2121,4 @@ exit:
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
#define SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
/*[clinic end generated code: output=64c56362026c8fcf input=a9049054013a1b77]*/ /*[clinic end generated code: output=dd304e713c0d089f input=a9049054013a1b77]*/

View file

@ -15,6 +15,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_moduleobject.h" // _PyModule_GetDef()
#include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_namespace.h" // _PyNamespace_Type
#include "pycore_object.h" // _Py_SetImmortal() #include "pycore_object.h" // _Py_SetImmortal()
#include "pycore_pyatomic_ft_wrappers.h"
#include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pyerrors.h" // _PyErr_SetString()
#include "pycore_pyhash.h" // _Py_KeyedHash() #include "pycore_pyhash.h" // _Py_KeyedHash()
#include "pycore_pylifecycle.h" #include "pycore_pylifecycle.h"
@ -4228,7 +4229,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate,
assert(_PyEval_GetFrame()->f_globals == _PyEval_GetFrame()->f_locals); // should only be called in global scope assert(_PyEval_GetFrame()->f_globals == _PyEval_GetFrame()->f_locals); // should only be called in global scope
// Check if the filter disables the lazy import // Check if the filter disables the lazy import
PyObject *filter = LAZY_IMPORTS_FILTER(interp); PyObject *filter = FT_ATOMIC_LOAD_PTR_RELAXED(LAZY_IMPORTS_FILTER(interp));
if (filter != NULL) { if (filter != NULL) {
PyObject *modname; PyObject *modname;
if (PyDict_GetItemRef(globals, &_Py_ID(__name__), &modname) < 0) { if (PyDict_GetItemRef(globals, &_Py_ID(__name__), &modname) < 0) {
@ -4608,9 +4609,8 @@ PyImport_ImportModuleAttrString(const char *modname, const char *attrname)
return result; return result;
} }
int int
PyImport_SetLazyImports(PyImport_LazyImportsMode mode, PyObject *filter) PyImport_SetLazyImportsFilter(PyObject *filter)
{ {
if (filter == Py_None) { if (filter == Py_None) {
filter = NULL; filter = NULL;
@ -4621,17 +4621,39 @@ PyImport_SetLazyImports(PyImport_LazyImportsMode mode, PyObject *filter)
} }
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
LAZY_IMPORTS_MODE(interp) = mode; #ifdef Py_GIL_DISABLED
// exchange just in case another thread did same thing at same time
PyObject *old = _Py_atomic_exchange_ptr(&LAZY_IMPORTS_FILTER(interp), Py_XNewRef(filter));
Py_XDECREF(old);
#else
Py_XSETREF(LAZY_IMPORTS_FILTER(interp), Py_XNewRef(filter)); Py_XSETREF(LAZY_IMPORTS_FILTER(interp), Py_XNewRef(filter));
#endif
return 0;
}
/* Gets the lazy imports filter. Returns a new reference. */
PyObject *
PyImport_GetLazyImportsFilter()
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return Py_XNewRef(FT_ATOMIC_LOAD_PTR_RELAXED(LAZY_IMPORTS_FILTER(interp)));
}
int
PyImport_SetLazyImportsMode(PyImport_LazyImportsMode mode)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
FT_ATOMIC_STORE_INT_RELAXED(LAZY_IMPORTS_MODE(interp), mode);
return 0; return 0;
} }
/* Checks if lazy imports is globally enabled or disabled. Return 1 when globally /* Checks if lazy imports is globally enabled or disabled. Return 1 when globally
* forced on, 0 when globally forced off, or -1 when */ * forced on, 0 when globally forced off, or -1 when */
PyImport_LazyImportsMode PyImport_LazyImportsEnabled(void) PyImport_LazyImportsMode
PyImport_GetLazyImportsMode()
{ {
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
return LAZY_IMPORTS_MODE(interp); return FT_ATOMIC_LOAD_INT_RELAXED(LAZY_IMPORTS_MODE(interp));
} }
/**************/ /**************/
@ -5223,51 +5245,6 @@ _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source)
return PyBytes_FromStringAndSize(hash.data, sizeof(hash.data)); return PyBytes_FromStringAndSize(hash.data, sizeof(hash.data));
} }
/*[clinic input]
_imp.set_lazy_imports
enabled: object = None
/
filter: object = NULL
Programmatic API for enabling lazy imports at runtime.
enabled can be:
None (lazy imports always respect keyword)
False (forced lazy imports off)
True (forced lazy imports on)
filter is an optional callable which further disables lazy imports when they
would otherwise be enabled. Returns True if the the import is still enabled
or False to disable it. The callable is called with:
(importing_module_name, imported_module_name, [fromlist])
[clinic start generated code]*/
static PyObject *
_imp_set_lazy_imports_impl(PyObject *module, PyObject *enabled,
PyObject *filter)
/*[clinic end generated code: output=d8d5a848c041edc5 input=00b2334fae4345a3]*/
{
PyImport_LazyImportsMode mode;
if (enabled == Py_None) {
mode = PyLazyImportsMode_Default;
} else if (enabled == Py_False) {
mode = PyLazyImportsMode_ForcedOff;
} else if (enabled == Py_True) {
mode = PyLazyImportsMode_ForcedOn;
} else {
PyErr_SetString(PyExc_ValueError, "expected None, True or False for enabled mode");
return NULL;
}
if (PyImport_SetLazyImports(mode, filter) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
/*[clinic input] /*[clinic input]
_imp._set_lazy_attributes _imp._set_lazy_attributes
child_module: object child_module: object
@ -5352,7 +5329,6 @@ static PyMethodDef imp_methods[] = {
_IMP_EXEC_BUILTIN_METHODDEF _IMP_EXEC_BUILTIN_METHODDEF
_IMP__FIX_CO_FILENAME_METHODDEF _IMP__FIX_CO_FILENAME_METHODDEF
_IMP_SOURCE_HASH_METHODDEF _IMP_SOURCE_HASH_METHODDEF
_IMP_SET_LAZY_IMPORTS_METHODDEF
_IMP__SET_LAZY_ATTRIBUTES_METHODDEF _IMP__SET_LAZY_ATTRIBUTES_METHODDEF
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };

View file

@ -1321,11 +1321,11 @@ init_interp_main(PyThreadState *tstate)
if (config->lazy_imports != -1) { if (config->lazy_imports != -1) {
PyImport_LazyImportsMode lazy_mode; PyImport_LazyImportsMode lazy_mode;
if (config->lazy_imports == 1) { if (config->lazy_imports == 1) {
lazy_mode = PyLazyImportsMode_ForcedOn; lazy_mode = PyImport_LAZY_ALL;
} else { } else {
lazy_mode = PyLazyImportsMode_ForcedOff; lazy_mode = PyImport_LAZY_NONE;
} }
if (PyImport_SetLazyImports(lazy_mode, NULL) < 0) { if (PyImport_SetLazyImportsMode(lazy_mode) < 0) {
return _PyStatus_ERR("failed to set lazy imports mode"); return _PyStatus_ERR("failed to set lazy imports mode");
} }
} }

View file

@ -2792,20 +2792,10 @@ static PyObject *
sys_set_lazy_imports_filter_impl(PyObject *module, PyObject *filter) sys_set_lazy_imports_filter_impl(PyObject *module, PyObject *filter)
/*[clinic end generated code: output=10251d49469c278c input=2eb48786bdd4ee42]*/ /*[clinic end generated code: output=10251d49469c278c input=2eb48786bdd4ee42]*/
{ {
PyObject *current_filter = NULL; if (PyImport_SetLazyImportsFilter(filter) < 0) {
if (filter == Py_None) {
current_filter = NULL;
}
else if (!PyCallable_Check(filter)) {
PyErr_SetString(PyExc_TypeError, "filter must be callable or None");
return NULL; return NULL;
} }
else {
current_filter = filter;
}
PyInterpreterState *interp = _PyInterpreterState_GET();
Py_XSETREF(interp->imports.lazy_imports_filter, Py_XNewRef(current_filter));
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -2821,14 +2811,78 @@ static PyObject *
sys_get_lazy_imports_filter_impl(PyObject *module) sys_get_lazy_imports_filter_impl(PyObject *module)
/*[clinic end generated code: output=3bf73022892165af input=cf1e07cb8e203c94]*/ /*[clinic end generated code: output=3bf73022892165af input=cf1e07cb8e203c94]*/
{ {
PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *filter = PyImport_GetLazyImportsFilter();
PyObject *filter = interp->imports.lazy_imports_filter;
if (filter == NULL) { if (filter == NULL) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
return Py_NewRef(filter); return filter;
} }
/*[clinic input]
sys.set_lazy_imports
enabled: object
Sets the global lazy imports flag.
True sets all imports at the top level as potentially lazy.
False disables lazy imports for any explicitly marked imports.
None causes only explicitly marked imports as lazy.
In addition to the mode lazy imports can be controlled via the filter
provided to sys.set_lazy_imports_filter
[clinic start generated code]*/
static PyObject *
sys_set_lazy_imports_impl(PyObject *module, PyObject *enabled)
/*[clinic end generated code: output=d601640d3e2d70fb input=d351054b5884eae5]*/
{
PyImport_LazyImportsMode mode;
if (enabled == Py_None) {
mode = PyImport_LAZY_NORMAL;
} else if (enabled == Py_False) {
mode = PyImport_LAZY_NONE;
} else if (enabled == Py_True) {
mode = PyImport_LAZY_ALL;
} else {
PyErr_SetString(PyExc_ValueError, "expected None, True or False for enabled mode");
return NULL;
}
if (PyImport_SetLazyImportsMode(mode)) {
return NULL;
}
Py_RETURN_NONE;
}
/*[clinic input]
sys.get_lazy_imports
Gets the global lazy imports flag.
Returns True if all top level imports are potentially lazy.
Returns False if all explicilty marked lazy imports are suppressed.
Returns None if only explicitly marked imports are lazy.
[clinic start generated code]*/
static PyObject *
sys_get_lazy_imports_impl(PyObject *module)
/*[clinic end generated code: output=4147dec48c51ae99 input=d7b25d814165c8ce]*/
{
switch (PyImport_GetLazyImportsMode()) {
case PyImport_LAZY_NORMAL:
Py_RETURN_NONE;
case PyImport_LAZY_ALL:
Py_RETURN_TRUE;
case PyImport_LAZY_NONE:
Py_RETURN_FALSE;
default:
PyErr_SetString(PyExc_RuntimeError, "unknown lazy imports mode");
return NULL;
}
}
static PyMethodDef sys_methods[] = { static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */ /* Might as well keep this in alphabetic order */
@ -2894,6 +2948,8 @@ static PyMethodDef sys_methods[] = {
SYS_UNRAISABLEHOOK_METHODDEF SYS_UNRAISABLEHOOK_METHODDEF
SYS_GET_INT_MAX_STR_DIGITS_METHODDEF SYS_GET_INT_MAX_STR_DIGITS_METHODDEF
SYS_SET_INT_MAX_STR_DIGITS_METHODDEF SYS_SET_INT_MAX_STR_DIGITS_METHODDEF
SYS_GET_LAZY_IMPORTS_METHODDEF
SYS_SET_LAZY_IMPORTS_METHODDEF
SYS_GET_LAZY_IMPORTS_FILTER_METHODDEF SYS_GET_LAZY_IMPORTS_FILTER_METHODDEF
SYS_SET_LAZY_IMPORTS_FILTER_METHODDEF SYS_SET_LAZY_IMPORTS_FILTER_METHODDEF
SYS__BASEREPL_METHODDEF SYS__BASEREPL_METHODDEF