2025-09-16 15:10:28 -07:00
|
|
|
/* Lazy object implementation */
|
|
|
|
|
|
|
|
|
|
#include "Python.h"
|
|
|
|
|
#include "pycore_lazyimportobject.h"
|
|
|
|
|
|
|
|
|
|
PyObject *
|
2025-09-22 07:42:54 -07:00
|
|
|
_PyLazyImport_New(PyObject *import_func, PyObject *from, PyObject *attr)
|
2025-09-16 15:10:28 -07:00
|
|
|
{
|
|
|
|
|
PyLazyImportObject *m;
|
|
|
|
|
if (!from || !PyUnicode_Check(from)) {
|
|
|
|
|
PyErr_BadArgument();
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (attr == Py_None) {
|
|
|
|
|
attr = NULL;
|
|
|
|
|
}
|
|
|
|
|
assert(!attr || PyObject_IsTrue(attr));
|
|
|
|
|
m = PyObject_GC_New(PyLazyImportObject, &PyLazyImport_Type);
|
|
|
|
|
if (m == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2025-09-22 07:42:54 -07:00
|
|
|
Py_XINCREF(import_func);
|
|
|
|
|
m->lz_import_func = import_func;
|
2025-09-16 15:10:28 -07:00
|
|
|
Py_INCREF(from);
|
|
|
|
|
m->lz_from = from;
|
|
|
|
|
Py_XINCREF(attr);
|
|
|
|
|
m->lz_attr = attr;
|
|
|
|
|
PyObject_GC_Track(m);
|
|
|
|
|
return (PyObject *)m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lazy_import_dealloc(PyLazyImportObject *m)
|
|
|
|
|
{
|
|
|
|
|
PyObject_GC_UnTrack(m);
|
2025-09-22 07:42:54 -07:00
|
|
|
Py_XDECREF(m->lz_import_func);
|
2025-09-16 15:10:28 -07:00
|
|
|
Py_XDECREF(m->lz_from);
|
|
|
|
|
Py_XDECREF(m->lz_attr);
|
|
|
|
|
Py_TYPE(m)->tp_free((PyObject *)m);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
lazy_import_name(PyLazyImportObject *m)
|
|
|
|
|
{
|
|
|
|
|
if (m->lz_attr != NULL) {
|
|
|
|
|
if (PyUnicode_Check(m->lz_attr)) {
|
|
|
|
|
return PyUnicode_FromFormat("%U.%U", m->lz_from, m->lz_attr);
|
|
|
|
|
} else {
|
|
|
|
|
return PyUnicode_FromFormat("%U...", m->lz_from);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Py_INCREF(m->lz_from);
|
|
|
|
|
return m->lz_from;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
lazy_import_repr(PyLazyImportObject *m)
|
|
|
|
|
{
|
|
|
|
|
PyObject *name = lazy_import_name(m);
|
|
|
|
|
if (name == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
PyObject *res = PyUnicode_FromFormat("<lazy_import '%U'>", name);
|
|
|
|
|
Py_DECREF(name);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
lazy_import_traverse(PyLazyImportObject *m, visitproc visit, void *arg)
|
|
|
|
|
{
|
2025-09-22 07:42:54 -07:00
|
|
|
Py_VISIT(m->lz_import_func);
|
2025-09-16 15:10:28 -07:00
|
|
|
Py_VISIT(m->lz_from);
|
|
|
|
|
Py_VISIT(m->lz_attr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
lazy_import_clear(PyLazyImportObject *m)
|
|
|
|
|
{
|
2025-09-22 07:42:54 -07:00
|
|
|
Py_CLEAR(m->lz_import_func);
|
2025-09-16 15:10:28 -07:00
|
|
|
Py_CLEAR(m->lz_from);
|
|
|
|
|
Py_CLEAR(m->lz_attr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-18 14:54:37 -07:00
|
|
|
static PyObject *
|
|
|
|
|
lazy_import_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
|
|
{
|
|
|
|
|
if (PyTuple_GET_SIZE(args) != 2 && PyTuple_GET_SIZE(args) != 3) {
|
|
|
|
|
PyErr_SetString(PyExc_ValueError, "lazy_import expected 2-3 arguments");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject *builtins = PyTuple_GET_ITEM(args, 0);
|
|
|
|
|
PyObject *from = PyTuple_GET_ITEM(args, 1);
|
|
|
|
|
PyObject *attr = NULL;
|
|
|
|
|
if (PyTuple_GET_SIZE(args) == 3) {
|
|
|
|
|
attr = PyTuple_GET_ITEM(args, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _PyLazyImport_New(builtins, from, attr);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 15:10:28 -07:00
|
|
|
PyObject *
|
|
|
|
|
_PyLazyImport_GetName(PyObject *lazy_import)
|
|
|
|
|
{
|
|
|
|
|
assert(PyLazyImport_CheckExact(lazy_import));
|
|
|
|
|
return lazy_import_name((PyLazyImportObject *)lazy_import);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyTypeObject PyLazyImport_Type = {
|
|
|
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
|
|
|
"lazy_import", /* tp_name */
|
|
|
|
|
sizeof(PyLazyImportObject), /* tp_basicsize */
|
|
|
|
|
0, /* tp_itemsize */
|
|
|
|
|
(destructor)lazy_import_dealloc, /* tp_dealloc */
|
|
|
|
|
0, /* tp_print */
|
|
|
|
|
0, /* tp_getattr */
|
|
|
|
|
0, /* tp_setattr */
|
|
|
|
|
0, /* tp_reserved */
|
|
|
|
|
(reprfunc)lazy_import_repr, /* tp_repr */
|
|
|
|
|
0, /* tp_as_number */
|
|
|
|
|
0, /* tp_as_sequence */
|
|
|
|
|
0, /* tp_as_mapping */
|
|
|
|
|
0, /* tp_hash */
|
|
|
|
|
0, /* tp_call */
|
|
|
|
|
0, /* tp_str */
|
|
|
|
|
0, /* tp_getattro */
|
|
|
|
|
0, /* tp_setattro */
|
|
|
|
|
0, /* tp_as_buffer */
|
|
|
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
|
|
|
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
|
|
|
0, /* tp_doc */
|
|
|
|
|
(traverseproc)lazy_import_traverse, /* tp_traverse */
|
|
|
|
|
(inquiry)lazy_import_clear, /* tp_clear */
|
|
|
|
|
0, /* tp_richcompare */
|
|
|
|
|
0, /* tp_weaklistoffset */
|
|
|
|
|
0, /* tp_iter */
|
|
|
|
|
0, /* tp_iternext */
|
|
|
|
|
0, /* tp_methods */
|
|
|
|
|
0, /* tp_members */
|
|
|
|
|
0, /* tp_getset */
|
|
|
|
|
0, /* tp_base */
|
|
|
|
|
0, /* tp_dict */
|
|
|
|
|
0, /* tp_descr_get */
|
|
|
|
|
0, /* tp_descr_set */
|
|
|
|
|
0, /* tp_dictoffset */
|
|
|
|
|
0, /* tp_init */
|
|
|
|
|
PyType_GenericAlloc, /* tp_alloc */
|
2025-09-18 14:54:37 -07:00
|
|
|
lazy_import_new, /* tp_new */
|
2025-09-16 15:10:28 -07:00
|
|
|
PyObject_GC_Del, /* tp_free */
|
|
|
|
|
};
|