Skip to content

Commit

Permalink
pythongh-128911: Add PyImport_GetModuleAttrString() function
Browse files Browse the repository at this point in the history
Remove "pycore_import.h" includes, no longer needed.
  • Loading branch information
vstinner committed Jan 16, 2025
1 parent 313b96e commit 5f320d1
Show file tree
Hide file tree
Showing 32 changed files with 66 additions and 47 deletions.
14 changes: 14 additions & 0 deletions Doc/c-api/import.rst
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,17 @@ Importing Modules
If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or
:c:func:`PyImport_ExtendInittab` must be called before each Python
initialization.
.. c:function:: PyObject* PyImport_GetModuleAttrString(const char *mod_name, const char *attr_name)
Import the module *mod_name* and get its attribute *attr_name*.
Names must be UTF-8 encoded strings.
Helper function combining :c:func:`PyImport_Import` and
:c:func:`PyObject_GetAttr`. For example, it can raise :exc:`ImportError` if
the module is not found, and :exc:`AttributeError` if the attribute doesn't
exist.
.. versionadded:: 3.14
4 changes: 4 additions & 0 deletions Doc/data/refcounts.dat
Original file line number Diff line number Diff line change
Expand Up @@ -3052,3 +3052,7 @@ _Py_c_quot:Py_complex:divisor::
_Py_c_sum:Py_complex:::
_Py_c_sum:Py_complex:left::
_Py_c_sum:Py_complex:right::

PyImport_GetModuleAttrString:PyObject*::+1:
PyImport_GetModuleAttrString:const char *:mod_name::
PyImport_GetModuleAttrString:const char *:attr_name::
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,10 @@ New features
bit-packing Python version numbers.
(Contributed by Petr Viktorin in :gh:`128629`.)

* Add :c:func:`PyImport_GetModuleAttrString` helper function to import a module
and get an attribute of the module.
(Contributed by Victor Stinner in :gh:`128911`.)


Porting to Python 3.14
----------------------
Expand Down
4 changes: 4 additions & 0 deletions Include/cpython/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ struct _frozen {
collection of frozen modules: */

PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules;

PyAPI_FUNC(PyObject*) PyImport_GetModuleAttrString(
const char *mod_name,
const char *attr_name);
3 changes: 0 additions & 3 deletions Include/internal/pycore_import.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ extern int _PyImport_FixupBuiltin(
// Export for many shared extensions, like '_json'
PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttr(PyObject *, PyObject *);

// Export for many shared extensions, like '_datetime'
PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttrString(const char *, const char *);


struct _import_runtime_state {
/* The builtin modules (defined in config.c). */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :c:func:`PyImport_GetModuleAttrString` helper function to import a
module and get an attribute of the module. Patch by Victor Stinner.
2 changes: 1 addition & 1 deletion Modules/_ctypes/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
if (context == NULL)
context = PyUnicode_InternFromString("_ctypes.DllGetClassObject");

func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject");
func = PyImport_GetModuleAttrString("ctypes", "DllGetClassObject");
if (!func) {
PyErr_WriteUnraisable(context ? context : Py_None);
/* There has been a warning before about this already */
Expand Down
2 changes: 1 addition & 1 deletion Modules/_ctypes/stgdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
goto error;
}

PyObject *layout_func = _PyImport_GetModuleAttrString("ctypes._layout",
PyObject *layout_func = PyImport_GetModuleAttrString("ctypes._layout",
"get_layout");
if (!layout_func) {
goto error;
Expand Down
2 changes: 1 addition & 1 deletion Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ _PyCursesCheckFunction(int called, const char *funcname)
if (called == TRUE) {
return 1;
}
PyObject *exc = _PyImport_GetModuleAttrString("_curses", "error");
PyObject *exc = PyImport_GetModuleAttrString("_curses", "error");
if (exc != NULL) {
PyErr_Format(exc, "must call %s() first", funcname);
Py_DECREF(exc);
Expand Down
6 changes: 3 additions & 3 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
assert(object && format && timetuple);
assert(PyUnicode_Check(format));

PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime");
PyObject *strftime = PyImport_GetModuleAttrString("time", "strftime");
if (strftime == NULL) {
return NULL;
}
Expand Down Expand Up @@ -2021,7 +2021,7 @@ static PyObject *
time_time(void)
{
PyObject *result = NULL;
PyObject *time = _PyImport_GetModuleAttrString("time", "time");
PyObject *time = PyImport_GetModuleAttrString("time", "time");

if (time != NULL) {
result = PyObject_CallNoArgs(time);
Expand All @@ -2039,7 +2039,7 @@ build_struct_time(int y, int m, int d, int hh, int mm, int ss, int dstflag)
PyObject *struct_time;
PyObject *result;

struct_time = _PyImport_GetModuleAttrString("time", "struct_time");
struct_time = PyImport_GetModuleAttrString("time", "struct_time");
if (struct_time == NULL) {
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_decimal/_decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3464,7 +3464,7 @@ pydec_format(PyObject *dec, PyObject *context, PyObject *fmt, decimal_state *sta
PyObject *u;

if (state->PyDecimal == NULL) {
state->PyDecimal = _PyImport_GetModuleAttrString("_pydecimal", "Decimal");
state->PyDecimal = PyImport_GetModuleAttrString("_pydecimal", "Decimal");
if (state->PyDecimal == NULL) {
return NULL;
}
Expand Down
5 changes: 2 additions & 3 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#endif

#include "Python.h"
#include "pycore_import.h" // _PyImport_GetModuleAttrString()
#include "pycore_pyhash.h" // _Py_HashSecret

#include <stddef.h> // offsetof()
Expand Down Expand Up @@ -4393,7 +4392,7 @@ module_exec(PyObject *m)
CREATE_TYPE(m, st->Element_Type, &element_spec);
CREATE_TYPE(m, st->XMLParser_Type, &xmlparser_spec);

st->deepcopy_obj = _PyImport_GetModuleAttrString("copy", "deepcopy");
st->deepcopy_obj = PyImport_GetModuleAttrString("copy", "deepcopy");
if (st->deepcopy_obj == NULL) {
goto error;
}
Expand All @@ -4403,7 +4402,7 @@ module_exec(PyObject *m)
goto error;

/* link against pyexpat */
if (!(st->expat_capsule = _PyImport_GetModuleAttrString("pyexpat", "expat_CAPI")))
if (!(st->expat_capsule = PyImport_GetModuleAttrString("pyexpat", "expat_CAPI")))
goto error;
if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME)))
goto error;
Expand Down
6 changes: 3 additions & 3 deletions Modules/_lsprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls,
return NULL;
}

PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring");
PyObject* monitoring = PyImport_GetModuleAttrString("sys", "monitoring");
if (!monitoring) {
return NULL;
}
Expand Down Expand Up @@ -857,7 +857,7 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self)
}
if (self->flags & POF_ENABLED) {
PyObject* result = NULL;
PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring");
PyObject* monitoring = PyImport_GetModuleAttrString("sys", "monitoring");

if (!monitoring) {
return NULL;
Expand Down Expand Up @@ -973,7 +973,7 @@ profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit,
Py_XSETREF(self->externalTimer, Py_XNewRef(timer));
self->tool_id = PY_MONITORING_PROFILER_ID;

PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring");
PyObject* monitoring = PyImport_GetModuleAttrString("sys", "monitoring");
if (!monitoring) {
return -1;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_operator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1868,7 +1868,7 @@ methodcaller_reduce(methodcallerobject *mc, PyObject *Py_UNUSED(ignored))
PyObject *constructor;
PyObject *newargs[2];

partial = _PyImport_GetModuleAttrString("functools", "partial");
partial = PyImport_GetModuleAttrString("functools", "partial");
if (!partial)
return NULL;

Expand Down
4 changes: 2 additions & 2 deletions Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ _Pickle_InitState(PickleState *st)
}
Py_CLEAR(compat_pickle);

st->codecs_encode = _PyImport_GetModuleAttrString("codecs", "encode");
st->codecs_encode = PyImport_GetModuleAttrString("codecs", "encode");
if (st->codecs_encode == NULL) {
goto error;
}
Expand All @@ -373,7 +373,7 @@ _Pickle_InitState(PickleState *st)
goto error;
}

st->partial = _PyImport_GetModuleAttrString("functools", "partial");
st->partial = PyImport_GetModuleAttrString("functools", "partial");
if (!st->partial)
goto error;

Expand Down
3 changes: 1 addition & 2 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include "prepare_protocol.h"
#include "util.h"

#include "pycore_import.h" // _PyImport_GetModuleAttrString()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
Expand Down Expand Up @@ -1995,7 +1994,7 @@ pysqlite_connection_iterdump_impl(pysqlite_Connection *self,
return NULL;
}

PyObject *iterdump = _PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump");
PyObject *iterdump = PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump");
if (!iterdump) {
if (!PyErr_Occurred()) {
PyErr_SetString(self->OperationalError,
Expand Down
4 changes: 1 addition & 3 deletions Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
#include "row.h"
#include "blob.h"

#include "pycore_import.h" // _PyImport_GetModuleAttrString()

#if SQLITE_VERSION_NUMBER < 3015002
#error "SQLite 3.15.2 or higher required"
#endif
Expand Down Expand Up @@ -234,7 +232,7 @@ static int
load_functools_lru_cache(PyObject *module)
{
pysqlite_state *state = pysqlite_get_state(module);
state->lru_cache = _PyImport_GetModuleAttrString("functools", "lru_cache");
state->lru_cache = PyImport_GetModuleAttrString("functools", "lru_cache");
if (state->lru_cache == NULL) {
return -1;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_sre/sre.c
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,7 @@ compile_template(_sremodulestate *module_state,
/* delegate to Python code */
PyObject *func = module_state->compile_template;
if (func == NULL) {
func = _PyImport_GetModuleAttrString("re", "_compile_template");
func = PyImport_GetModuleAttrString("re", "_compile_template");
if (func == NULL) {
return NULL;
}
Expand Down
8 changes: 4 additions & 4 deletions Modules/_zoneinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ zoneinfo_reduce(PyObject *obj_self, PyObject *unused)
if (self->source == SOURCE_FILE) {
// Objects constructed from files cannot be pickled.
PyObject *pickle_error =
_PyImport_GetModuleAttrString("pickle", "PicklingError");
PyImport_GetModuleAttrString("pickle", "PicklingError");
if (pickle_error == NULL) {
return NULL;
}
Expand Down Expand Up @@ -2554,7 +2554,7 @@ static PyObject *
new_weak_cache(void)
{
PyObject *WeakValueDictionary =
_PyImport_GetModuleAttrString("weakref", "WeakValueDictionary");
PyImport_GetModuleAttrString("weakref", "WeakValueDictionary");
if (WeakValueDictionary == NULL) {
return NULL;
}
Expand Down Expand Up @@ -2732,12 +2732,12 @@ zoneinfomodule_exec(PyObject *m)

/* Populate imports */
state->_tzpath_find_tzfile =
_PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile");
PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile");
if (state->_tzpath_find_tzfile == NULL) {
goto error;
}

state->io_open = _PyImport_GetModuleAttrString("io", "open");
state->io_open = PyImport_GetModuleAttrString("io", "open");
if (state->io_open == NULL) {
goto error;
}
Expand Down
4 changes: 2 additions & 2 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2285,7 +2285,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls,
assert(state != NULL);

if (state->array_reconstructor == NULL) {
state->array_reconstructor = _PyImport_GetModuleAttrString(
state->array_reconstructor = PyImport_GetModuleAttrString(
"array", "_array_reconstructor");
if (state->array_reconstructor == NULL) {
return NULL;
Expand Down Expand Up @@ -3202,7 +3202,7 @@ array_modexec(PyObject *m)
return -1;
}

PyObject *mutablesequence = _PyImport_GetModuleAttrString(
PyObject *mutablesequence = PyImport_GetModuleAttrString(
"collections.abc", "MutableSequence");
if (!mutablesequence) {
Py_DECREF((PyObject *)state->ArrayType);
Expand Down
3 changes: 1 addition & 2 deletions Modules/cjkcodecs/cjkcodecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#include "Python.h"
#include "multibytecodec.h"
#include "pycore_import.h" // _PyImport_GetModuleAttrString()


/* a unicode "undefined" code point */
Expand Down Expand Up @@ -299,7 +298,7 @@ add_codecs(cjkcodecs_module_state *st) \
static PyObject *
getmultibytecodec(void)
{
return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec");
return PyImport_GetModuleAttrString("_multibytecodec", "__create_codec");
}

static void
Expand Down
2 changes: 1 addition & 1 deletion Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,7 @@ PyInit_faulthandler(void)
static int
faulthandler_init_enable(void)
{
PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable");
PyObject *enable = PyImport_GetModuleAttrString("faulthandler", "enable");
if (enable == NULL) {
return -1;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -9886,7 +9886,7 @@ wait_helper(PyObject *module, pid_t pid, int status, struct rusage *ru)
memset(ru, 0, sizeof(*ru));
}

struct_rusage = _PyImport_GetModuleAttrString("resource", "struct_rusage");
struct_rusage = PyImport_GetModuleAttrString("resource", "struct_rusage");
if (struct_rusage == NULL)
return NULL;

Expand Down
3 changes: 1 addition & 2 deletions Modules/selectmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

#include "Python.h"
#include "pycore_fileutils.h" // _Py_set_inheritable()
#include "pycore_import.h" // _PyImport_GetModuleAttrString()
#include "pycore_time.h" // _PyTime_FromSecondsObject()

#include <stdbool.h>
Expand Down Expand Up @@ -1996,7 +1995,7 @@ kqueue_tracking_init(PyObject *module) {
// Register a callback to invalidate kqueues with open fds after fork.
PyObject *register_at_fork = NULL, *cb = NULL, *args = NULL,
*kwargs = NULL, *result = NULL;
register_at_fork = _PyImport_GetModuleAttrString("posix",
register_at_fork = PyImport_GetModuleAttrString("posix",
"register_at_fork");
if (register_at_fork == NULL) {
goto finally;
Expand Down
2 changes: 1 addition & 1 deletion Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ time_strptime(PyObject *self, PyObject *args)
{
PyObject *func, *result;

func = _PyImport_GetModuleAttrString("_strptime", "_strptime_time");
func = PyImport_GetModuleAttrString("_strptime", "_strptime_time");
if (!func) {
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ PyBuffer_SizeFromFormat(const char *format)
PyObject *fmt = NULL;
Py_ssize_t itemsize = -1;

calcsize = _PyImport_GetModuleAttrString("struct", "calcsize");
calcsize = PyImport_GetModuleAttrString("struct", "calcsize");
if (calcsize == NULL) {
goto done;
}
Expand Down
4 changes: 2 additions & 2 deletions Objects/fileobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const c
PyObject *open, *stream;

/* import _io in case we are being used to open io.py */
open = _PyImport_GetModuleAttrString("_io", "open");
open = PyImport_GetModuleAttrString("_io", "open");
if (open == NULL)
return NULL;
stream = PyObject_CallFunction(open, "isisssO", fd, mode,
Expand Down Expand Up @@ -506,7 +506,7 @@ PyFile_OpenCodeObject(PyObject *path)
if (hook) {
f = hook(path, _PyRuntime.open_code_userdata);
} else {
PyObject *open = _PyImport_GetModuleAttrString("_io", "open");
PyObject *open = PyImport_GetModuleAttrString("_io", "open");
if (open) {
f = PyObject_CallFunction(open, "Os", path, "rb");
Py_DECREF(open);
Expand Down
2 changes: 1 addition & 1 deletion Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2083,7 +2083,7 @@ struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
PyObject *format = NULL;
struct unpacker *x = NULL;

Struct = _PyImport_GetModuleAttrString("struct", "Struct");
Struct = PyImport_GetModuleAttrString("struct", "Struct");
if (Struct == NULL)
return NULL;

Expand Down
Loading

0 comments on commit 5f320d1

Please sign in to comment.